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

Bra*_*ach 8 wpf

是否可以在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
}
Run Code Online (Sandbox Code Playgroud)

假设我有两个继承自这些基类的类:

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

    // TestView specific methods, properties, etc
}

public class TestViewModel : ViewModel
{ /* TestViewModel specific methods, properties, etc */ }
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

我基本上试图采用我的基本视图/ viewmodel类并应用一致的外观.这当然适用于非通用基本视图案例.但是,我需要在视图和视图模型之间进行类型安全连接,这样我就可以从视图中调用视图模型上的方法(我知道这些方法可能与某些人已经实现MVVM的方式"坐得不好").

cwi*_*lls 5

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

1 - 将DefaultStyleKey设置为CodeNaked的答案中提到的默认泛型类型:

    DefaultStyleKeyProperty.OverrideMetadata(typeof(View<T>), 
        new FrameworkPropertyMetadata(typeof(View<>)));
Run Code Online (Sandbox Code Playgroud)

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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

        . . .
Run Code Online (Sandbox Code Playgroud)

多数民众赞成.但有一点需要注意,当您尝试绑定/设置View <T>类中定义的任何依赖项属性时,VS会抛出编译错误.所以你不能使用像{TemplateBinding ViewTProperty}... 这样的简单语法