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

本文关键字:控件 用户 依赖 属性 动态 WPF 同类型 | 更新日期: 2023-09-27 18:20:30

我对WPF相当陌生,在用户控件方面遇到了一些困难。

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

MySpecialButtonControl

此"按钮"有两种外观"oldStyle"answers"newStyle"(由枚举"AppearanceStyle"指定),由名为的依赖属性控制

MyLayoutProperty

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

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

Binding binding = new Binding("AppearanceStyle");
binding.Source = myOptionsClass;
this.myButton.SetBinding(UserControls.MySpecialButtonControl.MyLayoutProperty, binding);

效果非常好。但是,我如何直接更改所有UC实例的依赖属性,而不必迭代UC的集合等。?在WPF/C#中有没有实现这一点的方法?

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

接下来,我尝试使用这样一种风格的动态资源:

  <uc:MySpecialButtonControl x:Key="myFakeButton" ></uc:MySpecialButtonControl >
    <Style x:Key="myButtonStyle" TargetType="uc:MySpecialButtonControl ">
        <Setter Property="MyLayoutProperty" Value="{DynamicResource myFakeButton}"></Setter>
    </Style>

这允许我在运行时更改"myFakeButton"的"MyLayoutProperty",这是我想要的一半,但即使在谷歌上搜索了一段时间后,我仍然找不到将"myFakButton"的"MyLayoutProperty"绑定到setter的方法,这正是我真正需要的。

如有任何帮助,我们将不胜感激!

更新:我试图实现Michael提供的解决方案,但不幸的是,我得到了以下异常:

PropertyMetadata is already registered for type 'MySpecialButtonControl'.

经过一些谷歌搜索(参见MSDN),我发现OverrideMetadata调用应该放在"MySpecialButtonControl"的静态构造函数中,我做到了:

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

现在,应用程序正在编译。现在它运行得很好。

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

我不完全确定我是否理解,但我会尝试回答。如果这已经结束,请发表评论,我会编辑,直到我们到达那里。

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

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

当控件放置在Window上时,框架将在可用资源中查找具有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>

现在假设您有两种不同的样式,希望在运行时进行切换。您可以在App.xaml.中定义这些样式

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

在运行时,您可以执行类似的操作来切换控件的默认样式。

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

这还差吗?