WPF:在运行时从 App.xaml 更改资源(颜色)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/786183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:17:21  来源:igfitidea点击:

WPF: Changing Resources (colors) from the App.xaml during runtime

wpfxamlresourcescustomizationapp.xaml

提问by Andreas Grech

I am trying to make my application more customizable by allowing users to pick a color from a Color Picker dialog, and then changing the style of the application in real time (with DynamicResource)

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

How do I go about in changing specific resources that reside in the app.xaml?

我如何更改驻留在app.xaml.



I have tried something like this but no luck (just a test):

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

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));

This an excerpt of the app.xamlfile:

这是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>

What is the best way to allow this form of customizability (basically just changing some colors) to an application?

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



[Update]

[更新]

I just found this answerfrom a previous question that was asked, and tried it but I am getting the same InvalidOperationExceptionexception Petoj mentioned in the comments for the given answer. Here is the sample code from the answer:

我刚刚从之前提出的问题中找到了这个答案,并尝试了它,但我得到了在给定答案的评论中提到的相同的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#:

C#:

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

回答by Will Eddins

It looks like you're trying to do some sort of skinning?

看起来你正在尝试做某种剥皮?

I'd recommend defining the resources in a Resource Dictionary contained in a separate file. Then in code (App.cs to load a default, then elsewhere to change) you can load the resources as so:

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

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

Application.Current.Resources.MergedDictionaries.Add(dict);

You could also define the default resource dictionary in App.xaml and unload it in code just fine.

您还可以在 App.xaml 中定义默认资源字典并在代码中卸载它就好了。

Use the MergedDictionaries object to change the dictionary you're using at runtime. Works like a charm for changing an entire interface quickly.

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

回答by Nikos Tsokos

Changing application wide resources in runtime is like:

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

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

About the InvalidOperationException, i guess WallStreet Programmer is right. Maybe you should not try to modify an existing brush, but instead create a new brush in code with all the gradientstops you need, and then assign this new brush in application resources.

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

Another Approach on changing the color of some GradientStops is to define those colors as DynamicResource references to Application Wide SolidColorBrushes like:

另一种更改某些 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>

and then use

然后使用

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

HTH

HTH

回答by Steven

Use the Clone()method to make a deep copy of the brush (or any other freezable object like Storyboard) and then use it:

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

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

@WallstreetProgrammer is right - all application level resources are frozen by default.

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

Thats why you need to clone the object first.

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

回答by Wallstreet Programmer

You get an exception because you are trying to modify a frozen object. All application level resources are automatically frozen if they are freezable and LinearGradientBrush is. If you add it on a lower level like window level it will work.

由于您试图修改冻结的对象,因此会出现异常。如果所有应用程序级资源是可冻结的并且 LinearGradientBrush 是,则它们会自动冻结。如果您将它添加到窗口级别等较低级别,它将起作用。