开发者

WPF TabControl with DataTemplate behaves very strange

开发者 https://www.devze.com 2023-04-11 23:08 出处:网络
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?! I

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>
      开发者_Go百科<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 );
    }
}


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.


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.

<TabControl>
    <TabItem Header="Tab1">
        <local:TabControlContent />
    </TabItem>
    <TabItem Header="Tab2">
        <local:TabControlContent />
    </TabItem>
</TabControl>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号