我是一个新的WPF用户,我试图围绕模板 . 特别是我试图模板TabControl .
当TabControl绑定到数据时,实际生成的控件让我感到困惑 . 我需要的是每个标签在其内容部分中有一个单独的控件副本 . 我发现,似乎创建了一组控件,当用户从一个选项卡到另一个选项卡时,只有绑定的数据发生了变化 .
Project Description:
示例项目由带有TabControl的单个视图组成 . 在TabControl的内容模板中是一个ListBox . 视图绑定到TabBindingViewModel类的对象 . 该类有一个名为Tabs的属性,它是TabViewModel对象的ObservableCollection . TabViewModel类有两个属性:TabHeader和Guids . TabViewModel.TabHeader是一个字符串,其中包含将出现在选项卡上的文本,TabViewModel.Guids是一个ObservableCollection字符串 .
绑定时,TabBindingViewModel.Tabs集合中的每个TabViewModel都应在TabControl对象中生成一个选项卡,该选项卡的 Headers 为TabViewModel.TabHeader属性 . 每个选项卡的内容应该是ListBox,其中填充了TabViewModel.Guids集合中的字符串集合 .
Problem
这一切似乎渲染/绑定都很好,但是如果你改变ListBox的状态(例如滚动或选择一个项目)然后更改选项卡,看起来状态会转移到新选项卡上的ListBox,你只是选择 . 这使我假设只有一个ListBox实例(而不是5个独立的实例),当您更改选项卡时,数据是唯一发生变化的事情 .
在另一种情况下,我没有将集合绑定到模板,而是使用xaml中自己的ListBox显式定义每个TabItem对象 . 这次,当我从tab切换到tab时,每个ListBox都维护它自己的状态 .
我的假设是否正确?如果是这样,我如何在仍然利用模板的同时实现第二种情况中描述的结果? (这是一个简化的例子 . 我的真实世界内容要复杂得多 . )
在此先感谢您的帮助!
我的示例的源代码如下所示 .
View Classes
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 Classes
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 回答
是的,TabControl在切换选项卡时重新使用控件 . 它还根据需要卸载/重新加载控件,这会导致重置未绑定的控件 . 例如,如果Tab1具有选择了ItemA的ListBox,并且您选择了ItemB并将选项卡切换为没有列表框的选项卡,则当您返回到Tab1时,将再次选择ItemA .
最好的办法是将UI属性绑定到后面代码中的某些内容 . 例如,TabControl可能包含TabItemViewModel列表,每个ViewModel应包含表示UI状态的属性,例如ListBox.SelectedItems或CheckBox.IsChecked .