WPF TabControl模板

时间:2010-11-11 18:01:20

标签: wpf tabcontrol

我是一个新的WPF用户,我正试图围绕模板。特别是我正在尝试模板化TabControl。

我很困惑TabControl绑定到数据时实际生成的控件。我需要的是每个标签在其内容部分中有一个单独的控件副本。我发现,似乎创建了一组控件,当用户从一个选项卡到另一个选项卡时,只有绑定的数据发生了变化。

项目说明:

示例项目包含一个带TabControl的视图。在TabControl的内容模板中是一个ListBox。视图绑定到TabBindingViewModel类的对象。该类有一个名为Tabs的属性,它是TabViewModel对象的ObservableCollection。 TabViewModel类有两个属性:TabHeader和Guids。 TabViewModel.TabHeader是一个字符串,其中包含将出现在选项卡上的文本,TabViewModel.Guids是一个ObservableCollection字符串。

绑定时,TabBindingViewModel.Tabs集合中的每个TabViewModel都应在TabControl对象中生成一个选项卡,该选项卡的标题为TabViewModel.TabHeader属性。每个选项卡的内容应该是ListBox,其中填充了TabViewModel.Guids集合中的字符串集合。

问题

这一切似乎渲染/绑定都很好,但是如果你改变ListBox的状态(例如滚动或选择一个项目)然后更改选项卡,则状态会显示为新选项卡上的ListBox你刚才选择的这使我假设ListBox只有一个实例(而不是5个独立的实例),当你更改标签时,数据是唯一可以改变的。

在另一种情况下,我没有将集合绑定到模板,而是使用xaml中自己的ListBox显式定义每个TabItem对象。这次,当我从tab切换到tab时,每个ListBox都维护它自己的状态。

我的假设是否正确?如果是这样,我如何在仍然利用模板的同时实现第二种情况中描述的结果? (这是一个简化的例子。我的真实世界内容要复杂得多。)

提前感谢您的帮助!

我的示例的源代码如下所示。

查看课程

1。 TabBinding

<Window x:Class="TabBindingQuestion.View.TabBinding"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:TabBindingQuestion.ViewModel"
        Title="TabTemplateView" 
        Height="344" Width="618">
    <Window.Resources>
        <vm:TabBindingViewModel x:Key="Data" />
    </Window.Resources>
    <Grid DataContext="{StaticResource Data}">
        <TabControl Width="Auto"
                    Height="Auto"
                    ItemsSource="{Binding Tabs}"
                    IsSynchronizedWithCurrentItem="True">
            <TabControl.ItemContainerStyle>
                <Style TargetType="TabItem">
                    <Setter Property="Header" Value="{Binding TabHeader}" />
                    <Setter Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <ListBox Width="Auto"
                                         Height="Auto"
                                         ItemsSource="{Binding Guids}" />
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </TabControl.ItemContainerStyle>
        </TabControl>
    </Grid>
</Window>

ViewModel类

2。 ViewModelBase

using System.ComponentModel;

namespace TabBindingQuestion.ViewModel
{
    class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(object sender, string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

第3。 TabBindingViewModel

using System.Collections.ObjectModel;

namespace TabBindingQuestion.ViewModel
{
    class TabBindingViewModel : ViewModelBase
    {
        #region Members

        private ObservableCollection<TabViewModel> _Tabs;
        public ObservableCollection<TabViewModel> Tabs
        {
            get { return _Tabs; }
            set
            {
                _Tabs = value;
                OnPropertyChanged(this, "Tabs");
            }
        }

        #endregion

        #region Constructor

        public TabBindingViewModel()
        {
            var tabs = new ObservableCollection<TabViewModel>();
            for (int i = 1; i <= 5; i++)
            {
                tabs.Add(new TabViewModel() { TabHeader = "Tab " + i.ToString() });
            }
            Tabs = tabs;
        }

        #endregion
    }
}

4。 TabViewModel

using System;
using System.Collections.ObjectModel;

namespace TabBindingQuestion.ViewModel
{
    class TabViewModel : ViewModelBase
    {
        #region Members

        private string _TabHeader;
        public string TabHeader
        {
            get { return _TabHeader; }
            set
            {
                _TabHeader = value;
                OnPropertyChanged(this, "TabHeader");
            }
        }

        private ObservableCollection<string> _Guids;
        public ObservableCollection<string> Guids
        {
            get { return _Guids; }
            set
            {
                _Guids = value;
                OnPropertyChanged(this, "Guids");
            }
        }

        #endregion

        #region Constructors

        public TabViewModel()
        {
            var guids = new ObservableCollection<string>();
            for (int i = 1; i < 100; i++)
            {
                guids.Add(Guid.NewGuid().ToString());
            }
            Guids = guids;
        }

        #endregion
    }
}

1 个答案:

答案 0 :(得分:1)

是的,TabControl在切换标签时重新使用控件。它还根据需要卸载/重新加载控件,这会导致重置未绑定的控件。例如,如果Tab1具有选择了ItemA的ListBox,并且您选择ItemB并将选项卡切换为没有列表框的选项卡,则当您返回到Tab1时,将再次选择ItemA。

最好的办法是将UI属性绑定到后面代码中的某些内容。例如,TabControl可能包含TabItemViewModel列表,每个ViewModel应包含表示UI状态的属性,例如ListBox.SelectedItems或CheckBox.IsChecked。