C# WPF:动态更改相同类型的所有用户控件的依赖项属性值

C# WPF:动态更改相同类型的所有用户控件的依赖项属性值,c#,wpf,styles,C#,Wpf,Styles,我是WPF的新手,在使用用户控件时遇到了一些困难 private void Button_Click(object sender, RoutedEventArgs e) { // get the style resources var style1 = FindResource("Style1") as Style; var style2 = FindResource("Style2") as Style; var defaultStyle = FindResou

我是WPF的新手,在使用用户控件时遇到了一些困难

private void Button_Click(object sender, RoutedEventArgs e)
{
    // get the style resources
    var style1 = FindResource("Style1") as Style;
    var style2 = FindResource("Style2") as Style;
    var defaultStyle = FindResource(typeof (MySpecialButtonControl)) as Style;
    if (style1 == null || style2 == null || defaultStyle == null)
        return;

    // create a new style based on the "other" style
    var newDefaultStyle = new Style(
        typeof (MySpecialButtonControl),
        (defaultStyle.BasedOn == style1 ? style2 : style1));

    // set the application-level resource to the new default style
    Application.Current.Resources[typeof (MySpecialButtonControl)] = newDefaultStyle;
}

请考虑以下情况: 我有一个带有用户控件的WPF应用程序,比如

MySpecialButtonControl
此“按钮”有两个外观“oldStyle”和“newStyle”(由枚举“AppearanceStyle”指定),它们由名为的依赖项属性控制

MyLayoutProperty
回调函数必须执行更改布局的代码。 现在我想做的是: 我需要在运行时在代码隐藏文件中一次性更改此窗口中用户控件的所有(!)实例的外观

将(例如)属性绑定到UC类的单个实例

Binding binding = new Binding("AppearanceStyle");
binding.Source = myOptionsClass;
this.myButton.SetBinding(UserControls.MySpecialButtonControl.MyLayoutProperty, binding);
效果非常好。但是,我如何直接更改所有UC实例的dependency属性,而不必迭代UCs集合等。?在WPF/C中是否有实现这一点的方法

我试图通过使用样式来解决这个问题,但是在运行时更改所有UCs本身共享的样式是不可能的,因为它已经在使用中(并且已经绘制了使用此样式的UCs)

接下来,我尝试使用如下样式的动态资源:

  <uc:MySpecialButtonControl x:Key="myFakeButton" ></uc:MySpecialButtonControl >

    <Style x:Key="myButtonStyle" TargetType="uc:MySpecialButtonControl ">
        <Setter Property="MyLayoutProperty" Value="{DynamicResource myFakeButton}"></Setter>
    </Style>
通过谷歌搜索(请参阅),我发现OverrideMetadata调用应该放在“MySpecialButtonControl”的静态构造函数中,我这样做了:

static MySpecialButtonControl()
{
    DefaultStyleKeyProperty.OverrideMetadata(
    typeof(MySpecialButtonControl),
    new FrameworkPropertyMetadata(typeof(MySpecialButtonControl)));
}

现在,应用程序可以编译了。现在它工作得很好。

我不确定我是否完全理解,但我会尝试一个答案。请评论,如果这是关闭,我会编辑,直到我们到达那里

WPF中的所有控件都有一个属性
DefaultStyleKey
。任何派生的自定义控件或用户控件都可以使用此属性设置默认样式的键。在运行时,框架将尝试查找此密钥的资源。将默认样式键设置为类的运行时类型是很常见的

public MySpecialButtonControl()
{
    DefaultStyleKeyProperty.OverrideMetadata(
        typeof (MySpecialButtonControl),
        new FrameworkPropertyMetadata(typeof (MySpecialButtonControl)));

    InitializeComponent();
}
当控件放置到窗口上时,框架将在可用资源中查找具有由
DefaultStyleKey
定义的键的资源。可以在许多地方定义资源。谷歌“WPF资源解析”获取更多信息。最简单的说明方法是显示App.xaml中定义的默认样式

<Application.Resources>

    <!-- the default style for MySpecialButtonControls -->
    <Style x:Key="{x:Type uc:MySpecialButtonControl}"
           TargetType="{x:Type uc:MySpecialButtonControl}"
           BasedOn="{StaticResource {x:Type UserControl}}" >
        <Setter Property="Background" Value="Blue" />
    </Style>

</Application.Resources>
<Application.Resources>

    <!-- the first style -->
    <Style x:Key="Style1"
           TargetType="{x:Type uc:MySpecialButtonControl}"
           BasedOn="{StaticResource {x:Type UserControl}}">
        <Setter Property="Background" Value="Blue" />
    </Style>

    <!-- the second style -->
    <Style x:Key="Style2"
           TargetType="{x:Type uc:MySpecialButtonControl}"
           BasedOn="{StaticResource {x:Type UserControl}}">
        <Setter Property="Background" Value="Red" />
    </Style>

    <!-- the default style, now based on Style1 -->
    <Style x:Key="{x:Type uc:MySpecialButtonControl}"
           TargetType="{x:Type uc:MySpecialButtonControl}"
           BasedOn="{StaticResource Style1}" />

</Application.Resources>

这很接近吗?

如果您将所有控件绑定到myoptionClass对象,并且该对象作为一个单例实现(只有一个类实例处于活动状态),则只需更改myoptionClass的绑定属性,就可以更新所有控件。如果MyOptionClass实现INotifyPropertyChanged或使用依赖属性,则更改后的值应自动复制到UC的每个实例(这就是数据绑定的全部内容),感谢您的想法-它可以将UCs手动绑定到依赖属性,但这不是我想要的:我不想为每个控件手动进行数据绑定。假设我在代码中的某个地方动态创建一个新UC(可能是一个非常复杂的场景),然后“忘记”将其绑定到myOptionClass。=>则不会通过更改Dependency属性来更改其外观。=>不,代码维护很好。谢谢你的回答,Michael!我相信这是实现我想要的目标的一种方法——明天我会立即尝试。还有一个问题:如果你不能使用样式文件,你将如何解决这个问题(想象一个场景,UC布局中的更改非常复杂,并且具有许多相互依赖性,它们不能用XAML中的简单样式表示,但需要用C#实现)。是否有方法触发所有(!)的依赖项属性(MyLayoutProperty)值的更改没有将“MyOptionClass”手动绑定到每个UC的UCs实例?我想我现在可以自己回答我的问题了。:)我可以创建两种(或更多)不同的样式,它们的依赖属性值不同。更改样式将自动触发dependency Property回调,我可以在其中放置切换布局时必须执行的任何代码。尝试了您的解决方案,但遇到了一些问题-请参阅原始问题的更新。问题已解决。控件找不到样式资源,但现在它可以工作了。谢谢!
private void Button_Click(object sender, RoutedEventArgs e)
{
    // get the style resources
    var style1 = FindResource("Style1") as Style;
    var style2 = FindResource("Style2") as Style;
    var defaultStyle = FindResource(typeof (MySpecialButtonControl)) as Style;
    if (style1 == null || style2 == null || defaultStyle == null)
        return;

    // create a new style based on the "other" style
    var newDefaultStyle = new Style(
        typeof (MySpecialButtonControl),
        (defaultStyle.BasedOn == style1 ? style2 : style1));

    // set the application-level resource to the new default style
    Application.Current.Resources[typeof (MySpecialButtonControl)] = newDefaultStyle;
}