WPF:设置通用基本控件的样式

2024-04-13

是否可以为 WPF 中的通用基本控件提供默认样式?

假设我有以下基类:

public abstract class View<T> : ContentControl
    where T : ViewModel
{
    static View()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(View<T>), 
            new FrameworkPropertyMetadata(typeof(View<T>)));
    }

    // Other properties, methods, etc in here
}

public abstract class ViewModel
{
    // Other properties, methods, etc in here
}

然后假设我有两个从这些基类继承的类:

public partial class TestView : View<TestViewModel>
{
    public TestView()
    {
        InitializeComponent();
    }

    // TestView specific methods, properties, etc
}

public class TestViewModel : ViewModel
{ /* TestViewModel specific methods, properties, etc */ }

现在我想为我的所有派生控件使用的基本控件提供默认样式:

<Style TargetType="{x:Type local:View`1}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:View`1}">
                <Border Background="Magenta"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <StackPanel>
                        <Button>Test</Button>
                        <ContentPresenter ContentSource="Content" />
                    </StackPanel>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

但是,当我使用 TestView 控件时,我没有应用模板标记(因此我可能在 TestView 控件的 XAML 中定义的任何内容都不在视觉/逻辑树中)。

我基本上试图采用我的基本视图/视图模型类并应用一致的外观和感觉。这当然适用于非通用基本视图情况。然而,我需要视图和视图模型之间的类型安全连接,这样我就可以从任何引用视图的地方调用视图模型上的方法(我知道这可能不适合某些人实现 MVVM 的方式)。


我发现相当简单的解决方案涉及自定义TypeExtension.

1 - 将 DefaultStyleKey 设置为默认泛型类型正如 CodeNaked 的回答中提到的 https://stackoverflow.com/a/5413514/590790:

    DefaultStyleKeyProperty.OverrideMetadata(typeof(View<T>), 
        new FrameworkPropertyMetadata(typeof(View<>)));

2 - 创建以下类并继承自System.Windows.Markup.TypeExtension


    [System.Windows.Markup.ContentProperty("Type")]
    public class TypeExtension : System.Windows.Markup.TypeExtension
    {
        public TypeExtension()
            : base()
        { }

        public TypeExtension(Type type)
        : base(type)
        { }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Type == null)
                throw new InvalidOperationException("Must specify the Type");

            return Type;
        }
    }

3 - 更新样式的 TargetType 以指向新的local:Type扩展而不是通常的x:Type扩大


    <Style>
        <Style.TargetType>
            <local:Type Type="{x:Type local:View`1}" />
        </Style.TargetType>
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Control}">

        . . .

就是这样.. 但有一个警告,当您尝试绑定/设置 View 类上定义的任何依赖项属性时,VS 会引发编译错误。所以你不能使用像这样的简单语法{TemplateBinding ViewTProperty} ...

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WPF:设置通用基本控件的样式 的相关文章

随机推荐