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>