Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WPF, Silverlight Новый топик    Ответить
 Переключение между Tab'ами лагает  [new]
_Novichok
Member

Откуда:
Сообщений: 316
есть TabControl. К нему как источник Tab'ов биндится коллекция навигаторов, которые могут быть нескольких типов, объединенных
одним базовым классом.
+ TabControl
<TabControl x:Name="TabControl"
            Style="{StaticResource TabControlStyle}"
            ItemsSource="{Binding Navigators}">
    <TabControl.Resources>
       
        <DataTemplate DataType="{x:Type vms:NavigatorViewModel}">
            <TextBlock Text="{Binding RootNodeHeader}"/>
        </DataTemplate>     
    </TabControl.Resources>
    
    <TabControl.ContentTemplateSelector>
        <ts:TabContentTemplateSelector 
            PersonsTreeDataTemplate="{StaticResource PersonsNavigatorTemplate}"
            ProjectsTreeDataTemplate="{StaticResource ProjectsNavigatorTemplate}"/>
    </TabControl.ContentTemplateSelector>
</TabControl>

стиль для TabControl'а. В нем переопределяется темплейт с включением кнопки для добавления новых навигаторов.
+ TabControlStyle
<Style x:Key="TabControlStyle" TargetType="{x:Type TabControl}">
    <Setter Property="OverridesDefaultStyle" 
            Value="True"/>
    <Setter Property="SnapsToDevicePixels" 
            Value="True"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabControl}">
                <Grid KeyboardNavigation.TabNavigation="Local">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition x:Name="ColumnDefinition0"/>
                        <ColumnDefinition x:Name="ColumnDefinition1" 
                                          Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>

                    <TabPanel x:Name="HeaderPanel"
                              Grid.Row="0"
                              Panel.ZIndex="1"
                              Margin="2,2,2,0"
                              IsItemsHost="True"
                              KeyboardNavigation.TabIndex="1"
                              Background="Transparent"/>
                    <customControls:DropDownButton Grid.Row="0" 
                                       Grid.Column="1" 
                                       Style="{StaticResource ToogleButtonStyle}" >

                        <StackPanel Orientation="Horizontal" >
                            <TextBlock Text="Add..."/>                            
                            <Separator Width="14" 
                                       Margin="4,0,0,0">
                                <Separator.LayoutTransform>
                                    <RotateTransform Angle="90"/>
                                </Separator.LayoutTransform>
                            </Separator>
                            <TextBlock Text="&#9660;" 
                                       VerticalAlignment="Center" 
                                       Margin="2,0,2,0"/>
                        </StackPanel>
                        <customControls:DropDownButton.DropDown>
                            <ContextMenu>
                                <MenuItem Name="NewProjectNavigatorMenuItem"
                                          Header="New Projects Navigator..."
                                          Command="{Binding NewProjectsNavigatorCommand}"/>
                                <MenuItem Name="NewPersonNavigatorMenuItem"
                                          Header="New Persons Navigator..."
                                          Command="{Binding NewPersonsNavigatorCommand}"/>
                            </ContextMenu>
                        </customControls:DropDownButton.DropDown>
                    </customControls:DropDownButton>

                    <Border Name="ContentPanel"
                            Grid.Column="0"
                            Grid.ColumnSpan="2"
                            Grid.Row="1"
                            Background="{StaticResource WindowBackgroundBrush}"
                            BorderBrush="{StaticResource SolidBorderBrush}"
                            BorderThickness="1"
                            CornerRadius="0,0,7.5,7.5"
                            KeyboardNavigation.TabNavigation="Local"
                            KeyboardNavigation.DirectionalNavigation="Contained"
                            KeyboardNavigation.TabIndex="2">

                        <ContentPresenter Name="PART_SelectedContentHost"
                                          Margin="0"
                                          ContentSource="SelectedContent">
                        </ContentPresenter>
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" 
                             Value="False">
                        <Setter Property="Foreground" 
                                Value="{StaticResource DisabledForegroundBrush}"/>
                        <Setter TargetName="ContentPanel" 
                                Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>    
</Style>


Для каждого типа навигатора для контента вкладки описывается темплейт с деревом внутри.

Теперь суть проблемы: создаю несколько вкладок с разными типами. После переключения между вкладками то состояние, в каком было дерево теряется, то есть, те узлы дерева, которые были развернутые, сворачиваются обратно. И узлы дерева на вкладка принимают один и тот же вид (если это вкладки одинаковых типов).

Вопрос: в чем причина, где копать? Я так подозреваю, что проблема может быть темплейте для TabControla.
4 авг 14, 21:09    [16398514]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
@k@DElpher
Member

Откуда:
Сообщений: 165
_Novichok,

Пока все молчат. Что-то подсказывает, что проблема не в стиле для TabControl'а.
И лучше сначала проверять на минимально проекте. С WPF не работаю, но быстро собрал тестовый вариант с одной ViewModel, без селектора. Действительно при смене табов состояние теряется. А вот если два раза закинуть ссылку на одну ViewModel, то состояние "синхронизируется".

То есть проблема в потере состояния. Судя по всему, там ContentPresenter выкидывает состояние при смене SelectedContent (точнее каждый раз создает новое). С точки зрения MVVM это состояние должно храниться в твоей ViewModel. Тут правда тоже мороки, этот TreeView как-то не очень под MVVM заточен:

+
Там для биндинга выбранных элементов, развернутых элементов нужно использовать переопределение стиля TreeViewItem:

<TreeView>
  <TreeView.ItemContainerStyle>
    <Style TargetType="TreeViewItem">
      <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
      <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
    </Style>
  </TreeView.ItemContainerStyle>
</TreeView>

Sourece: http://stackoverflow.com/questions/9143107/get-selected-treeviewitem-using-mvvm


В гугле поиск: tabcontrol lost state. А вот какое решение верней не знаю)

http://stackoverflow.com/questions/2238072/tabcontrol-disposes-of-controls-on-inactive-tabs
http://stackoverflow.com/questions/2080764/how-to-preserve-control-state-within-tab-items-in-a-tabcontrol
http://stackoverflow.com/questions/22336497/wpf-tabcontrol-tabs-losing-state-information

+

Про минимальный, вроде такого:
   
<TabControl x:Name="tabControl">   
            <TabControl.ContentTemplate>
                <DataTemplate DataType="{x:Type vms:TabItemVM}">
                    <TreeView ItemsSource="{Binding children}">
                        <TreeView.ItemTemplate>
                            <HierarchicalDataTemplate ItemsSource="{Binding children}">
                                <TextBlock Text="{Binding name}"/>
                            </HierarchicalDataTemplate>
                        </TreeView.ItemTemplate>
                    </TreeView>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>



_Novichok
И узлы дерева на вкладка принимают один и тот же вид (если это вкладки одинаковых типов).

Под вопросом этот момент
5 авг 14, 08:19    [16399383]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
@k@DElpher
Member

Откуда:
Сообщений: 165
_Novichok
И узлы дерева на вкладка принимают один и тот же вид (если это вкладки одинаковых типов).

Под вопросом этот момент. У меня такое вышло, не когда одинаковые типы, а когда объекты физически одинаковые (одного типа и ссылаются на один экземпляр)
5 авг 14, 08:22    [16399387]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
_Novichok
Member

Откуда:
Сообщений: 316
@k@DElpher
_Novichok
И узлы дерева на вкладка принимают один и тот же вид (если это вкладки одинаковых типов).

Под вопросом этот момент. У меня такое вышло, не когда одинаковые типы, а когда объекты физически одинаковые (одного типа и ссылаются на один экземпляр)

ну тут не может быть одинаковых экземпляров, поскольку каждый таб - элемент колекции - это отдельный объект, который создается по нажатию кнопкии (с использованием ключевого слова new - насколько я знаю это влечет за собой создание нового экземпляра в памяти), то есть равенство объектов может быть исключено; все поля каждого объекта заполняются из базы данных.

опять же, я не могу предугадать все, что фреймворк должен делать сам, и выносить состояние элемента управления в ViewModel - это даже противоречит концепции MVVM (ViewModel не знает о View, тем более, что ViewModel и View у меня находятся в разных сборках). Когда я программировал на WinForms, то не заботился о таких вещах
5 авг 14, 10:03    [16399636]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
@k@DElpher
Member

Откуда:
Сообщений: 165
_Novichok,

скорее наоборот, View ничего не знает о ViewModel. А вот ViewModel специально снабжается всем, что может понадобиться для View (команды, состояния, SelectedItems и т.д.- всё, что отличает model от ViewModel)
---
Ну вот я у себя пробую, состояние копируется, если объекты дерева одного экземпляра. Если в деревьях разные экземпляры, но одинаковые внутренности (только внешне, то есть поля, текст, структура), то состояние не запоминается.
Может из базы в дерево попадают одинаковые экземпляры (ну там синглетон какой)?
Можно попробовать проверить оператором сравнения или в режиме отладки, добавив переменные с объектом в Watch List и нажав Make Object ID (разные экземпляры пометятся разными номерами)

К сообщению приложен файл. Размер - 13Kb
5 авг 14, 11:01    [16399958]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
@k@DElpher
Member

Откуда:
Сообщений: 165
Я поясню, что это даже не из-за TabControl, а из-за того, что TabControl основан на ContentPresenter. При переключении вкладки его контент меняется и старый уходит для экономии памяти.
Бегло три решения:
Описаные тут (http://stackoverflow.com/questions/2238072/tabcontrol-disposes-of-controls-on-inactive-tabs)
1) Самому хранить то, что нужно
2) Использовать UserControl на каждый таб
и вот третий:
3) http://stackoverflow.com/questions/9794151/stop-tabcontrol-from-recreating-its-children
Предлагают модифицировать TabControl. Вместо ContentPresenter там используют Grid в который запихиваются все табы, а при смене выбранного таба вместо его пересоздания меняется свойство Visibility
5 авг 14, 11:31    [16400096]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
_Novichok
Member

Откуда:
Сообщений: 316
@k@DElpher
скорее наоборот, View ничего не знает о ViewModel.

Я с вами не согласен. ViewModel предоставляет свойтсва, команды, события для привязки их в View.
Соотвественно, ViewModel может использоватсья в разных местах View или в разных View (как собственно, у меня)
5 авг 14, 11:44    [16400202]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
_Novichok
Member

Откуда:
Сообщений: 316
@k@DElpher
Предлагают модифицировать TabControl. Вместо ContentPresenter там используют Grid в который запихиваются все табы, а при смене выбранного таба вместо его пересоздания меняется свойство Visibility

Наверное, этот вариант будет наиболее приемлемым. Попробую. Спасибо
5 авг 14, 11:53    [16400285]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
@k@DElpher
Member

Откуда:
Сообщений: 165
А, об это уже много костылей сломано). Но это дело вкуса.
При чем:
@k@DElpher
View ничего не знает о ViewModel
в разных источниках по разному. Но тут с формулировкой вы правее). С другой стороны, как не крути, по факту, и представление и модель представления пишутся совместно. По научному раздельно, по факту вы за ранее знаете что вам во ViewModel нужен будет SelectedItem, если используется ListBox и IsSelected для каждого элемента, если используется дерево. Кто-то даже умудряется во ViewModel запихать свойства Visibility, потому что не хочется писать биндинги с конвертерами, а ведь можно так и так сделать. И в каждом случае нужно знать на что способен XAML и, что действительно потребуется от ViewModel.

С меня оффтоп).

В общем, не все там в WPF под MVVM заточено хорошо.
5 авг 14, 12:05    [16400391]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
@k@DElpher
Member

Откуда:
Сообщений: 165
_Novichok
@k@DElpher
Предлагают модифицировать TabControl. Вместо ContentPresenter там используют Grid в который запихиваются все табы, а при смене выбранного таба вместо его пересоздания меняется свойство Visibility

Наверное, этот вариант будет наиболее приемлемым. Попробую. Спасибо


Вы только пошарьте еще на тему. На stackoverflow не обязательно универсальное решение.
http://www.codeproject.com/Articles/212233/Persist-the-Visual-Tree-when-switching-tabs-in-the (Вот например, у этого в комментариях пишут про проблемы с TemplateSelector, но там же в комментариях описывают, как это обойти)
http://www.codeproject.com/Articles/362940/Persist-the-Visual-Tree-when-switching-tabs-in-t (Пример выше, но в чем-то оптимизирован)
5 авг 14, 12:13    [16400442]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
_Novichok
Member

Откуда:
Сообщений: 316
@k@DElpher
А, об это уже много костылей сломано). Но это дело вкуса.
При чем:
@k@DElpher
View ничего не знает о ViewModel
в разных источниках по разному. Но тут с формулировкой вы правее). С другой стороны, как не крути, по факту, и представление и модель представления пишутся совместно. По научному раздельно, по факту вы за ранее знаете что вам во ViewModel нужен будет SelectedItem, если используется ListBox и IsSelected для каждого элемента, если используется дерево. Кто-то даже умудряется во ViewModel запихать свойства Visibility, потому что не хочется писать биндинги с конвертерами, а ведь можно так и так сделать. И в каждом случае нужно знать на что способен XAML и, что действительно потребуется от ViewModel.

С меня оффтоп).

В общем, не все там в WPF под MVVM заточено хорошо.

Согласен, в каждом конкретном случае надо вертеть, как получается.
Я просто часто пытаюсь делать универсальнее и с меньшими затратами
5 авг 14, 12:34    [16400602]     Ответить | Цитировать Сообщить модератору
Между сообщениями интервал более 1 года.
 Re: Переключение между Tab'ами лагает  [new]
kariaja
Member

Откуда:
Сообщений: 1
_Novichok, аналогичная проблема. Могу просить совета, как вы решили вопрос потери узлов treeview?
27 мар 16, 13:01    [18983467]     Ответить | Цитировать Сообщить модератору
 Re: Переключение между Tab'ами лагает  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4030
kariaja
_Novichok, аналогичная проблема. Могу просить совета, как вы решили вопрос потери узлов treeview?

нужно просто вынести свойство IsSelected и IsExpanded в модель представления, забиндить через стиль для TreeViewItem эти свойства. За остальное отвечает CollectionView (прокрутка, текущий элемент и т.д.
когда вы открываете там, создается новое визуальное дерево, но коллекция к которой биндится TreeView (ItemSource) находится в ViewModel, для этой коллекции существует CollectionView.
когда вы переключаете вкладку, так как IsExpanded свойство не вынесено из View в ViewModel оно создается по умолчанию со значением False.
27 мар 16, 13:18    [18983479]     Ответить | Цитировать Сообщить модератору
Все форумы / WPF, Silverlight Ответить