12

我试图通过允许用户从颜色选择器对话框中选择一种颜色来使我的应用程序更具可定制性,然后实时更改应用程序的样式(使用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>

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


[更新]

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

xml :

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

4 回答 4

16

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

我建议在包含在单独文件中的资源字典中定义资源。然后在代码中(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.

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

于 2009-04-24T19:32:30.773 回答
13

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

于 2009-04-27T12:43:11.373 回答
3

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.

于 2010-05-05T19:07:15.283 回答
2

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

于 2009-04-24T19:02:11.470 回答