I would like to hide the separator in my context menu when all the menuitems are hidden.
If at least one of the two menuitems is visible, the separator must be visible too.
I've tried that:
<Separator>
<Separator.Style>
<Style TargetType="Separator">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Visibility, ElementName=Item1}" Value="Collapsed" />
<Condition Binding="{Binding Path=Visibility, ElementName=Item2}" Value="Collapsed" />
</MultiDataTrigger.Conditions>
<Setter Property="Separator.Visibility" Value="Collapsed" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Visibility, ElementName=Item1}" Value="Visible" />
<Condition Binding="{Binding Path=Visibility, ElementName=Item2}" Value="Visible" />
</MultiDataTrigger.Conditions>
<Setter Property="Separator.Visibility" Value="Visible" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Separator.Style>
</Separator>
<MenuItem x:Name="Item1" Header="Item1" Visibility="{Binding Item1Visibility, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<MenuItem x:Name="Item2" Header="Item2" Visibility="{Binding Item2Visibility, Converter={StaticResource BooleanToVisibilityConverter}}"/>
But the separator is always hidden.
What's wrong with my code?
Related
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>
I'd like to have several TextBlocks generally looking the same, but each needs to react on another trigger and in another way. I've tried to use a common style (MyTextBlockStyle) and add triggers later. But I get allways error meesages like "the property 'style' has been declared twice" or simillar.
To explain what I mean, I've made an example with 3 TextBlocks. 2 of them are bound to each a different CheckBox, and each triggering a different property (displayed text vs. foreground color). A third TextBlock shall change its background color depending of the content of a TextbBox. How can I achieve something like this?
<UserControl.Resources>
<Style x:Key="MyTextBlockStyle" TargetType="TextBlock">
<Setter Property="Background" Value="Yellow"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="Padding" Value="5"/>
</Style>
</UserControl.Resources>
<Grid >
<StackPanel Margin="10">
<CheckBox x:Name="CheckBox01" Content="Change Background of TextBlock 1" IsChecked="False" Foreground="White" Margin="5" />
<CheckBox x:Name="CheckBox02" Content="Change Background of TextBlock 2" IsChecked="False" Foreground="White" Margin="5" />
<TextBox x:Name="TextBox03" Padding="10" Background="White" Text="Enter Text here ..." Tooltip="Change Background of TextBlock 3"/>
<TextBlock Style="{StaticResource MyTextBlockStyle}" >
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="No" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CheckBox01, Path=IsChecked}" Value="True">
<Setter Property="Text" Value="Yes!" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Style="{Static Resource MyTextBlockStyle}" Text="Something different">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CheckBox02, Path=IsChecked}" Value="True">
<Setter Property="Foreground" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Style="{Static Resource MyTextBlockStyle}" Text="Anything else">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Background" Value="Yellow" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=TextBox03, Path=Text}" Value="">
<Setter Property="Background" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Grid >
Please try this code.It works.I guess as you wish
<Window.Resources>
<Style TargetType="TextBlock">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=CheckBox01,Path=IsChecked}" Value="True"/>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Tag}" Value="tb1"/>
</MultiDataTrigger.Conditions>
<Setter Property="TextBlock.Background" Value="Orange"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=CheckBox02,Path=IsChecked}" Value="True"/>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Tag}" Value="tb2"/>
</MultiDataTrigger.Conditions>
<Setter Property="TextBlock.Background" Value="Pink"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=TextBox03,Path=Text}" Value=""/>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Tag}" Value="tb3"/>
</MultiDataTrigger.Conditions>
<Setter Property="TextBlock.Background" Value="Green"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel Margin="10">
<CheckBox x:Name="CheckBox01" Content="Change Background of TextBlock 1" IsChecked="False" Margin="5"/>
<CheckBox x:Name="CheckBox02" Content="Change Background of TextBlock 2" IsChecked="False" Margin="5"/>
<TextBox x:Name="TextBox03" Padding="10" Background="White" Text="Enter Text here ..."/>
<TextBlock Tag="tb1"/>
<TextBlock Tag="tb2" Text="Something different"/>
<TextBlock Tag="tb3" x:Name="tb3" Text="Anything else"/>
</StackPanel>
</Grid >
You are looking for the BasedOn Property. It gets me all the time.
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock" BasedOn="MyTextBlockStyle">
<Setter Property="Text" Value="No" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CheckBox01, Path=IsChecked}" Value="True">
<Setter Property="Text" Value="Yes!" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
I have a Listbox with an Alternation Index of 2 on it. I then have a style set up to provide styling on the different alternation indexes.
<Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<Border x:Name="Bd" SnapsToDevicePixels="true">
<ContentPresenter Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<Rectangle x:Name="HoverRectangle"
Height="Auto"
SnapsToDevicePixels="True"
Stroke="{StaticResource Gold}"
StrokeDashCap="Square"
StrokeThickness="0" />
<Rectangle x:Name="KeyboardFocusRectangle"
Height="Auto"
SnapsToDevicePixels="True"
Stroke="{StaticResource BrightBlue}"
StrokeDashCap="Square"
StrokeThickness="0" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter TargetName="Bd" Property="Background" Value="{StaticResource LightGray}" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter TargetName="Bd" Property="Background" Value="{StaticResource VeryLightGray}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I also want to change the background on the items if they happen in the future. I have a function IsFuture returning a boolean. I then got this code working in the data template to style the background.
<DataTemplate x:Key="MeetingListItemTemplate">
<Grid x:Name="grid">
<!-- Removed lots of stuff here-->
</Grid>
<DataTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsFuture}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="#0094d6" TargetName="grid"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
I set up the MutliDataTrigger so I could have the condition for alternation index and then I would use a different blue for each alternation but I'm not sure how I can get alternation index from here. Any ideas?
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsFuture}" Value="true" />
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=(ItemsControl.AlternationIndex)}" Value="0"/>
</MultiDataTrigger.Conditions>
Try the TemplatedParent RelativeSource mode.
You should be able to use a RelativeSource binding to bind to the AlternationIndex property of the parent ItemsControl:
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsFuture}" Value="True" />
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}, Path=AlternationIndex}" Value="1"
</MultiDataTrigger.Conditions>
I have a TreeView with a ToggleButton ( ExpanderButton ). The togglebutton has a two images ( one for expanded and one when not ). However when I select a TreeViewItem I highligh it with a different color and I'd like to change the color of the images as well ( I have the same ones in the other color ).
Problem is I don't know how to set a trigger property on the ToggleButton to the IsSelected property on the TreeViewItem.
Any Ideas?
Here if anyone else needs this.
<ControlTemplate TargetType="ToggleButton">
<Image Name="ExpanderImage" Height="24" Width="24" Source="..\Images\Icons\32x32\Blue\Open.png" />
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="ExpanderImage" Property="Source" Value="..\Images\Icons\32x32\Blue\Close.png" />
</Trigger>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter TargetName="ExpanderImage" Property="Source" Value="..\Images\Icons\32x32\Green\Open.png" />
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}" Value="True" />
<Condition Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter TargetName="ExpanderImage" Property="Source" Value="..\Images\Icons\32x32\Green\Close.png" />
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>