TabControl располагает элементами управления на неактивных вкладках - PullRequest
3 голосов
/ 10 февраля 2010

Я использую шаблон MVVM для своего приложения. MainWindow содержит TabControl с DataContext, сопоставленным с ViewModel:

<Window.Resources>
  <ResourceDictionary>
    <DataTemplate x:Key="templateMainTabControl">
      <ContentPresenter Content="{Binding Path=DisplayName}" />
    </DataTemplate>

    <local:ViewModel x:Key="VM" />
    <local:WorkspaceSelector x:Key="WorkspaceSelector" />
    <local:TabOneView x:Key="TabOneView" />
    <local:TabTableView x:Key="TabTableView" />

    <DataTemplate x:Key="TabOne">
      <local:TabOneView />
    </DataTemplate>

    <DataTemplate x:Key="TabTable">
      <local:TabTableView />
    </DataTemplate>

  </ResourceDictionary>
</Window.Resources>


<TabControl Grid.Row="0"
            DataContext="{StaticResource VM}"
            ItemsSource="{Binding Workspaces}"
            SelectedItem="{Binding SelectedWorkspace}"
            ItemTemplate="{StaticResource templateMainTabControl}"
            ContentTemplateSelector="{StaticResource WorkspaceSelector}" />

WorkspaceSelector выглядит так:

public class WorkspaceSelector : DataTemplateSelector
{
  public override DataTemplate SelectTemplate( object item, DependencyObject container )
  {
    Window win = Application.Current.MainWindow;
    Workspace w = ( Workspace ) item;
    string key = w.DisplayName.Replace( " ", "" );
    if ( key != "TabOne" )
    {
      key = "TabTable";
    }
    return win.FindResource( key ) as DataTemplate;
  }
}

так что TabOne возвращает DataTemplate. TabOne и две другие вкладки возвращают DataTemplate TabTable.

Если я запускаю приложение и дважды нажимаю на каждую вкладку (1, 2, 3, 1, 2, 3), я не получаю ожидаемого результата, а это


Представление TabOne создано
Представление TabTwo создано
TabOne's View создан
Создан вид TabTwo

, то есть, если TemplateSelector возвращает другое значение, элементы управления существующей вкладки отбрасываются и создаются элементы управления новой вкладки, а если TemplateSelector возвращает то же значение, ничего не происходит.

Это именно то, чего я не хочу! Я бы хотел, чтобы TabControl оставил все элементы управления на вкладках, и я хотел бы иметь возможность что-то сделать с созданием различных элементов управления в коде для случая, когда я перехожу с TabTwo на TabThree. Я могу жить без последнего. Но как я могу сказать TabControl не выбрасывать элементы управления каждой вкладки, когда она не выбрана?

1 Ответ

4 голосов
/ 10 февраля 2010

Это функция TabControl и поведение по умолчанию.

По сути, для экономии памяти TabControl выгружает визуальное дерево, которое находится в его области содержимого, и заменяет его вновь созданным для новой вкладки. Чтобы убедиться в этом, вы можете прослушать событие Unload на каждом элементе управления, в котором вы используете шаблон, и заметить, что оно срабатывает каждый раз, когда вы переключаете вкладки.

Существует две причины, по которым вы хотите изменить это поведение:

  1. Вы полагаете, что будет существенное снижение производительности.
  2. Вы теряете состояние элементов управления, потому что любое визуальное состояние, которое теряется, не поддерживается моделью представления.

Что касается # 1 , вас это не должно волновать. Время ЦП, как правило, дешевле, чем ОЗУ, а поведение по умолчанию опирается на более дешевую сторону уравнения ресурсов. Если вы все еще чувствуете, что ДЕЙСТВИТЕЛЬНО не хотите такого поведения, вы можете увидеть пример переопределения здесь: https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Wpf.Example/Controls/NonReloadingTabControl.cs

Однако я бы посчитал это «запахом» для потенциальной проблемы с производительностью в будущем, которую вы должны потратить на выяснение сейчас, а не на задержку с выяснением этого.

Для # 2 у вас есть два варианта:

  1. Убедитесь, что каждое свойство, которое вы хотите сохранить (например, IsSelected и т. Д.), Поддерживается моделью ViewModel, которая сохраняет это состояние.
  2. Создайте постоянный UserControl для каждой вкладки, к которой вы привязываетесь, а не к ViewModels (рабочие области в вашем случае). Вот пример этого в образце «Writer» для WAF: http://waf.codeplex.com/
...