代码之家  ›  专栏  ›  技术社区  ›  bretik

wpf-tabitem中奇怪的滚动条行为

  •  1
  • bretik  · 技术社区  · 14 年前

    我有以下代码:

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

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

    此外,当我修改代码并制作两个数据模板(每个选项卡一个)时,滚动条根本不保留它们的位置-这意味着如果我向下滚动选项卡1,切换到选项卡2并再次切换到选项卡1,滚动条将处于默认位置。这个有什么解决办法吗?

    2 回复  |  直到 14 年前
        1
  •  3
  •   Community CDub    8 年前

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

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

    这将导致第二个问题,即选项卡更改时保留用户界面。根据 WPF UI persistence in TabControl 解决方法是使用不同的 ItemsControl 看起来像 TabControl .

        2
  •  1
  •   bretik    14 年前

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

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