WPF - TabItem中奇怪的滚动条行为

时间:2010-10-27 10:00:04

标签: wpf xaml datatemplate tabcontrol scrollviewer

我有以下代码:

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

滚动条的行为是多么奇怪 - 如果我向下滚动第一个选项卡并切换到第二个选项卡,滚动条也会关闭 - 当选项卡项具有相同的数据模板时,滚动条的位置会同步。你知道这个问题的任何解决方案吗?

此外,当我更改代码并制作两个数据模板(每个选项卡一个)时,滚动条根本不保留它们的位置 - 这意味着如果我向下滚动tab1,再次切换到tab2和tab1,滚动条位于默认位置。这个的任何解决方案?

2 个答案:

答案 0 :(得分:3)

要让DataTemplate为每次使用创建单独的实例,只需将x:Shared属性设置为False

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

这将导致您的第二个问题,即在选项卡更改时保留UI。根据{{​​3}},解决方案是使用看起来像ItemsControl的其他TabControl

答案 1 :(得分:1)

我使用新控件ZoomPanel : ScrollViewer解决了第二个问题,其中根据DataContext.GetHashCode()保存了scollbar的位置。也许不是最佳解决方案,但对我有用。每个选项卡都有自己的ViewModel,因此保留滚动条的位置。

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);
    }
}