接口DataContexts

时间:2017-07-28 13:57:48

标签: c# wpf xaml mvvm

我已经设置了一个通用对话框窗口,它接收一个视图模型和标题,然后根据窗口的XAML进行显示。

例如,此代码设置窗口的标题和数据上下文并显示它:

public void ShowWindow(object viewModel, string title)
{
    var win = new DialogWindow()
    {
        Title = title,
        DataContext = viewModel
    };
    win.Show();
}

窗口的代码隐藏不包含任何相关内容,但其内容展示器的XAML如下所示:

<ContentPresenter x:Name="DialogPresenter" Content="{Binding}">
    <ContentPresenter.Resources>
        <DataTemplate DataType="{x:Type i:IMyInterface}" >
            <c:MyInterfacesControl/>
        </DataTemplate>
    </ContentPresenter.Resources>
</ContentPresenter>

问题是datatemplate不会触发,因为传入的viewmodel是该接口的实现。但是,我希望代码检测viewmodel是否实现了该代码,并相应地使用该模板。

我已经考虑过使用转换器解决问题的一种或两种方法,例如检查某些内容是否是转换器参数的实现。

但这里有更简单的方法吗?

编辑:这与评论中建议的问题不同(编辑2:现在已经不见了);我不知道接口类型(可以传入许多不同的接口类型),而是有一个类型为object的数据上下文。

1 个答案:

答案 0 :(得分:0)

DataTemplate不能将类型用作接口,通常应该将它与具体类型一起使用。

如果您定义了接口

public interface IA
{
    string A { get; set; }
}

实现它的具体类型:

public class AA : IA
{
    public string A { get; set; }
}

当传递new A()时,

<DataTemplate DataType="{x:Type local:IA}">
    <TextBlock Text="{Binding A}" />
</DataTemplate>

相反,你会看到像

这样的东西
  

Application.AA

解决方案1 ​​

可以使用具体类型,然后一切都会有效:

<DataTemplate DataType="{x:Type local:AA}">
    <TextBlock Text="{Binding A}" />
</DataTemplate>

解决方案2

使用接口类型的属性并绑定到它(而不是具体类型),这在this answer中有描述。

注意:您可以使用同名属性在具体类型中返回不同界面(选择数据模板的那个)。

解决方案3

您可以使用模板选择器。这非常简单,为数据模板提供密钥:

<DataTemplate x:Key="ia">
    <TextBlock Text="{Binding A}" />
</DataTemplate>

并选择在代码中使用哪一个:

public class TemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is IA)
            return (DataTemplate)((FrameworkElement)container).FindResource("ia");

        return base.SelectTemplate(item, container);
    }
}

ContentControl拥有ContentTemplateSelector属性,请勿使用ContentPresenter