I want to say at the very beginning is that I'm just beginning my adventure with Xaml, so please be understanding if question is trivial.
I'm going to design a user control with a variable layout and it is controlled by radio button for UWP - C++Cx App.
Generally, the user control have 4 possible views / states. I show it in the picture:
What is the best way to construct this control in this way? Propably that's important that I want to bind observable collections to elements visible in the picture:
element 0 of collection - main View and elements 1-4 : smaller, side views
Thanks in advance!
We could try to use a User Control and VisualState to achieve it. You could divide your root Grid into two columns and put your main View into column 0, then divide column 1 into 6 rows and 6 columns.
First you could add your four views in the second column and set the Visibility of them as Collapsed. When you want to show the first layout which only contains the main view, you could set the value of MainView.(Grid.ColumnSpan) to 2 in the VisualState. When you want to show the main view and other small views, you need to change the MainView.(Grid.ColumnSpan) to 1 and re-layout those small views by changing its row and column. For example:
.UserControl.xaml:
<Grid x:Name="RootGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid x:Name="MainView" Background="Gray">
<StackPanel>
<RadioButton
x:Name="firstrb"
Margin="10"
Click="rb_Click"
Content="First Layout" />
<RadioButton
x:Name="secondrb"
Margin="10"
Click="rb_Click"
Content="Second Layout" />
<RadioButton
x:Name="thirdrb"
Margin="10"
Click="rb_Click"
Content="Third Layout" />
<RadioButton
x:Name="fourthrb"
Margin="10"
Click="rb_Click"
Content="Fourth Layout" />
</StackPanel>
</Grid>
<Grid x:Name="SideView" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel
x:Name="View1"
Background="Red"
Visibility="Collapsed" />
<StackPanel
x:Name="View2"
Background="Yellow"
Visibility="Collapsed" />
<StackPanel
x:Name="View3"
Background="Blue"
Visibility="Collapsed" />
<StackPanel
x:Name="View4"
Background="Green"
Visibility="Collapsed" />
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="FirstLayout">
<VisualState.Setters>
<Setter Target="MainView.(Grid.ColumnSpan)" Value="2" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="SecondLayout">
<VisualState.Setters>
<Setter Target="MainView.(Grid.Column)" Value="0" />
<Setter Target="SideView.(Grid.Column)" Value="1" />
<Setter Target="SideView.Visibility" Value="Visible" />
<Setter Target="View1.Visibility" Value="Visible" />
<Setter Target="View1.(Grid.Row)" Value="0" />
<Setter Target="View1.(Grid.RowSpan)" Value="3" />
<Setter Target="View1.(Grid.Column)" Value="0" />
<Setter Target="View1.(Grid.ColumnSpan)" Value="6" />
<Setter Target="View2.Visibility" Value="Visible" />
<Setter Target="View2.(Grid.Row)" Value="3" />
<Setter Target="View2.(Grid.RowSpan)" Value="3" />
<Setter Target="View2.(Grid.Column)" Value="0" />
<Setter Target="View2.(Grid.ColumnSpan)" Value="6" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="ThirdLayout">
<VisualState.Setters>
<Setter Target="MainView.(Grid.Column)" Value="0" />
<Setter Target="SideView.(Grid.Column)" Value="1" />
<Setter Target="SideView.Visibility" Value="Visible" />
<Setter Target="View1.Visibility" Value="Visible" />
<Setter Target="View1.(Grid.Row)" Value="0" />
<Setter Target="View1.(Grid.RowSpan)" Value="2" />
<Setter Target="View1.(Grid.Column)" Value="0" />
<Setter Target="View1.(Grid.ColumnSpan)" Value="6" />
<Setter Target="View2.Visibility" Value="Visible" />
<Setter Target="View2.(Grid.Row)" Value="2" />
<Setter Target="View2.(Grid.RowSpan)" Value="2" />
<Setter Target="View2.(Grid.Column)" Value="0" />
<Setter Target="View2.(Grid.ColumnSpan)" Value="6" />
<Setter Target="View3.Visibility" Value="Visible" />
<Setter Target="View3.(Grid.Row)" Value="4" />
<Setter Target="View3.(Grid.RowSpan)" Value="2" />
<Setter Target="View3.(Grid.Column)" Value="0" />
<Setter Target="View3.(Grid.ColumnSpan)" Value="6" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="FourthLayout">
<VisualState.Setters>
<Setter Target="MainView.(Grid.Column)" Value="0" />
<Setter Target="SideView.(Grid.Column)" Value="1" />
<Setter Target="SideView.Visibility" Value="Visible" />
<Setter Target="View1.Visibility" Value="Visible" />
<Setter Target="View1.(Grid.Row)" Value="0" />
<Setter Target="View1.(Grid.RowSpan)" Value="3" />
<Setter Target="View1.(Grid.Column)" Value="0" />
<Setter Target="View1.(Grid.ColumnSpan)" Value="3" />
<Setter Target="View2.Visibility" Value="Visible" />
<Setter Target="View2.(Grid.Row)" Value="0" />
<Setter Target="View2.(Grid.RowSpan)" Value="3" />
<Setter Target="View2.(Grid.Column)" Value="3" />
<Setter Target="View2.(Grid.ColumnSpan)" Value="3" />
<Setter Target="View3.Visibility" Value="Visible" />
<Setter Target="View3.(Grid.Row)" Value="3" />
<Setter Target="View3.(Grid.RowSpan)" Value="3" />
<Setter Target="View3.(Grid.Column)" Value="0" />
<Setter Target="View3.(Grid.ColumnSpan)" Value="3" />
<Setter Target="View4.Visibility" Value="Visible" />
<Setter Target="View4.(Grid.Row)" Value="3" />
<Setter Target="View4.(Grid.RowSpan)" Value="3" />
<Setter Target="View4.(Grid.Column)" Value="3" />
<Setter Target="View4.(Grid.ColumnSpan)" Value="3" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
.UserControl.xaml.cpp:
void AppCX::UserControl::rb_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
RadioButton^ rb = (RadioButton^)sender;
if (rb->Name == "firstrb")
{
VisualStateManager::GoToState(this, "FirstLayout", false);
}
if (rb->Name == "secondrb")
{
VisualStateManager::GoToState(this, "SecondLayout", false);
}
if (rb->Name == "thirdrb")
{
VisualStateManager::GoToState(this, "ThirdLayout", false);
}
if (rb->Name == "fourthrb")
{
VisualStateManager::GoToState(this, "FourthLayout", false);
}
}
Related
How can I cause the DataGrid column headers to be centered instead of left-aligned?
In particular, I want to center just the 3rd column.
(I used to use DNOA!). Anyway ... here you go.
If memory serves this is more or less the default style, I think I've pulled out any of my specifics so should just drop in to your application. Remember to pull in the Default DataGrid styles first.
<FluentTheme Mode="Dark" />
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
Style code
<Style Selector="DataGridColumnHeader">
<Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Focusable" Value="False" />
<Setter Property="SeparatorBrush" Value="{DynamicResource DataGridGridLinesBrush}" />
<Setter Property="Padding" Value="12,0,0,0" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="MinHeight" Value="30" />
<Setter Property="Template">
<ControlTemplate>
<Grid Name="PART_ColumnHeaderRoot"
ColumnDefinitions="*,Auto"
Background="{TemplateBinding Background}">
<Grid HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition MinWidth="32"
Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
<Path Name="SortIcon"
Grid.Column="1"
Fill="{DynamicResource SampleSortOrange}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
Height="12" />
</Grid>
<Rectangle Name="VerticalSeparator"
Grid.Column="1"
Width="1"
VerticalAlignment="Stretch"
Fill="{TemplateBinding SeparatorBrush}"
IsVisible="{TemplateBinding AreSeparatorsVisible}" />
<Grid x:Name="FocusVisual"
IsHitTestVisible="False">
<Rectangle x:Name="FocusVisualPrimary"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualPrimaryBrush}"
StrokeThickness="2" />
<Rectangle x:Name="FocusVisualSecondary"
Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualSecondaryBrush}"
StrokeThickness="1" />
</Grid>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<!-- Selected Row Background -->
<Style Selector="DataGridRow:selected /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource SampleSortOrange}" />
<Setter Property="Opacity" Value="0.3" />
</Style>
<!-- <Style Selector="DataGridRow:selected /template/ ContentPresenter"> -->
<!-- <Setter Property="TextBlock.Foreground" Value="Black" /> -->
<!-- </Style> -->
<Style Selector="DataGridColumnHeader /template/ Grid#FocusVisual">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="DataGridColumnHeader:focus-visible /template/ Grid#FocusVisual">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="DataGridColumnHeader:pointerover /template/ Grid#PART_ColumnHeaderRoot">
<Setter Property="Background" Value="{DynamicResource DataGridColumnHeaderHoveredBackgroundColor}" />
</Style>
<Style Selector="DataGridColumnHeader:pressed /template/ Grid#PART_ColumnHeaderRoot">
<Setter Property="Background" Value="{DynamicResource DataGridColumnHeaderPressedBackgroundColor}" />
</Style>
<Style Selector="DataGridColumnHeader:dragIndicator">
<Setter Property="Opacity" Value="0.5" />
</Style>
<Style Selector="DataGridColumnHeader /template/ Path#SortIcon">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="DataGridColumnHeader:sortascending /template/ Path#SortIcon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{StaticResource DataGridSortIconAscendingPath}" />
</Style>
<Style Selector="DataGridColumnHeader:sortdescending /template/ Path#SortIcon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{StaticResource DataGridSortIconDescendingPath}" />
</Style>
The key line relative to this question is:
<Setter Property="HorizontalContentAlignment" Value="Center" />
To only do one column, things would get a little more involved as above is a globally applied style through the Selector=Type (same as WPF {Type:xxx} style convention). So you could look at making that one column "targetable" somehow so a Selector= would only hit that column.
Off the top of my head, you'd have to turn off auto column generation on your DataGrid instance, manually generate the columns and give that one column a name, such as "immagonnabecentered", then selectors should just target this single column.
So create columns like:
<controls:DataGrid.Columns>
<DataGridTextColumn Header="File Name" Binding="{Binding FileName}" SortMemberPath="FileName"/>
<DataGridTextColumn x:Name="immagonnabecentered" Header="File Name" Binding="{Binding FileName}" SortMemberPath="FileName"/>
...
</controls:DataGrid.Columns>
Then update the style selector on the Style to hit this one column.
<Style Selector="#immagonnabecentered">
<Style Selector="DataGridColumnHeader#immagonnabecentered">
Early today I've asked for help here because my Xamarin App wasn't working like I expected.
After the help about how to change my Action Bar color, I start wondering "why the way it says on tutorials I've found does not work"
EDIT
<?xml version="1.0" encoding="UTF-8"?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Mobile.XamarinApp.Views"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="Mobile.XamarinApp.AppShell"
BackgroundColor="{StaticResource Primary}"
Shell.ForegroundColor="{StaticResource Background}"
Shell.TitleColor="{StaticResource Background}">
<!--
The overall app visual hierarchy is defined here, along with navigation.
https://learn.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell/
-->
<Shell.Resources>
<ResourceDictionary>
<Style x:Key="BaseStyle" TargetType="Element" ApplyToDerivedTypes="True">
<Setter Property="Shell.Title" Value="App" />
<Setter Property="Shell.BackgroundColor" Value="{StaticResource Background}" />
<Setter Property="Shell.ForegroundColor" Value="{StaticResource Primary}" />
<Setter Property="Shell.TitleColor" Value="{StaticResource Primary}" />
<Setter Property="Shell.DisabledColor" Value="HotPink" />
<Setter Property="Shell.UnselectedColor" Value="{StaticResource Secondary}" />
<Setter Property="Shell.TabBarBackgroundColor" Value="Red" />
<Setter Property="Shell.TabBarForegroundColor" Value="Blue"/>
<Setter Property="Shell.TabBarUnselectedColor" Value="Green"/>
<Setter Property="Shell.TabBarTitleColor" Value="Yellow"/>
<Setter Property="Shell.FlyoutHeight" Value="400"/>
<Setter Property="Shell.FlyoutWidth" Value="200"/>
</Style>
<Style TargetType="TabBar" BasedOn="{StaticResource BaseStyle}" />
<Style TargetType="FlyoutItem" BasedOn="{StaticResource BaseStyle}" />
<!--
Default Styles for all Flyout Items
https://learn.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell/flyout#flyoutitem-and-menuitem-style-classes
-->
<Style Class="teste" TargetType="TabbedPage">
<Setter Property="BackgroundColor" Value="Red"/>
</Style>
<Style Class="FlyoutItemLabelStyle" TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource Accent}"></Setter>
</Style>
<Style Class="FlyoutItemLayoutStyle" TargetType="Layout" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="{StaticResource Primary}"></Setter>
<Setter Property="HeightRequest" Value="50" />
<Setter Property="HorizontalOptions" Value="Start"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{StaticResource Primary}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{StaticResource Secondary}" />
<Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<!--
Custom Style you can apply to any Menu Item
-->
<Style Class="MenuItemLayoutStyle" TargetType="Layout" ApplyToDerivedTypes="True">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{StaticResource Accent}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ResourceDictionary>
</Shell.Resources>
<Shell.FlyoutHeaderTemplate>
<DataTemplate>
<Grid BackgroundColor="{StaticResource Secondary}" HeightRequest="56" Padding="10,0,10,0">
<Label Text="Menu"
TextColor="{StaticResource Primary}"
FontAttributes="Bold"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Start"/>
</Grid>
</DataTemplate>
</Shell.FlyoutHeaderTemplate>
<Shell.FlyoutFooterTemplate>
<DataTemplate>
<StackLayout>
<Label Text="Xaminals"
TextColor="Black"
FontAttributes="Bold"
HorizontalOptions="Center" />
<Label Text="{Binding Source={x:Static sys:DateTime.Now}, StringFormat='{0:MMMM dd, yyyy}'}"
TextColor="Black"
HorizontalOptions="Center" />
</StackLayout>
</DataTemplate>
</Shell.FlyoutFooterTemplate>
<!-- Splash Screen/Start Page -->
<!--<ShellItem Route="loading">
<ShellContent ContentTemplate="{DataTemplate local:LoadingPage}" />
</ShellItem>-->
<!-- SignIn Page -->
<ShellContent Route="SignInPage" ContentTemplate="{DataTemplate local:SignInPage}"/>
<!--
When the Flyout is visible this defines the content to display in the flyout.
FlyoutDisplayOptions="AsMultipleItems" will create a separate flyout item for each child element
https://learn.microsoft.com/dotnet/api/xamarin.forms.shellgroupitem.flyoutdisplayoptions?view=xamarin-forms
-->
<FlyoutItem Title="Browse">
<ShellContent Route="ItemsPage" ContentTemplate="{DataTemplate local:ItemsPage}" />
</FlyoutItem>
<FlyoutItem Title="About">
<ShellContent Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />
</FlyoutItem>
<FlyoutItem Title="Cadastro">
<ShellContent Route="ItemsPage" ContentTemplate="{DataTemplate local:ItemsPage}" />
</FlyoutItem>
<!-- When the Flyout is visible this will be a menu item you can tie a click behavior to -->
<MenuItem Text="Sair" StyleClass="MenuItemLayoutStyle" Clicked="OnSignOutMenuItemClicked">
</MenuItem>
<!--
TabBar lets you define content that won't show up in a flyout menu. When this content is active
the flyout menu won't be available. This is useful for creating areas of the application where
you don't want users to be able to navigate away from. If you would like to navigate to this
content you can do so by calling
await Shell.Current.GoToAsync("//LoginPage");
-->
<!-- Optional Templates
// These may be provided inline as below or as separate classes.
// This header appears at the top of the Flyout.
// https://learn.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell/flyout#flyout-header
<Shell.FlyoutHeaderTemplate>
<DataTemplate>
<Grid>ContentHere</Grid>
</DataTemplate>
</Shell.FlyoutHeaderTemplate>
// ItemTemplate is for ShellItems as displayed in a Flyout
// https://learn.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell/flyout#define-flyoutitem-appearance
-->
<!--<Shell.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Text="{Binding Title}"
FontAttributes="Italic"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
</Shell.ItemTemplate>-->
<!--
// MenuItemTemplate is for MenuItems as displayed in a Flyout
// https://learn.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell/flyout#define-menuitem-appearance
-->
<!--<Shell.MenuItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Text="{Binding Text}"
FontAttributes="Italic"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
</Shell.MenuItemTemplate>-->
While I stand for the configuration of Shell on those 3 lines, it does not work.
<Setter Property="Shell.BackgroundColor" Value="{StaticResource Background}" />
<Setter Property="Shell.ForegroundColor" Value="{StaticResource Primary}" />
<Setter Property="Shell.TitleColor" Value="{StaticResource Primary}" />
After getting help, the 3 last lines shell config at the header, made it work.
BackgroundColor="{StaticResource Primary}"
Shell.ForegroundColor="{StaticResource Background}"
Shell.TitleColor="{StaticResource Background}"
The question is, am I doing something wrong? Did I miss something?
I just want to change the color of my Tabbar, action bar and etc from my Shell.Resources Dictionary like the tutorials shows us to do.
thanks in advance
You probably have to Target ShellContent type also:
<Style TargetType="ShellContent" BasedOn="{StaticResource BaseStyle}"/>
As you can see below, the FlyoutItem has an Icon and a Title.
<FlyoutItem Title="About" >
<FlyoutItem.Icon>
<FontImageSource FontFamily="MaterialDesignIconFont"
Glyph="{StaticResource InformationOutlineGlyph}"
Color="Green" />
</FlyoutItem.Icon>
<ShellContent Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />
</FlyoutItem>
The Title Color changes automatically because of this Style:
<Style Class="FlyoutItemLayoutStyle" TargetType="Layout" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="LightBlue"></Setter>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
<Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{StaticResource PrimaryColor}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{StaticResource PrimaryColor}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
So the Label that is the Title changes color automatically when the FlyoutItem is selected. I need the Icon to do the same thing. I could use a trigger to set the FontImageSource but that comes with its own problems.
Given the TargetName "FlyoutItemLabel" from the above Style, is it possible to create a binding from the FontImageSource.Color to each FlyoutItem's "FlyoutItemLabel".Color? It would have to bind upward to the FlyoutItem ancestor, then downward to the <Label x:Name="FlyoutItemLabel" />, wouldn't it?
You could set the [ItemTemplate][1] of FlyoutItem as you want
<Shell.ItemTemplate>
<DataTemplate >
<Grid Style="{StaticResource FloutItemStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.8*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding xxx}"
Margin="5"
BackgroundColor="{Binding Source={x:Reference label} ,Path=BackgroundColor}"
HeightRequest="45" />
<Label Grid.Column="1"
x:Name="label"
BackgroundColor="Red"
Text="{Binding Title}"
FontAttributes="Italic"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
</Shell.ItemTemplate>
I am using Material Design Font Icons as my icon source for my project. The trouble is, since it's a font it needs a different color when selected vs. when deselected (as shown - the deselected white ones have white icons, which isn't awesome).
How can I modify the Style to change the color of the icon like it does the text and background color?
<!-- redacted because it would've never worked -->
Edit 1:
Consensus is that using the VSM isn't going to work because it doesn't derive from VisualElement. I've gotten it to work using a Trigger - but I'm not happy with the implementation. This works:
<Shell.Resources>
<ResourceDictionary>
<Style TargetType="FlyoutItem" BasedOn="{StaticResource BaseStyle}">
<Style.Triggers>
<Trigger TargetType="FlyoutItem" Property="IsChecked" Value="True">
<Setter Property="Title" Value="Checked" />
<Setter Property="FlyoutIcon" >
<Setter.Value>
<FontImageSource FontFamily="MaterialDesignIconFont"
Glyph="{StaticResource InformationOutlineGlyph}"
Color="White" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</Shell.Resources>
<FlyoutItem Title="About" >
<FlyoutItem.Icon>
<FontImageSource FontFamily="MaterialDesignIconFont"
Glyph="{StaticResource InformationOutlineGlyph}"
Color="Green" />
</FlyoutItem.Icon>
<ShellContent Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />
</FlyoutItem>
... but as you can see, I have to set the entire FontImageSource value - which has the Glyph property - so I have to repeat this Style each time for each FlyoutItem.
How can I rewrite this Style to be reusable and only change the color, not the other properties?
I had the same question and solved it as follows
Create a custom flyout with an additional IconGlyphProperty
class FlyoutItemIconFont : FlyoutItem
{
public static readonly BindableProperty IconGlyphProperty = BindableProperty.Create(nameof(IconGlyphProperty), typeof(string), typeof(FlyoutItemIconFont), string.Empty);
public string IconGlyph
{
get { return (string)GetValue(IconGlyphProperty); }
set { SetValue(IconGlyphProperty, value); }
}
}
Create a FlyoutItemTemplate with two Lables and VisualStateManager
<Shell.ItemTemplate>
<DataTemplate>
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
<Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{StaticResource Primary}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{StaticResource Primary}" />
<Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.8*" />
</Grid.ColumnDefinitions>
<Label x:Name="FlyoutItemIcon"
FontFamily="MaterialDesignFont"
Text="{Binding IconGlyph}"
TextColor="{Binding Source={x:Reference FlyoutItemLabel} ,Path=TextColor}"
FontSize="30"
Margin="5"/>
<Label x:Name="FlyoutItemLabel"
Grid.Column="1"
Text="{Binding Title}"
VerticalTextAlignment="Center" />
</Grid>
</DataTemplate>
</Shell.ItemTemplate>
Replace the original FlyoutItem in AppShell.xaml with the custom FlyoutItem
<controls:FlyoutItemIconFont Title="About" IconGlyph="{StaticResource IconInfo}">
<ShellContent Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />
</controls:FlyoutItemIconFont>
<controls:FlyoutItemIconFont Title="Browse" IconGlyph="{StaticResource IconListBulleted}">
<ShellContent Route="ItemsPage" ContentTemplate="{DataTemplate local:ItemsPage}" />
</controls:FlyoutItemIconFont>
Add the BaseStyle to the customFlyouItem
<Shell.Resources>
<ResourceDictionary>
<x:String x:Key="IconInfo"></x:String>
<x:String x:Key="IconListBulleted"></x:String>
...
<Style TargetType="controls:FlyoutItemIconFont" BasedOn="{StaticResource BaseStyle}"/>
</ResourceDictionary>
</Shell.Resources>
Here is the Result
Create the Material Design Icons.
<Application.Resources>
<ResourceDictionary>
<Color x:Key="fgColor">#66169C</Color>
<Color x:Key="bgColor">#FFFFFF</Color>
<Color x:Key="OverDueItem">#FF1C07</Color>
<OnPlatform x:Key="Material" x:TypeArguments="x:String">
<On Platform="iOS" Value="Material Design Icons" />
<On Platform="Android" Value="materialdesignicons-webfont.ttf#Material Design Icons" />
</OnPlatform>
<Style x:Key="MaterialIcons" TargetType="{x:Type Label}">
<Setter Property="FontFamily" Value="{DynamicResource Material}" />
<Setter Property="FontSize" Value="100" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="TextColor" Value="{DynamicResource fgColor}" />
<Setter Property="FontSize" Value="Large" />
</Style>
</ResourceDictionary>
</Application.Resources>
For more details about the Material Design Icons, you could download from the GitHub. https://github.com/WendyZang/Test/tree/master/MaterialDesignIcons/App2
And then create the style to change the background color when you selected.
<Style x:Key="FloutItemStyle" TargetType="Grid">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Accent" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
Change the Label TextColor with the Triggers.
<Shell.ItemTemplate>
<DataTemplate>
<Grid x:Name="grid" Style="{StaticResource FloutItemStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="0.8*" />
</Grid.ColumnDefinitions>
<Label Style="{StaticResource MaterialIcons}" Text="">
<Label.Triggers>
<DataTrigger
Binding="{Binding Source={x:Reference grid}, Path=BackgroundColor}"
TargetType="Label"
Value="Accent">
<Setter Property="TextColor" Value="White" />
</DataTrigger>
</Label.Triggers>
</Label>
<Label
Grid.Column="1"
FontAttributes="Italic"
Text="{Binding Title}"
VerticalTextAlignment="Center">
<Label.Triggers>
<DataTrigger
Binding="{Binding Source={x:Reference grid}, Path=BackgroundColor}"
TargetType="Label"
Value="Accent">
<Setter Property="TextColor" Value="White" />
</DataTrigger>
</Label.Triggers>
</Label>
</Grid>
</DataTemplate>
</Shell.ItemTemplate>
Screenshot:
Updated:
Change:
<Setter Property="TextColor" Value="White" />
To:
<Setter Property="BackgroundColor" Value="Yellow" />
The whold trigger of the shell itemtemplate.
<Label.Triggers>
<DataTrigger
Binding="{Binding Source={x:Reference grid}, Path=BackgroundColor}"
TargetType="Label"
Value="Accent">
<!--<Setter Property="TextColor" Value="White" />-->
<Setter Property="BackgroundColor" Value="Yellow" />
</DataTrigger>
</Label.Triggers>
Screenshot:
I'm trying to create a TitleView where the navigation title is centered in the middle of the screen. But have buttons on either or both sides.
(I recently found posts saying it was best to add buttons to the TitleView rather than ContentPage.ToolbarItem as we couldn't changes the colour of the text.)
Instead we opted for fixed width buttons / spacers, so we could have a middle label for the title which would be centered. You can see the result below, unforunetly I'm going to have to increased the size of the button for longer text. We also support several languages so the text could be longer still.
Here's the xaml
<NavigationPage.TitleView>
<StackLayout Style="{StaticResource TitleViewStackLayout}">
<Label Style="{StaticResource TitleViewSpacer}"
HorizontalOptions="Start" />
<Label Text="{tran:Translate Contact_ConfirmEmail}"
Style="{StaticResource TitleViewLabel}" />
<Button Style="{StaticResource TitleViewButton}"
HorizontalOptions="End"
Text="{tran:Translate Common_Restart}"
Command="{Binding ToolbarItemRestartCommand}"/>
</StackLayout>
</NavigationPage.TitleView>
And here's our style...
<Style x:Key="TitleViewStackLayout" TargetType="StackLayout">
<Setter Property="BackgroundColor" Value="{DynamicResource DarkBlue}" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="HorizontalOptions" Value="FillAndExpand" />
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="Spacing" Value="0" />
</Style>
<Style x:Key="TitleViewLabel" TargetType="Label">
<Setter Property="TextColor" Value="{DynamicResource White}" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="HorizontalOptions" Value="CenterAndExpand" />
<Setter Property="FontSize" Value="{DynamicResource Title}" />
</Style>
<OnPlatform x:Key="TitleViewItemMargin" x:TypeArguments="Thickness" Android="10,0,10,0" iOS="0" />
<OnPlatform x:Key="TitleViewItemWidth" x:TypeArguments="x:Double" Android="60" iOS="50" />
<Style x:Key="TitleViewButton" TargetType="Button">
<Setter Property="BackgroundColor" Value="{DynamicResource DarkBlue}" />
<Setter Property="TextColor" Value="{DynamicResource White}" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="Margin" Value="{DynamicResource TitleViewItemMargin}" />
<Setter Property="WidthRequest" Value="{DynamicResource TitleViewItemWidth}" />
<Setter Property="FontSize" Value="16" />
</Style>
<Style x:Key="TitleViewSpacer" TargetType="Label">
<Setter Property="BackgroundColor" Value="{DynamicResource DarkBlue}" />
<Setter Property="TextColor" Value="{DynamicResource White}" />
<Setter Property="VerticalOptions" Value="Center" />
<Setter Property="Margin" Value="{DynamicResource TitleViewItemMargin}" />
<Setter Property="WidthRequest" Value="{DynamicResource TitleViewItemWidth}" />
<Setter Property="FontSize" Value="16" />
</Style>
I did think about using a grid, I know could also add three columns all with Grid.Column="0".. but I'd then have the possibility of a long title which would overlap the buttons. We do have some long titles. I guess I would need to be able to set a max width and add LineBreakMode="TailTruncation"
Xamarin Forms - center title in a stacklayout
I did think about repeating the text but transparent to achieve equal widths, but this wouldn't cater for 2 different buttons.
As you said , it could be better to use Grid instead of StackLayout .
In your case , you could set the width of three columns as a fixed percentage value. In this way , since the Text of Label is a long value , it will never cover the right Button .
<NavigationPage.TitleView>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*"/>
<ColumnDefinition Width="0.6*"/>
<ColumnDefinition Width="0.2*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Column="0"
Text="Back"
MaxLines="1"
Style="{StaticResource TitleViewSpacer}"
HorizontalOptions="Start" />
<Label Grid.Column="1" Text="Email Confirm Email Confirm Email Confirm Email Confirm Email Confirm"
MaxLines="1"
LineBreakMode="TailTruncation" // you could set it or not , both are OK ,it's up to you
Style="{StaticResource TitleViewLabel}" />
<Button Grid.Column="2" Style="{StaticResource TitleViewButton}"
HorizontalOptions="EndAndExpand"
Text="Restart"
WidthRequest="80"
Command="{Binding ToolbarItemRestartCommand}"/>
</Grid>
</NavigationPage.TitleView>