Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question]In Nodify.Calculator, the difference between static TabItem and dynamic TabItem in TabControl #161

Open
LaiHT1211 opened this issue Nov 29, 2024 · 2 comments
Assignees
Labels
question Further information is requested

Comments

@LaiHT1211
Copy link

Hi Miroiu.
In the TabControl, static TabItem and dynamic TabItem, when the Tab page is switched, all nodes in the dynamic TabItem seem to be initialized and re-rendered, so it will take more time to complete the Tab page switch (the number of nodes in the test is 150/page, and the more nodes, the more obvious the time difference).
Is this a problem with the processing mechanism of TabControl itself? Can the processing logic of dynamic TabItem switching be the same as that of static TabItem?
Thanks for any replies and suggestions.

Static tab item video
https://github.com/user-attachments/assets/575caa62-49b5-4de5-90bb-0353df32fac9

Dynamic tab item video
https://github.com/user-attachments/assets/28594096-452d-443c-be26-ab9a5456f471

@LaiHT1211 LaiHT1211 added the question Further information is requested label Nov 29, 2024
@LaiHT1211
Copy link
Author

LaiHT1211 commented Nov 30, 2024

I missed some information, the supplement to this question is as follows.

Static tab item code:

<shared:TabControlEx>
    <shared:TabControlEx.ItemContainerStyle>
        <Style BasedOn="{StaticResource {x:Type shared:TabItemEx}}"
            TargetType="{x:Type shared:TabItemEx}">
            <Setter Property="Header" Value="{Binding Name}" />
            <Setter Property="CloseTabCommand"
                Value="{Binding DataContext.CloseEditorCommand, Source={StaticResource Proxy}}" />
            <Setter Property="CloseTabCommandParameter" Value="{Binding Id}" />
        </Style>
    </shared:TabControlEx.ItemContainerStyle>
    <shared:TabItemEx Header="EditorView 1">
        <local:EditorView DataContext="{Binding EditorViewModel1}" />
    </shared:TabItemEx>
    <shared:TabItemEx Header="EditorView 2">
        <local:EditorView DataContext="{Binding EditorViewModel2}" />
    </shared:TabItemEx>
</shared:TabControlEx>

Dynamic tab item code:

<shared:TabControlEx
    AddTabCommand="{Binding AddEditorCommand}"
    AutoScrollToEnd="{Binding AutoSelectNewEditor}"
    ItemsSource="{Binding Editors}"
    SelectedItem="{Binding SelectedEditor}">
    <shared:TabControlEx.ItemContainerStyle>
        <Style BasedOn="{StaticResource {x:Type shared:TabItemEx}}"
            TargetType="{x:Type shared:TabItemEx}">
            <Setter Property="Header" Value="{Binding Name}" />
            <Setter Property="CloseTabCommand"
                Value="{Binding DataContext.CloseEditorCommand, Source={StaticResource Proxy}}" />
            <Setter Property="CloseTabCommandParameter" Value="{Binding Id}" />
        </Style>
    </shared:TabControlEx.ItemContainerStyle>
</shared:TabControlEx>

@miroiu
Copy link
Owner

miroiu commented Dec 2, 2024

Hi @LaiHT1211 , this is a known issue with the default TabControl implementation. When binding to the ItemsSource property, the TabControl discards visuals for unselected tabs, causing them to be rebuilt entirely when re-selected. This can be costly, especially for complex templates.

The linked article provides an excellent explanation and a potential solution: https://groups.google.com/g/wpf-disciples/c/bzUxoXICUt0

Key points from the article:

Unfortunately, if you're using a typical MVVM approach with a binding on the ItemsSource property of the TabControl, the entire tree must be rebuilt each time a tab item is selected. This is usually a very expensive operation.

The discarding of items is really only a problem when using a TabControl in ItemsSource mode. In Direct mode, the visuals will still be unloaded from the tree, but they won't be discarded.

However, the performance hit may also be caused by the complexity of the DataTemplate of the node, but that's only for the initial load. Try replacing the DataTemplate with a simple control like this to see the difference:

<DataTemplate DataType="{x:Type local:ExpandoOperationViewModel}">
    <TextBlock Text="This is a node" />
</DataTemplate>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants