在更改datacontext属性时更改contentcontrol的datatemplate

时间:2014-11-04 11:16:44

标签: c# wpf datatemplate

我有contentcontrol绑定到对象(示例中的DataContext的data属性)。每当data引用的对象发生更改时,我都想重新选择datatemplate。我怎么能这样做?

<ContentControl Name="rootData" Content="{Binding data}" 
            ContentTemplateSelector="{StaticResource myTemplateSelector}"/>

3 个答案:

答案 0 :(得分:1)

如果您有相同的数据类型和不同的Data值,那么您可以使用DataTemplate Selector,如下所示,否则只需使用DataTemplate的DataType属性,您甚至不需要datatemplate选择器。 下面是每次更改数据时选择模板的示例代码。

MainWindow.xaml

<Window x:Class="TextBindingFormatting.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TextBindingFormatting"
    Title="MainWindow" Height="350" Width="555">
<Window.Resources>
    <local:MyTemplateSelector x:Key="MyTemplateSelector"></local:MyTemplateSelector>
    <DataTemplate x:Key="Template1">
        <StackPanel Orientation="Horizontal">
            <Label>Label 1</Label>
            <Label>Label 2</Label>
        </StackPanel>
    </DataTemplate>
    <DataTemplate x:Key="Template2">
        <StackPanel Orientation="Vertical">
            <Label>Label 1</Label>
            <Label>Label 2</Label>
        </StackPanel>
    </DataTemplate>

</Window.Resources>
<Grid>
    <StackPanel>
    <ContentControl Content="{Binding Data}" ContentTemplateSelector="{StaticResource MyTemplateSelector}"></ContentControl>
        <Button Content="Change DataTemplate" Click="ButtonBase_OnClick"></Button>
    </StackPanel>
</Grid>

下面是Code Behind,理想情况下按钮点击应该使用命令来处理,但是对于快速示例我在代码后面实现了只是为了触发数据更改。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MainWindowViewModel() {Data = "1"};
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        var vm = this.DataContext as MainWindowViewModel;
        vm.Data = "2";
    }
}

以下是MainWindow的ViewModel

namespace TextBindingFormatting.ViewModels
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        private string _data;
        public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public string Data
    {
        get { return _data; }
        set
        {
            _data = value;
            OnPropertyChanged("Data");
        }
    }
}

}

DataTemplate Selector

namespace TextBindingFormatting
{
    public class MyTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var element = container as FrameworkElement;
            if (element == null || item == null)
                return base.SelectTemplate(item, container);

        if (item.ToString() == "1")
            return element.FindResource("Template1") as DataTemplate;

        if (item.ToString() == "2")
            return element.FindResource("Template2") as DataTemplate;

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

答案 1 :(得分:1)

如果您要更改整个数据类型,那么您的视图应如下所示,唯一的区别是删除键并使用DataType for DataTemplate,这称为隐式数据模板

<Window x:Class="TextBindingFormatting.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TextBindingFormatting"
    xmlns:viewModels="clr-namespace:TextBindingFormatting.ViewModels"
    Title="MainWindow" Height="350" Width="555">
<Window.Resources>
    <local:MyTemplateSelector x:Key="MyTemplateSelector"></local:MyTemplateSelector>
    <DataTemplate DataType="{x:Type viewModels:Student}">
        <StackPanel Orientation="Horizontal">
            <Label>Id</Label>
            <TextBlock Text="{Binding Id}"></TextBlock>
            <Label>Name</Label>
            <TextBlock Text="{Binding Name}"></TextBlock>
        </StackPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:Parent}">
        <StackPanel Orientation="Vertical">
            <Label>Name</Label>
            <TextBlock Text="{Binding Name}"></TextBlock>
        </StackPanel>
    </DataTemplate>

</Window.Resources>
<Grid>
    <StackPanel>
    <ContentControl Content="{Binding Data}" >
    </ContentControl>
        <Button Content="Change DataTemplate" Click="ButtonBase_OnClick"></Button>
    </StackPanel>
</Grid>

背后的代码

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MainWindowViewModel() {Data = new Student{Id = 1, Name = "Student"}};
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        var vm = this.DataContext as MainWindowViewModel;
        vm.Data = new Parent() {Name = "This is parent"};
    }
}

我有两个课程如下

public class Student : INotifyPropertyChanged
{
    private string _name;
    private int _id;
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public string Name {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }

    public int Id
    {
        get { return _id; }
        set
        {
            _id = value;
            OnPropertyChanged("Id");
        }
    }
}

另一个

public class Parent : INotifyPropertyChanged 
{

    private string _name;
    public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged(string propertyName)

    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }
}

答案 2 :(得分:0)

从Rachel找到了一个可能的解决方案: Change Data template dynamically

DataTemplateSelector不会触发PropertyChange,但设置触发器可以帮我完成工作!