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

发布于 2024-07-17 05:46:20 字数 1785 浏览 7 评论 0原文

我试图通过允许用户从颜色选择器对话框中选择颜色,然后实时更改应用程序的样式(使用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 的摘录。 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>

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


[更新]

我刚刚发现 < a href="https://stackoverflow.com/questions/529621/wpf-edit-resource/529687#529687">这个答案来自之前提出的问题,并尝试过,但我得到了相同的结果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;

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)

How do I go about in changing specific resources that reside in the 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.xaml file:

<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 answer from a previous question that was asked, and tried it but I am getting the same InvalidOperationException exception Petoj mentioned in the comments for the given answer. Here is the sample code from the answer:

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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

壹場煙雨 2024-07-24 05:46:20

看来您正在尝试进行某种剥皮?

我建议在单独文件中包含的资源字典中定义资源。 然后在代码中(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 对象更改运行时使用的字典。 就像快速改变整个界面的魅力一样。

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:

//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.

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

瀟灑尐姊 2024-07-24 05:46:20

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

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

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

更改某些 GradientStop 颜色的另一种方法是将这些颜色定义为对应用程序范围 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

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.

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

<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

十级心震 2024-07-24 05:46:20

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

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

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

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

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

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.

Thats why you need to clone the object first.

倾听心声的旋律 2024-07-24 05:46:20

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文