Reputation: 17
I have an Button
whose command is ToggleMode
, Inside this button is a FontIcon
and a TextBlock
.
In Styles.xaml I set the foreground color of a Button
to white when the Button
is enabled and to a light gray if the button is disabled. This leads to the Textblocks
foreground color correctly changing when the Button
is disabled because the ToggleMode.CanExecute()
returns false.
However the FontIcons
normal color is a light blue, which I set using the Foreground
property.
When the Button
is disabled the color should be changed to a pale blue improving the impression of the button being disabled.
<local:BooleanConverter x:Key="CanExecuteToIconColorConverter">
<local:BooleanConverter.True>
<SolidColorBrush Color="{ThemeResource VividSkyBlueColor}" />
</local:BooleanConverter.True>
<local:BooleanConverter.False>
<SolidColorBrush Color="{ThemeResource PaleVividSkyBlueColor}" />
</local:BooleanConverter.False>
</local:BooleanConverter>
<Button Grid.Row="0" Width="150" Padding="10"
Command="{x:Bind ToggleMode, Mode=OneWay}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<FontIcon FontSize="20" Grid.Column="0"
Glyph="{StaticResource mdi_toggle_off}"
FontFamily="{StaticResource MaterialDesignIconsOutlined}"
Foreground="{ThemeResource VividSkyBlueColor}"/>
<TextBlock Grid.Column="1" Margin="10,0,0,0" Text="Toggle"/>
</Grid>
</Button>
I tried using the generic BooleanConverter given here: How do I invert BooleanToVisibilityConverter?
Setting a SolidColorBrush
with the light blue color as True Value and the pale blue as the False Value and Binding the Foreground
property of my FontIcon
to the command but this does not work.
After that I tried to subscribe to the CanExecuteChanged
Event of the Command, saving the new value in a private field and binding to that but this does not work as well because at the time of initializing my view this command is still null.
My next guess would be to subscribe to the property changed event of the command when this is fired the command should'nt be null anymore and I should be able to subscribe to the Event but this seems like a lot boiler code especially if I have various commands I need to do this to.
How can I achieve this easier?
<FontIcon FontSize="20" Grid.Column="0"
Glyph="{StaticResource mdi_toggle_off}"
FontFamily="{StaticResource MaterialDesignIconsOutlined}"
Foreground="{x:Bind ToggleCommand, Mode=OneWay, Converter={StaticResource CanExecuteToIconColorConverter}}"/>
Following the anser by @AndrewKeepCoding I found out that just binding to the IsEnabled property of the button instead of binding to the command itself:
<Button Grid.Row="0" Width="150" Padding="10"
Command="{x:Bind ToggleMode, Mode=OneWay}"
x:Name="ToggleModeButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<FontIcon FontSize="20" Grid.Column="0"
Glyph="{StaticResource mdi_toggle_off}"
FontFamily="{StaticResource MaterialDesignIconsOutlined}"
Foreground="{x:Bind ToggleModeButton.IsEnabled, Mode=OneWay, Converter={StaticResource CanExecuteToIconColorConverter}}"/>
<TextBlock Grid.Column="1" Margin="10,0,0,0" Text="Toggle"/>
</Grid>
</Button>
Upvotes: 1
Views: 102
Reputation: 13666
Let me show you another way to achieve this using a ValueConverter.
BooleanToBrushConverter.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;
using System;
namespace FontIconExample;
public class BooleanToBrushConverter : DependencyObject, IValueConverter
{
public static readonly DependencyProperty TrueBrushProperty =
DependencyProperty.Register(
nameof(TrueBrush),
typeof(Brush),
typeof(BooleanToBrushConverter),
new PropertyMetadata(default));
public static readonly DependencyProperty FalseBrushProperty =
DependencyProperty.Register(
nameof(FalseBrush),
typeof(Brush),
typeof(BooleanToBrushConverter),
new PropertyMetadata(default));
public Brush TrueBrush
{
get => (Brush)GetValue(TrueBrushProperty);
set => SetValue(TrueBrushProperty, value);
}
public Brush FalseBrush
{
get => (Brush)GetValue(FalseBrushProperty);
set => SetValue(FalseBrushProperty, value);
}
public object Convert(object value, Type targetType, object parameter, string language)
{
return (bool)value is true
? TrueBrush
: FalseBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace FontIconExample;
public partial class ViewModel : ObservableObject
{
[RelayCommand(CanExecute = nameof(CanToggleMode))]
private void ToggleMode()
{
CanToggleMode = false;
}
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ToggleModeCommand))]
private bool canToggleMode = true;
}
MainPage.xaml
<Page
x:Class="FontIconExample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:FontIconExample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Page.DataContext>
<local:ViewModel x:Name="ViewModel" />
</Page.DataContext>
<Page.Resources>
<local:BooleanToBrushConverter
x:Key="BooleanToBrushConverter"
FalseBrush="LightGreen"
TrueBrush="SkyBlue" />
</Page.Resources>
<Grid>
<Button
x:Name="ToggleModeButton"
Grid.Row="0"
Width="150"
Padding="10"
Command="{x:Bind ViewModel.ToggleModeCommand, Mode=OneWay}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<FontIcon
Grid.Column="0"
FontFamily="Segoe MDL2 Assets"
FontSize="20"
Foreground="{x:Bind ToggleModeButton.IsEnabled, Mode=OneWay, Converter={StaticResource BooleanToBrushConverter}}"
Glyph="" />
<TextBlock
Grid.Column="1"
Margin="10,0,0,0"
Text="Toggle" />
</Grid>
</Button>
</Grid>
</Page>
Upvotes: 1
Reputation: 62110
In my experience FontIcon
is a bit flaky because in some ways it does not behave as expected. Modifying the color of the FontIcon could perhaps suit your particular situation, (if you could get it to work,) but in more complicated situations where you might have a complex control that must look disabled, it won't work.
What I prefer to do in these cases is to refrain from modifying the colors of individual elements and instead do one of the following:
When a certain deep blue is made slightly transparent, (or when it is overlaid by a white but almost transparent shade,) it will appear as light blue, and also a deep orange will appear as light orange, etc.
Upvotes: 0