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 с двумя шаблонными вкладками. Теперь введите что-нибудь в TextBox и переключитесь на другую вкладку, введенный текст будет перенесен. Каждая вкладка теперь будет иметь одинаковое содержимое. Я не наблюдаю такого же поведения в 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 );
    }
}

2 ответа

Решение

Поведение идеально, и есть способ решить эту проблему. DataTemplate должен использоваться только в случае привязки. Когда вы назначаете источник перечислимых элементов элементу управления вкладками, шаблон данных должен и будет состоять из односторонних или двусторонних привязок. В случае текстового поля оно должно быть двухсторонним.

TabControl делает это для экономии памяти, в случае шаблона данных элемент управления остается тем же самым, когда вы переключаете вкладку, но именно нижележащий ограниченный текст данных - это то, что изменяется, и привязка отражает правильные данные. Так что визуально вы чувствуете, как изменилась вкладка, но на самом деле изменяются только данные, однако контроль остается тем же. Это называется виртуализацией пользовательского интерфейса.

В вашем случае вы не должны использовать шаблон данных, если вы не связываете что-то с источником элементов. В противном случае вы должны использовать стиль контейнера элемента.

TabControls в WPF немного неприятны для работы. Например, когда вы переключаете вкладки, он уничтожает все на первой вкладке и загружает элементы управления для 2-й вкладки. Единственное, что не может быть удалено или воссоздано, - это элементы управления, существующие на всех вкладках, например, TextBox, созданный в шаблоне TabItem.

Таким образом, ваш TextBox повторно используется на других вкладках, и поскольку TextBox.Text не привязан ни к чему, он остается тем же при переключении вкладок.

Чтобы изменить это поведение, либо привяжите значение TextBox.Text к чему-либо, либо создайте каждый элемент TabItem с его собственной версией TextBox.

<TabControl>
    <TabItem Header="Tab1">
        <local:TabControlContent />
    </TabItem>
    <TabItem Header="Tab2">
        <local:TabControlContent />
    </TabItem>
</TabControl>
Другие вопросы по тегам