2010-10-27 55 views
0
奇怪的滚动条行为

我有以下代码:WPF - 在TabItem的

<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

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

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

这将导致你的第二个问题,这是保存UI的标签更改时。根据WPF UI persistence in TabControl,解决方案将使用看起来像TabControl的不同ItemsControl

+0

第一个问题的作品,使用ItemsControl似乎不是我的项目的一个很好的解决方案。但是失去位置并不像滚动条的位置那么古怪,所以我接受这个解决方案。 – bretik 2010-11-01 08:00:09

1

我使用新控件ZoomPanel : ScrollViewer解决了第二个问题,其中根据DataContext.GetHashCode()保存了scollbars的位置。也许不是最佳的解决方案,但为我工作。每个选项卡都有自己的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); 
    } 
} 
+1

请注意,GetHashCode不保证是唯一的。最安全的方法是在您的ViewModel上添加一个唯一的ID属性,或者使用控件中的索引保存滚动条位置。 – robertos 2010-11-03 08:31:26

+0

使用索引不是我的选择,因为我需要从内部控件中确定选项卡索引。这种方法的下一个问题是可以通过关闭并重新打开选项卡来更改选项卡索引。这不是代码的重要组成部分,只是增强了GUI,所以我愿意冒哈希代码风险。哈希代码的好点 - 很好的评论。 – bretik 2010-11-03 09:22:43