WPF TabControl 与 DataTemplate 的行为非常奇怪
如果将控件放入 DataTemplate 中,为什么它们的各个状态会复制或反映在 TabControl 中的每个选项卡中?你在一个选项卡中更改它,所有其他选项卡都会反映,这是为什么?!在我看来,TabControl 仅初始化一个模板化的 ContentControl,并且每次单击选项卡都会重新复制其中的整个内容 - 使旧的控件状态保持不变。要明白我的意思,请考虑将其放入 XAML-Pad 中:
<TabControl>
<TabControl.ContentTemplate>
<DataTemplate>
<Border>
<TextBox Text="test"/>
</Border>
</DataTemplate>
</TabControl.ContentTemplate>
<TabItem Header="Tab1"/>
<TabItem Header="Tab2"/>
</TabControl>
它将创建一个带有两个模板化选项卡的 TabControl。现在在文本框中输入一些内容并切换到另一个选项卡,输入的文本将保留。现在每个选项卡将具有相同的内容。我没有在 ListBox 或任何其他控件中观察到相同的行为,这使得实际工作非常困难,因为每一点都需要绑定到 ViewModel 才能使其在 TabControl 中可用。当我在 DataTemplate 中使用的扩展器在我的所有选项卡中弹出时,我注意到了这种奇怪的行为,尽管我专门解决了一个问题。作为一种解决方法,我必须将“IsExpanded”绑定到 ViewModel 中的属性,但这样做确实很糟糕。
有人知道这里发生了什么事吗?
解决方案
<TabControl x:Name="MainTab" SelectedIndex="0"/>
...
Collection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Collection_CollectionChanged);
...
void Collection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
TabItem MyNewItem = new TabItem();
ContentPresenter MyContentPresenter = new ContentPresenter();
MyContentPresenter.ContentTemplate = (DataTemplate)this.FindResource("MyTemplate");
MyContentPresenter.Content = e.NewItems[0];
MyNewItem.Content = MyContentPresenter;
MainTab.Items.Add(MyNewItem );
}
}
If you put controls in your DataTemplate, why are their individual states copied or reflected in each and every Tab in the TabControl? You change it in one Tab, all other Tabs reflect, why is that?! It seems to me the TabControl initializes one templated ContentControl only and each click on a Tab copies the entire content in it anew - leaving old controlstates untouched. To see what i mean consider putting this in your XAML-Pad:
<TabControl>
<TabControl.ContentTemplate>
<DataTemplate>
<Border>
<TextBox Text="test"/>
</Border>
</DataTemplate>
</TabControl.ContentTemplate>
<TabItem Header="Tab1"/>
<TabItem Header="Tab2"/>
</TabControl>
It will create a TabControl with two templated tabs. Now enter something in the TextBox and switch to another Tab, the entered text will carry over. Each Tab will have the same content now. I do not observe the same behavior in a ListBox or any other control and it makes practical work very hard because every little bit needs to be bound to a ViewModel to make it usable in a TabControl. I noticed this weird behavior when Expanders i used in a DataTemplate popped open in all of my tabs, although i specifically addressed one. As a workaround i had to bind "IsExpanded" to a property in the ViewModel, but it really sucks having to do that.
Anyone knows what's happening here?
SOLUTION
<TabControl x:Name="MainTab" SelectedIndex="0"/>
...
Collection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Collection_CollectionChanged);
...
void Collection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
TabItem MyNewItem = new TabItem();
ContentPresenter MyContentPresenter = new ContentPresenter();
MyContentPresenter.ContentTemplate = (DataTemplate)this.FindResource("MyTemplate");
MyContentPresenter.Content = e.NewItems[0];
MyNewItem.Content = MyContentPresenter;
MainTab.Items.Add(MyNewItem );
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这种行为是完美的,并且有一种方法可以解决这个问题。 DataTemplate 必须仅在绑定的情况下使用。当您将可枚举项源分配给选项卡控件时,您的数据模板应该并且将包含一种或两种方式的绑定。如果是文本框,则应该是双向绑定。
TabControl 这样做是为了节省内存,在数据模板的情况下,切换选项卡时控件保持不变,但它的底层绑定数据上下文发生了变化,并且绑定反映了正确的数据。因此,视觉上你感觉选项卡发生了变化,但实际上只有数据发生变化,但控件保持不变。这称为 ui 虚拟化。
在您的情况下,除非将某些内容绑定到项目源,否则不应使用数据模板。否则,您必须使用项目容器样式。
The behavior is perfect and there is a way to resolve this. DataTemplate must be used only in case of binding. When you assign an enumerable items source to tab control, your data template should and will consist either one or two way bindings. In case of text box, it should be two way binding.
TabControl does this to save memory, in case of data template, control remains same when you switch tab, but it's the under lying bound datacontext is what changes, and binding reflects correct data. So visually you feel as tab has changed, but actually only data changes, however control remains same. This is called ui virtualization.
In your case you should not use data template unless you bind something to items source. Otherwise you must use item container style.
WPF 中的 TabControl 使用起来有点令人讨厌。首先,当您切换选项卡时,它会销毁第一个选项卡上的所有内容,并加载第二个选项卡的控件。唯一不会被破坏/重新创建的是所有选项卡上存在的控件,例如在 TabItem 的模板中创建的 TextBox。
因此,您的 TextBox 在其他选项卡上被重复使用,并且由于 TextBox.Text 没有绑定到任何内容,因此在切换选项卡时它保持不变。
要更改此行为,请将 TextBox.Text 值绑定到某些内容,或者使用其自己的 TextBox 版本创建每个 TabItem。
TabControls in WPF are slightly obnoxious to work with. For one, when you switch tabs it destroys everything on the first tab, and loads up the controls for the 2nd tab. The only thing that doesn't get destoryed/recreated is the controls that exist on all tabs, such as a TextBox that is created in the TabItem's Template.
So your TextBox is getting re-used on the other tabs, and since the TextBox.Text is not bound to anything, it stays the same when switching tabs.
To change this behavior, either bind the TextBox.Text value to something, or create each TabItem with it's own version of the TextBox.