WPF TabControl с DataTemplate ведет себя очень странно

#wpf #silverlight #xaml #datatemplate #tabcontrol

#wpf #серебристый свет #xaml #datatemplate #tabcontrol #silverlight

Вопрос:

Если вы помещаете элементы управления в свой DataTemplate, почему их отдельные состояния копируются или отражаются на каждой вкладке в TabControl? Вы меняете его на одной вкладке, все остальные вкладки отражают, почему это так ?! Мне кажется, TabControl инициализирует только один шаблонный ContentControl, и каждый щелчок по вкладке копирует все содержимое в нем заново, оставляя старые controlstates нетронутыми. Чтобы понять, что я имею в виду, подумайте о том, чтобы поместить это в свой 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 );
    }
}
  

Комментарии:

1. Я думаю, что свойства ContentTemplate и ItemTemplate должны применяться к элементам свойства ItemsSource, а не к явно определенным элементам. Но встроенный TabControl не имеет свойства ItemsSource, поэтому вы можете использовать расширенный TabControl: vortexwolf.wordpress.com/2011/04/09 /. … Но я не знаю, что не так с этим конкретным примером. В любом случае элемент управления вкладками silverlight отличается от своего аналога в WPF, так что, возможно, это ошибка.

2. Я попытался применить шаблон к самому TabItem, что дает тот же результат. TabControl в WPF, по крайней мере, имеет ItemsSource, который я использую для его заполнения. В вашей расширенной версии элементы управления внутри DataTemple не переносят свои состояния? Вы пробовали поставить флажок или что-то в этом роде и посмотреть, идет ли одна проверка для всех? Я мог бы попробовать … спасибо за ваше время и наилучшие пожелания

Ответ №1:

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

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

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

Комментарии:

1. Ну, тогда в таком случае, почему бы вам не создать отдельные элементы вкладки и не добавить их в качестве дочерних элементов элемента управления вкладками? Я понимаю, что вы пытаетесь сделать, но в этом случае вы не можете сохранить состояние редактирования. Если вы определяете шаблон данных, то каждый раз, когда вы будете переключаться, элемент вкладки будет выгружен и будет загружен новый элемент, и если вы поместите трассировку в событие загрузки, оно будет запускаться при каждом переключении. Такое поведение характерно для визуального представления с привязкой к данным, но если вы говорите о редактировании состояния, то само состояние становится данными.

2. Если элемент управления вкладкой содержит элемент вкладки с элементом пользовательского интерфейса, он сохранит все.

3. Проблема в том, что вам нужно привязать все, а не только содержимое. В моей программе я использую привязки к данным, и, конечно, содержимое не переключается, но все остальное меняется. Например, положение полосы прокрутки в списке, выбранный элемент, состояние расширителя и т. Д., И т. Д., И т. Д. Это делает его практически непригодным для использования и сбивает с толку моих клиентов. 🙁

4. О, я извиняюсь, поэтому не позволил мне изменить свой комментарий, поэтому я удалил и создал новый, слишком поздно. Я попробую это сейчас, большое вам спасибо!! (-:

5. Это работает! большое спасибо, я быстро найду решение!

Ответ №2:

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

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

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

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

Комментарии:

1. Большое спасибо, это, по крайней мере, объясняет это! Но, как я писал ранее, простого привязывания содержимого, по-видимому, недостаточно, поскольку также переносится каждое видимое состояние, позиции полосы прокрутки, выбранные элементы, расширенные состояния и т. Д. Это означало бы, что мне пришлось бы раздувать мою ViewModel мусором. Я серьезно рассматриваю возможность написания TabControl самостоятельно, я понятия не имею, как они могли бы выпустить его таким образом. 🙁

2. @hpalu Самым простым способом, вероятно, было бы создать UserControl ваш TabContent, а затем установить содержимое каждого TabItem в новый экземпляр UserControl. Это должно содержать отдельные экземпляры каждой вкладки, хотя не связанные значения, такие как позиции списка и расширенные значения, будут сброшены при переключении вкладок. Для поддержания этих значений я обычно использую расширенный TabControl, найденный здесь: pluralsight-training.net/community/blogs/eburke/archive/2009/04 /…

3. Вау, большое спасибо, Рейчел! Если это поможет избавить меня от необходимости писать свою собственную версию, я был бы очень признателен. : D

4. Рейчел, я использовал решение Akashs, это избавляет меня от многих проблем прямо сейчас, но я все еще читаю материал, который вы мне прислали, еще раз большое спасибо!