【问题标题】:How to change WPF Material Design Palette at runtime?如何在运行时更改 WPF Material Design Palette?
【发布时间】:2019-01-27 19:47:47
【问题描述】:

我最近将解决方案“升级”到 VS2017 和 .NET Framework 4.6.1。

我还将所有 NuGet 包更新到最新版本。

这个问题可能涉及以下一个或多个包(括号中是以前的版本):

MahApps.Metro by Jan Karger et al. 1.6.5 (1.3.0-ALPHA016)

MaterialDesignColors by James Willock 1.1.3 (1.1.2)

MaterialDesignThemes by James Willock 2.5.0.1205 (1.1.0.234)

MaterialDesignThemes.MahApps by James Willock 0.0.12 (0.0.3)

还被引用的 WPF 相关包包括:

Extended.Wpf.Toolkit by Xceed 3.4.0 (2.6.0)

ControlzEx by Jan Karger et al. 3.0.2.4 (none, new dependency of MahApps.Metro)

在更新之前,以下内容会在运行时更改 UI 调色板:

private void primaryPaletteComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
   paletteHelper.ReplacePrimaryColor(this.primaryPaletteComboBox.Text);
}

/* Where: */

var paletteHelper = new MaterialDesignThemes.Wpf.PaletteHelper();

this.primaryPaletteComboBox.Items.AddRange(new object[] {
    "Amber",
    "Blue",
    "BlueGrey",
    "Brown",
    "Cyan",
    "DeepOrange",
    "DeepPurple",
    "Green",
    "Grey",
    "Indigo",
    "LightBlue",
    "LightGreen",
    "Lime",
    "Orange",
    "Pink",
    "Purple",
    "Red",
    "Teal",
    "Yellow"});

...超级简单,超级容易。

更新后,ReplacePrimaryColor 抛出如下异常:

System.InvalidOperationException: '无法安全地确定单个 SecondaryAccentBrush 的资源定义。'

将这些软件包降级到以前的版本会导致其他问题。

如何在这些软件包的最新版本中在运行时更改调色板?

我想通过简单地使用用户从 ComboBox 中选择的调色板名称来做到这一点。

显然SecondaryAccentBrush 是个问题。

有人知道过去几年发生了什么变化吗?

这应该很容易,但 Google 并没有给我任何有用的信息。也许我没有问正确的问题。

PaletteHelper 现在提供了一个看起来很有前途的ReplacePalette(Palette palette) 方法,也许有一种方法可以通过使用预定义资源的名称来实例化 Palette 对象?

我宁愿同时去看牙医和直肠科医师,也不愿乱用 XAML 资源定义。

【问题讨论】:

    标签: c# wpf mahapps.metro material-design-in-xaml


    【解决方案1】:

    您可以使用 MDIX PaletteHelper 实现此目的。

    适用于深色/浅色

    在您的 Ui 上放置一个 ToggleButton 并将其 isChecked bool 绑定到下面使用的 isDark bool(绑定或代码后面,但是您正在连接您的 ui)

        private readonly PaletteHelper _paletteHelper = new PaletteHelper();
    
        private void ToggleBaseColour(bool isDark)
        {
            ITheme theme = _paletteHelper.GetTheme();
            IBaseTheme baseTheme = isDark ? new MaterialDesignDarkTheme() : (IBaseTheme)new MaterialDesignLightTheme();
            theme.SetBaseTheme(baseTheme);
            _paletteHelper.SetTheme(theme);
        }
    

    用于原色和强调色

    MDIX GitHub 演示应用 PaletteSelector VM 编写良好且易于阅读的代码here

    【讨论】:

      【解决方案2】:

      这是我的解决方法,不是答案。

      所以在启动时,默认调色板是在 App.xaml 中设置的:

      <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.SWATCHNAME.xaml" />
      

      我正在做的改变它在运行时是:

      Uri uri = new Uri($"pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.{SWATCHNAME}.xaml");
      System.Windows.Application.Current.Resources.MergedDictionaries.RemoveAt(4);
      System.Windows.Application.Current.Resources.MergedDictionaries.Insert(4, new ResourceDictionary() { Source = uri });
      

      这符合我的要求,因为我可以在 Palette 构造函数中指定单个色样,而不必指定重音或设置色调索引。

      有问题的资源始终位于索引 4 处,所以现在我将使用它,因为 App.xaml 中没有定义任何键。

      唯一的其他警告是只有一些元素在运行时更改。在所有元素获得新颜色之前,必须使用 AppStart.cs 中的相同代码行重新启动应用程序。

      我希望这对其他人有所帮助。 (注意 SWATCHNAME 占位符和您的特定资源索引)

      如果有人有更好的想法,请告诉我。

      【讨论】:

        【解决方案3】:

        问题已经很老了,但也许对其他人有帮助。我认为您的 xaml 字典中缺少一些条目(与重音颜色相关)。最小值应该类似于以下

        <Application x:Class="MaterialTest.App"
                     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                     StartupUri="MainWindow.xaml">
            <Application.Resources>
                <ResourceDictionary>
                    <ResourceDictionary.MergedDictionaries>
        
                        <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                        <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                        <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
                        <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
        
                    </ResourceDictionary.MergedDictionaries>            
                </ResourceDictionary>
            </Application.Resources>
        </Application>
        

        但这对你来说还不够。您正在与 MahApp.Metro 集成 请点击此链接以了解有关集成的更多信息:https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/wiki/MahApps.Metro-integration

        好像您的主题已硬编码。最好直接从库中获取可用主题列表。然后你可以这样使用:

        SwatchesProvider swatchesProvider = new SwatchesProvider();
        List<string> PrimaryColorsList = swatchesProvider.Swatches.Select(a => a.Name).ToList();
        this.primaryPaletteComboBox.Items.AddRange(PrimaryColorsList);
        
        private void primaryPaletteComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            SwatchesProvider swatchesProvider = new SwatchesProvider();
            Swatch color= swatchesProvider.Swatches.FirstOrDefault(a => a.Name == this.primaryPaletteComboBox.Text);
            paletteHelper.ReplacePrimaryColor(color);
        }
        

        【讨论】:

          【解决方案4】:

          ITheme 有一个 SetPrimaryColorSetSecondaryColor 方法,也许以前没有。您还可以直接单独处理主题的属性(如primaryLightsecondaryMid、...)。

          private readonly PaletteHelper _paletteHelper = new PaletteHelper();
          
          ITheme theme = _paletteHelper.GetTheme();
          theme.SetPrimaryColor(System.Windows.Media.Color.FromRgb(200, 0, 0)); //red
          _paletteHelper.SetTheme(theme);
          

          【讨论】:

            猜你喜欢
            • 2021-08-30
            • 2023-03-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-06-27
            • 2015-02-21
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多