我是一个新的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
}
}
答案 0 :(得分:1)
是的,TabControl在切换标签时重新使用控件。它还根据需要卸载/重新加载控件,这会导致重置未绑定的控件。例如,如果Tab1具有选择了ItemA的ListBox,并且您选择ItemB并将选项卡切换为没有列表框的选项卡,则当您返回到Tab1时,将再次选择ItemA。
最好的办法是将UI属性绑定到后面代码中的某些内容。例如,TabControl可能包含TabItemViewModel列表,每个ViewModel应包含表示UI状态的属性,例如ListBox.SelectedItems或CheckBox.IsChecked。