WPF TabControl с DataTemplate ведет себя очень странно - PullRequest
3 голосов
/ 09 октября 2011

Если вы помещаете элементы управления в свой 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 ]

3 голосов
/ 09 октября 2011

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

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

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

2 голосов
/ 09 октября 2011

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>
...