TabControl视图不会在模板更改时更新

时间:2019-09-30 19:05:52

标签: wpf mvvm datatemplate

我需要即时更改TabControl内容的视图。。
我想最好的方法是将视图定义为DataTemplate,然后使用触发器更改所述模板。

在我的测试应用中,背景色与模板的数据触发条件相同。选择单选按钮后,背景颜色会立即更新。

  • 预期的行为:选项卡项目内容/数据模板也会立即更新。
  • 实际行为:在更改选项卡选择之前,选项卡内容视图不会更新。

这是我的Minimal, Complete, and Verifiable example

Test App Image

Window XAML

<Window x:Class="ChangeView.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        Title="Window1" Height="350" Width="400">
    <Window.Resources>
        <DataTemplate x:Key="ContentTemplate1">
            <Grid>
                <Label HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding MyBlurb}"/>
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="ContentTemplate2">
            <Grid>
                <Label HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                       HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
                       Content="{Binding MyHeader}" Background="Black" Foreground="White" FontSize="72"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <Grid.Style>
            <Style TargetType="{x:Type Grid}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ViewType1}" Value="False">
                        <Setter Property="Background" Value="Chartreuse"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding ViewType1}" Value="True">
                        <Setter Property="Background" Value="Bisque"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Style>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <TextBlock Margin="10,38,0,0" Text="Content Template:"/>
        <RadioButton x:Name="radio1" Margin="120,40,0,0" Grid.ColumnSpan="2" Content="1" GroupName="ViewSelect" IsChecked="{Binding Path=ViewType1}"/>
        <RadioButton Margin="170,40,0,0" Grid.ColumnSpan="2" Content="2" GroupName="ViewSelect"/>

        <TabControl Grid.Row="1" ItemsSource="{Binding TabGroup}">
            <TabControl.Style>
                <Style TargetType="{x:Type TabControl}">
                    <Setter Property="Margin" Value="10"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding ViewType1}" Value="True">
                            <Setter Property="ContentTemplate" Value="{DynamicResource ContentTemplate1}"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding ViewType1}" Value="False">
                            <Setter Property="ContentTemplate" Value="{DynamicResource ContentTemplate2}"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TabControl.Style>
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <Border x:Name="headerBorder">
                        <Label Content="{Binding MyHeader}" FontSize="20"/>
                    </Border>
                </DataTemplate>
            </TabControl.ItemTemplate>
        </TabControl>
    </Grid>
</Window>

隐藏代码

namespace ChangeView
{
    using System.Windows;
    using System.ComponentModel;
    using System.Collections.ObjectModel;

    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        public ObservableCollection<TabData> TabGroup { get; set; } = new ObservableCollection<TabData>();

        private bool _viewType1 = true;
        public bool ViewType1
        {
            get { return _viewType1; }
            set { _viewType1 = value; RaisePropertyChanged(nameof(ViewType1)); }
        }

        public Window1()
        {
            TabGroup.Add(new TabData("♻️", "Recycle"));
            TabGroup.Add(new TabData("⚔", "Swords"));
            TabGroup.Add(new TabData("⚗", "Chemistry"));
            TabGroup.Add(new TabData("?", "Cactus"));
            TabGroup.Add(new TabData("?", "Tengu"));
            TabGroup.Add(new TabData("?", "Octopus"));

            DataContext = this;
            InitializeComponent();
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

    public class TabData : INotifyPropertyChanged
    {
        private string _myHeader, _myBlurb;

        public TabData(string header, string blurb)
        {
            MyHeader = header;
            MyBlurb = blurb;
        }

        public string MyHeader
        {
            get { return _myHeader; }
            set { _myHeader = value; RaisePropertyChanged(nameof(MyHeader)); }
        }

        public string MyBlurb
        {
            get { return _myBlurb; }
            set { _myBlurb = value; RaisePropertyChanged(nameof(MyBlurb)); }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

1 个答案:

答案 0 :(得分:2)

更改单选按钮状态后,更改所选标签。然后,您将看到正确的内容模板。

看起来,在TabControl中,仅更改内容模板不会导致呈现内容。如果通过切换所选选项卡来呈现新内容,则将使用当前内容模板。

因此,让我们编写一个ContentTemplate,它创建一个ContentControl并切换ContentControl的ContentTemplate。我已经测试过,当ContentTemplate更改时,ContentControl将重新呈现其内容。绑定有点冗长。

<TabControl ItemsSource="{Binding TabGroup}" Grid.Row="1">
    <TabControl.ContentTemplate>
        <DataTemplate>
            <ContentControl
                x:Name="ContentCtl"
                Content="{Binding}"
                />
            <DataTemplate.Triggers>
                <DataTrigger 
                    Binding="{Binding DataContext.ViewType1, RelativeSource={RelativeSource AncestorType=TabControl}}" 
                    Value="True">
                    <Setter 
                        TargetName="ContentCtl" 
                        Property="ContentTemplate" 
                        Value="{DynamicResource ContentTemplate1}"
                        />
                </DataTrigger>
                <DataTrigger 
                    Binding="{Binding DataContext.ViewType1, RelativeSource={RelativeSource AncestorType=TabControl}}" 
                    Value="False"
                    >
                    <Setter 
                        TargetName="ContentCtl" 
                        Property="ContentTemplate" 
                        Value="{DynamicResource ContentTemplate2}"
                        />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </TabControl.ContentTemplate>
    <TabControl.ItemTemplate>
        <DataTemplate>
            <Border x:Name="headerBorder">
                <Label Content="{Binding MyHeader}" FontSize="20"/>
            </Border>
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>

您还可以在后面的代码中执行一些丑陋的操作,以使TabControl再次根据命令呈现自身。或者,您可以替换TabControl.ContentTemplate上的元数据。