【问题标题】:WPF: Changing Resources (colors) from the App.xaml during runtimeWPF:在运行时从 App.xaml 更改资源(颜色)
【发布时间】:2010-10-21 15:12:21
【问题描述】:

我正在尝试通过允许用户从颜色选择器对话框中选择颜色,然后实时更改应用程序的样式(使用DynamicResource)来使我的应用程序更具可定制性

如何更改位于app.xaml 中的特定资源?


我尝试过这样的事情,但没有运气(只是一个测试):

var colorDialog = new CustomControls.ColorPickerDialog();
var dResult = colorDialog.ShowDialog();
var x = Application.Current.Resources.Values.OfType<LinearGradientBrush>().First();
x = new LinearGradientBrush();
x.GradientStops.Add(new GradientStop(colorDialog.SelectedColor,1));

这是app.xaml 文件的摘录:

<Application.Resources>
    <LinearGradientBrush x:Key="HeaderBackground" StartPoint="0.5,0" EndPoint="0.5,1">
        <GradientStop Color="#82cb02" Offset="1"/>
        <GradientStop Color="#82cb01" Offset="0.2"/>
        <GradientStop Color="#629a01" Offset="0.5"/>
    </LinearGradientBrush>
</Application.Resources>

为应用程序提供这种形式的可定制性(基本上只是改变一些颜色)的最佳方式是什么?


[更新]

我刚刚从之前提出的问题中找到了this answer,并尝试了它,但我得到了与给定答案在 cmets 中提到的相同的 InvalidOperationException 异常 Petoj。以下是答案中的示例代码:

Xaml

<LinearGradientBrush x:Key="MainBrush" StartPoint="0,0.5" EndPoint="1,0.5" >
    <GradientBrush.GradientStops>
        <GradientStop Color="Blue" Offset="0" />
        <GradientStop Color="Black" Offset="1" />
    </GradientBrush.GradientStops>
</LinearGradientBrush>

C#:

LinearGradientBrush myBrush = FindResource("MainBrush") as LinearGradientBrush;
myBrush.GradientStops[0].Color = Colors.Red;

【问题讨论】:

    标签: wpf xaml resources customization app.xaml


    【解决方案1】:

    您似乎正在尝试进行某种剥皮?

    我建议在包含在单独文件中的资源字典中定义资源。然后在代码中(App.cs 加载默认值,然后在其他地方进行更改)您可以这样加载资源:

    //using System.Windows
    ResourceDictionary dict = new ResourceDictionary();
    dict.Source = new Uri("MyResourceDictionary.xaml", UriKind.Relative);
    
    Application.Current.Resources.MergedDictionaries.Add(dict);
    

    您还可以在 App.xaml 中定义默认资源字典并在代码中将其卸载。

    使用 MergedDictionaries 对象更改您在运行时使用的字典。就像快速更改整个界面的魅力一样。

    【讨论】:

    • 请记住,MergedDictionaries 是一个容器。最近添加的 ResourceDictionary 中的资源获胜。如果意图以任何规律在字典之间来回翻转,则从列表中删除前一个字典可能是有益的。 (答案提到“在代码中卸载它”w.r.t 是 XAML 指定的默认值,但没有显示如何识别和删除它。)
    【解决方案2】:

    在运行时更改应用程序范围的资源就像:

    Application.Current.Resources("MainBackgroundBrush") = Brsh
    

    关于 InvalidOperationException,我猜华尔街程序员是对的。 也许您不应该尝试修改现有的画笔,而是在代码中创建一个带有您需要的所有渐变色标的新画笔,然后在应用程序资源中分配这个新画笔。

    改变某些 GradientStops 颜色的另一种方法是将这些颜色定义为对 Application Wide SolidColorBrushes 的 DynamicResource 引用,例如:

    <LinearGradientBrush x:Key="MainBrush" StartPoint="0, 0.5" EndPoint="1, 0.5" >
    <GradientBrush.GradientStops>
        <GradientStop Color="{DynamicResource FirstColor}" Offset="0" />
        <GradientStop Color="{DynamicResource SecondColor}" Offset="1" />
    </GradientBrush.GradientStops>
    

    然后使用

    Application.Current.Resources["FirstColor"] = NewFirstColorBrsh
    Application.Current.Resources["SecondColor"] = NewSecondColorBrsh
    

    HTH

    【讨论】:

    • 这正是我想要的。
    • 请注意,这在 Silverlight 中不起作用。不支持DynamicResource
    【解决方案3】:

    使用Clone() 方法制作画笔(或任何其他可冻结对象,如Storyboard)的深层副本,然后使用它:

    LinearGradientBrush myBrush = FindResource("MainBrush") as LinearGradientBrush;
    myBrush = myBrush.Clone();
    myBrush.GradientStops[0].Color = Colors.Red;
    

    @WallstreetProgrammer 是对的 - 默认情况下,所有应用程序级资源都被冻结。

    这就是为什么你需要先克隆对象。

    【讨论】:

      【解决方案4】:

      您收到异常是因为您尝试修改冻结的对象。如果它们是可冻结的并且 LinearGradientBrush 是,则所有应用程序级别的资源都会自动冻结。如果您将其添加到较低级别(例如窗口级别),它将起作用。

      【讨论】:

      • 但是我不能在窗口中添加它,因为这种样式适用于我项目中的每个窗口
      • 这帮助我解决了问题。我将具有 从 App.xaml 的 LinearGradientBrush 移动到我的 Window.Resources 并且 DynamicResource 开始按应有的方式应用。谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-16
      相关资源
      最近更新 更多