Skip to content

Commit

Permalink
Add github.com/rudyhuyn/XamlPlus Attached Style Helper
Browse files Browse the repository at this point in the history
Resolve issue with ToggleSwitch override due to microsoft/microsoft-ui-xaml#7792
  • Loading branch information
rudyhuyn authored and michael-hawker committed Oct 6, 2022
1 parent 137cc07 commit 2df826b
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
</ComboBox>
</labs:SettingsCard>

<labs:SettingsCard
Description="Control if a feature is enabled or disabled"
Header="Enable feature"
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}">
<ToggleSwitch/>
</labs:SettingsCard>

<labs:SettingsCard Header="Preferred languages" IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}">
<labs:SettingsCard.Description>
<HyperlinkButton Content="Learn more about Phone Link" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@
<CheckBox Content="A control that is left aligned" />
</labs:SettingsExpanderItem>
<labs:SettingsExpanderItem Header="SettingsExpanderItem can be clicked as well" IsClickEnabled="True"/>


<labs:SettingsExpanderItem Header="A togglable setting">
<ToggleSwitch />
</labs:SettingsExpanderItem>

<labs:SettingsExpanderItem
Header="SettingsExpanderItem can be disabled"
Expand Down
59 changes: 59 additions & 0 deletions labs/SettingsControls/src/Helpers/ResourceDictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace CommunityToolkit.Labs.WinUI;

// Adapted from https://github.com/rudyhuyn/XamlPlus
internal static class ResourceDictionaryExtensions
{
/// <summary>
/// Copies the <see cref="ResourceDictionary"/> provided as a parameter into the calling dictionary, includes overwriting the source location, theme dictionaries, and merged dictionaries.
/// </summary>
/// <param name="destination">ResourceDictionary to copy values to.</param>
/// <param name="source">ResourceDictionary to copy values from.</param>
internal static void CopyFrom(this ResourceDictionary destination, ResourceDictionary source)
{
if (source.Source != null)
{
destination.Source = source.Source;
}
else
{
// Clone theme dictionaries
if (source.ThemeDictionaries != null)
{
foreach (var theme in source.ThemeDictionaries)
{
if (theme.Value is ResourceDictionary themedResource)
{
var themeDictionary = new ResourceDictionary();
themeDictionary.CopyFrom(themedResource);
destination.ThemeDictionaries[theme.Key] = themeDictionary;
}
else
{
destination.ThemeDictionaries[theme.Key] = theme.Value;
}
}
}

// Clone merged dictionaries
if (source.MergedDictionaries != null)
{
foreach (var mergedResource in source.MergedDictionaries)
{
var themeDictionary = new ResourceDictionary();
themeDictionary.CopyFrom(mergedResource);
destination.MergedDictionaries.Add(themeDictionary);
}
}

// Clone all contents
foreach (var item in source)
{
destination[item.Key] = item.Value;
}
}
}
}
73 changes: 73 additions & 0 deletions labs/SettingsControls/src/Helpers/StyleExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace CommunityToolkit.Labs.WinUI;

// Adapted from https://github.com/rudyhuyn/XamlPlus
public static partial class StyleExtensions
{
// Used to distinct normal ResourceDictionary and the one we add.
private sealed class StyleExtensionResourceDictionary : ResourceDictionary
{
}

public static ResourceDictionary GetResources(Style obj)
{
return (ResourceDictionary)obj.GetValue(ResourcesProperty);
}

public static void SetResources(Style obj, ResourceDictionary value)
{
obj.SetValue(ResourcesProperty, value);
}

public static readonly DependencyProperty ResourcesProperty =
DependencyProperty.RegisterAttached("Resources", typeof(ResourceDictionary), typeof(StyleExtensions), new PropertyMetadata(null, ResourcesChanged));

private static void ResourcesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (!(sender is FrameworkElement frameworkElement))
{
return;
}

var mergedDictionaries = frameworkElement.Resources?.MergedDictionaries;
if (mergedDictionaries == null)
{
return;
}

var existingResourceDictionary =
mergedDictionaries.FirstOrDefault(c => c is StyleExtensionResourceDictionary);
if (existingResourceDictionary != null)
{
// Remove the existing resource dictionary
mergedDictionaries.Remove(existingResourceDictionary);
}

if (e.NewValue is ResourceDictionary resource)
{
var clonedResources = new StyleExtensionResourceDictionary();
clonedResources.CopyFrom(resource);
mergedDictionaries.Add(clonedResources);
}

if (frameworkElement.IsLoaded)
{
// Only force if the style was applied after the control was loaded
ForceControlToReloadThemeResources(frameworkElement);
}
}

private static void ForceControlToReloadThemeResources(FrameworkElement frameworkElement)
{
// To force the refresh of all resource references.
// Note: Doesn't work when in high-contrast.
var currentRequestedTheme = frameworkElement.RequestedTheme;
frameworkElement.RequestedTheme = currentRequestedTheme == ElementTheme.Dark
? ElementTheme.Light
: ElementTheme.Dark;
frameworkElement.RequestedTheme = currentRequestedTheme;
}
}
11 changes: 7 additions & 4 deletions labs/SettingsControls/src/SettingsCard/SettingsCard.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="labs:StyleExtensions.Resources">
<Setter.Value>
<ResourceDictionary>
<Style BasedOn="{StaticResource RightAlignedCompactToggleSwitchStyle}" TargetType="ToggleSwitch" />
</ResourceDictionary>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="labs:SettingsCard">
Expand Down Expand Up @@ -174,11 +181,7 @@
VerticalAlignment="Center"
HorizontalContentAlignment="Right"
Content="{TemplateBinding Content}">
<ContentPresenter.Resources>
<Style BasedOn="{StaticResource RightAlignedCompactToggleSwitchStyle}" TargetType="ToggleSwitch" />
</ContentPresenter.Resources>
<!--
TO DO: This doesn't seem to work. Override the template of a ToggleSwitch making it right aligned
TO DO: Set MinWidth of 116px on the hosted Content: SettingsCardContentMinWidth
-->
</ContentPresenter>
Expand Down

0 comments on commit 2df826b

Please sign in to comment.