Reputation: 5015
At runtime I would like to activate / deactivate a highlighting effect.
For this I created an AttachedProperty Control.Highlight
. This adds new Resources
to the FrameworkElement
and thus overwrites the default values for e.g. ButtonBackground
(https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.button?view=winrt-22000).
This problem does not exist with ButtonBackgroundPointerOver
and ButtonBackgroundPressed
. Access is new here each time the corresponding Storyboard
has been triggered:
https://github.com/microsoft/microsoft-ui-xaml/blob/3b9d847e59094543a0a3e07a0779b6634c581bcf/dev/CommonStyles/Button_themeresources.xaml#L183
Unfortunately, the Background
is not set again once the control has been rendered.
FrameworkElement.UpdateLayout()
does not bring the desired effect here either.
So I decided to reapply the default Style
(DefaultButtonStyle
) to eventually disable the highlighting effect.
However, this does not work and the background remains unchanged.
AttachedProperty
public class Control
{
public static readonly DependencyProperty HightlightProperty = DependencyProperty.RegisterAttached("Hightlight", typeof(bool), typeof(Control), new PropertyMetadata(null, HightlightChangedCallback));
public static bool GetHightlight(DependencyObject target) => (bool)target.GetValue(HightlightProperty);
public static void SetHightlight(DependencyObject target, bool value) => target.SetValue(HightlightProperty, value);
private static void HightlightChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is FrameworkElement frameworkElement)
{
Hightlight(frameworkElement, (bool)e.NewValue);
}
}
private static void Hightlight(FrameworkElement frameworkElement, bool highlight)
{
try
{
var resourceDictionary = Application.Current.Resources.MergedDictionaries.First(dictionary => dictionary.Source.OriginalString.EndsWith("Highlight.xaml"));
switch (frameworkElement)
{
case Button button:
resourceDictionary = (ResourceDictionary)resourceDictionary["ButtonHighlightLight"]; // https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.button?view=winrt-22000
break;
default:
_ = App.ServiceProvider.GetRequiredService<IDialogService>().ShowAsync(new ContentDialog
{
Title = "undefined FrameworkElement for Highlight",
Content = $"'{frameworkElement.GetType().Name}' case missing",
CloseButtonText = "Ok!"
});
return;
}
foreach (var kvp in resourceDictionary)
{
if (highlight)
{
frameworkElement.Resources.Add(kvp);
}
else
{
frameworkElement.Resources.Remove(kvp.Key);
}
}
var styles = Application.Current.Resources.MergedDictionaries[0].Where(pair => pair.Value is Style).ToList();
var buttonStyles = styles.Where(pair => ((Style)pair.Value).TargetType == typeof(Button)).ToList();
var style = buttonStyles.First(); // DefaultButtonStyle
frameworkElement.Style = (Style)style.Value;
}
catch (Exception e)
{
_ = App.ServiceProvider.GetRequiredService<IDialogService>().ShowExceptionAsync(e, Translations.DialogTitle_Error);
}
}
}
XAML
<ToggleButton IsChecked="{x:Bind ViewModel.Highlight, Mode=TwoWay}"/>
<Button attachedProperties:Control.Hightlight="{x:Bind ViewModel.Highlight, Mode=OneWay}" MinWidth="120" />
Highlight.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary x:Key="ButtonHighlightLight"> <!--https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.button?view=winrt-22000-->
<SolidColorBrush x:Key="ButtonBackground" Color="#ff6900"/>
<SolidColorBrush x:Key="ButtonBackgroundPointerOver" Color="#ff6900"/>
<SolidColorBrush x:Key="ButtonBackgroundPressed" Color="Red"/>
</ResourceDictionary>
</ResourceDictionary>
The Background
should revert back to its original Color
.
Upvotes: 0
Views: 366
Reputation: 5015
Changing the Theme
leads to the goal. I'm not sure if this is the right way, but this will reload the Resources
.
// force resource reload
if (frameworkElement.ActualTheme == ElementTheme.Light)
{
frameworkElement.RequestedTheme = ElementTheme.Dark;
frameworkElement.RequestedTheme = ElementTheme.Light;
}
else if (frameworkElement.ActualTheme == ElementTheme.Dark)
{
frameworkElement.RequestedTheme = ElementTheme.Light;
frameworkElement.RequestedTheme = ElementTheme.Dark;
}
else
{
frameworkElement.RequestedTheme = ElementTheme.Light;
frameworkElement.RequestedTheme = ElementTheme.Dark;
frameworkElement.RequestedTheme = ElementTheme.Default;
}
public class Control
{
public static readonly DependencyProperty HightlightProperty = DependencyProperty.RegisterAttached("Hightlight", typeof(bool), typeof(Control), new PropertyMetadata(null, HightlightChangedCallback));
public static bool GetHightlight(DependencyObject target) => (bool)target.GetValue(HightlightProperty);
public static void SetHightlight(DependencyObject target, bool value) => target.SetValue(HightlightProperty, value);
private static void HightlightChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is FrameworkElement frameworkElement)
{
Hightlight(frameworkElement, (bool)e.NewValue);
}
}
private static void Hightlight(FrameworkElement frameworkElement, bool highlight)
{
try
{
var resourceDictionary = Application.Current.Resources.MergedDictionaries.First(dictionary => dictionary.Source.OriginalString.EndsWith("Highlight.xaml"));
resourceDictionary = (ResourceDictionary)resourceDictionary[$"Highlight{frameworkElement.ActualTheme}"]; // https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.button?view=winrt-22000
// check if resource was defined
if (resourceDictionary.Keys.All(o => !o.ToString().StartsWith(frameworkElement.GetType().Name)))
{
_ = App.ServiceProvider.GetRequiredService<IDialogService>().ShowAsync(new ContentDialog
{
Title = "undefined FrameworkElement for Control.Highlight",
Content = $"'{frameworkElement.GetType().Name}' resource missing in Highlight.xaml",
CloseButtonText = "Ok!"
});
return;
}
foreach (var kvp in resourceDictionary)
{
if (highlight)
{
frameworkElement.Resources.Add(kvp);
}
else
{
frameworkElement.Resources.Remove(kvp.Key);
}
}
// force resource reload
if (frameworkElement.ActualTheme == ElementTheme.Light)
{
frameworkElement.RequestedTheme = ElementTheme.Dark;
frameworkElement.RequestedTheme = ElementTheme.Light;
}
else if (frameworkElement.ActualTheme == ElementTheme.Dark)
{
frameworkElement.RequestedTheme = ElementTheme.Light;
frameworkElement.RequestedTheme = ElementTheme.Dark;
}
else
{
frameworkElement.RequestedTheme = ElementTheme.Light;
frameworkElement.RequestedTheme = ElementTheme.Dark;
frameworkElement.RequestedTheme = ElementTheme.Default;
}
}
catch (Exception e)
{
_ = App.ServiceProvider.GetRequiredService<IDialogService>().ShowExceptionAsync(e, Translations.DialogTitle_Error);
}
}
}
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary x:Key="HighlightLight">
<!--https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.button?view=winrt-22000-->
<SolidColorBrush x:Key="ButtonBackground" Color="#ff6900"/>
<SolidColorBrush x:Key="ButtonBackgroundPointerOver" Color="#ff6900"/>
<SolidColorBrush x:Key="ButtonBackgroundPressed" Color="Red"/>
<SolidColorBrush x:Key="AppBarButtonBackground" Color="#ff6900"/>
<SolidColorBrush x:Key="AppBarButtonBackgroundPointerOver" Color="#ff6900"/>
<SolidColorBrush x:Key="AppBarButtonBackgroundPressed" Color="Red"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighlightDark">
<!--https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.button?view=winrt-22000-->
<SolidColorBrush x:Key="ButtonBackground" Color="#ff6900"/>
<SolidColorBrush x:Key="ButtonBackgroundPointerOver" Color="#ff6900"/>
<SolidColorBrush x:Key="ButtonBackgroundPressed" Color="Red"/>
<SolidColorBrush x:Key="AppBarButtonBackground" Color="#ff6900"/>
<SolidColorBrush x:Key="AppBarButtonBackgroundPointerOver" Color="#ff6900"/>
<SolidColorBrush x:Key="AppBarButtonBackgroundPressed" Color="Red"/>
</ResourceDictionary>
</ResourceDictionary>
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right" Spacing="5" Margin="0,0,5,0">
<ToggleButton x:Name="ToggleButton1" IsChecked="{x:Bind ViewModel.Highlight, Mode=TwoWay}" />
<Button attachedProperties:Control.Hightlight="{x:Bind ViewModel.Highlight, Mode=OneWay}" MinWidth="120"
attachedProperties:Translation.Translatable="{x:Bind trans:Translations.Button_Acknowledge}" />
<Button MinWidth="120" attachedProperties:Translation.Translatable="{x:Bind trans:Translations.Button_HornOff}" />
<Button MinWidth="120"
attachedProperties:Translation.Translatable="{x:Bind trans:Translations.Button_AlarmsHistory}" />
<AppBarButton attachedProperties:Translation.Translatable="{x:Bind trans:Translations.Navigation_Alarms}" attachedProperties:Control.Hightlight="{x:Bind ViewModel.Highlight, Mode=OneWay}">
<AppBarButton.Content>
<svg:SvgAwesome Icon="Solid_TriangleExclamation" Height="20"/>
</AppBarButton.Content>
</AppBarButton>
</StackPanel>
Upvotes: 1