bretik
bretik

Reputation: 727

WPF - Weird scrollbars behavior in TabItem

I have following code:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="145" Width="156">
    <Window.Resources>
        <DataTemplate x:Key="tabTemplate">
            <ScrollViewer>
                <StackPanel Orientation="Vertical">
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                    <TextBlock>x</TextBlock>
                </StackPanel>
            </ScrollViewer>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <TabControl>
            <TabItem Header="Tab1" ContentTemplate="{StaticResource ResourceKey=tabTemplate}"/>
            <TabItem Header="Tab2" ContentTemplate="{StaticResource ResourceKey=tabTemplate}"/>
        </TabControl>
    </Grid>
</Window>

What is weird is the behavior of scrollbars - if I scroll down on the first tab and switch to second tab, the scrollbar is down too - position of the scrollbars is synchronized when the tab items have the same data templates. Do you know about any solution of this issue?

In addition, when I alter the code and make two data templates (one for each tab), the scrollbars are not preserving their position at all - that means if I scroll down on tab1, switch to tab2 and to tab1 again, the scrollbar is on default position. Any solution of this one?

Upvotes: 1

Views: 1927

Answers (2)

bretik
bretik

Reputation: 727

I solved the second issue using new control ZoomPanel : ScrollViewer, where the position of scollbars is saved according to DataContext.GetHashCode(). Maybe not optimal solution, but works for me. Every tab has its own ViewModel, so the position of scrollbars is preserved.

public static readonly Dictionary<int, Point> ScrollbarPositions = new Dictionary<int, Point>();

private void ZoomPanelScrollChanged(object sender, ScrollChangedEventArgs e)
{
    ZoomPanel panel = (ZoomPanel)sender;

    // do not save position when uloading or empty data context
    if(!panel.IsLoaded || this.DataContext == null)
    {
        return;
    }

    // save scrollbar position
    int dataContextHashCode = this.DataContext.GetHashCode();
    Point position = new Point(panel.HorizontalOffset, panel.VerticalOffset);

    if(ScrollbarPositions.ContainsKey(dataContextHashCode))
    {
        ScrollbarPositions[dataContextHashCode] = position;
    }
    else
    {
        ScrollbarPositions.Add(dataContextHashCode, position);
    }
}

private void ZoomPanelLoaded(object sender, RoutedEventArgs e)
{
    if(this.DataContext == null)
    {
        return;
    }

    // load scrollbar position
    int dataContextHashCode = this.DataContext.GetHashCode();
    if (ScrollbarPositions.ContainsKey(dataContextHashCode))
    {
        Point position = ScrollbarPositions[dataContextHashCode];
        this.ScrollToHorizontalOffset(position.X);
        this.ScrollToVerticalOffset(position.Y);
    }
}

Upvotes: 1

robertos
robertos

Reputation: 1796

To enable the DataTemplate to create separate instances for each usage, just set the x:Shared attribute to False:

<DataTemplate x:Key="tabTemplate" x:Shared="False">

That will cause your second issue, which is preserving the UI when the tab changes. According to WPF UI persistence in TabControl, the solution would be to use a different ItemsControl that looks like a TabControl.

Upvotes: 3

Related Questions