2

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

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

MySpecialButtonControl

这个“按钮”有两个外观“oldStyle”和“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”,这是我想要的一半,但即使在谷歌搜索了一段时间后,我仍然找不到将“myFakeButton”的“MyLayoutProperty”绑定到设置器的方法这是我真正需要的。

任何帮助将不胜感激!

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

PropertyMetadata is already registered for type 'MySpecialButtonControl'.

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

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

现在,应用程序编译。现在它完美地工作了。

4

1 回答 1

1

我不完全确定我是否遵循,但我会尝试回答。如果这很接近,请发表评论,我会编辑直到我们到达那里。

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>

现在假设您有两种不同的样式要在运行时在它们之间切换。您可以在 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;
}

这甚至接近吗?

于 2013-07-01T16:38:24.767 回答