WPF ListBox在更改Style时保留SelectedItem上的视图

时间:2010-08-12 01:54:44

标签: c# wpf listbox styles

我有一个ListBox,其Style和ItemTemplate在点击特定按钮时在代码隐藏中更改。

listbox.ItemTemplate = FindResource("dataTemplateView1") as DataTemplate;
listbox.Style = FindResource("listBoxStyle1") as Style;

有三种可能的视图,因此有三组数据模板和样式。 DataTemplate包含一些文本和缩略图(每组不同的大小)。样式只是将ItemsPanelTemplate更改为WrapPanel,StackPanel(水平)和StackPanel(垂直)。例如:

<Style x:Key="listBoxStyle1" TargetType={x:Type ListBox}">
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
               <WrapPanel />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>

问题在于,当我有一个选定的项目(比如索引为20的项目)并且我更改了视图时,显示的列表框的可见区域将重置回第一个索引(但是所选项目仍然被选中,只是没有显示)。

我尝试使用解决方案here来解决此问题,以滚动到所选项目并将其设置为居中。但目前,有时候行为似乎不稳定,因为发生的事情是列表框中的第一项首先显示然后跳转到所选项目。还有其他选择吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

您所寻找的内容与我在之前的回答中所写的内容并无太大差异。

两个不同之处是:

  1. 您的目标似乎是保持当前项目不移动,而不是让它移动到中心。这实际上是可行的,就像集中它一样容易。
  2. 代码的时间允许暂时显示未滚动的版本,导致跳跃。
  3. 这两个问题可以一起解决如下(参考我之前对相关代码细节的回答):

    1. 使用box.ItemContainerGenerator.ContainerFromItem(box.SelectedItem)获取商品容器
    2. 调用container.TransformToAncestor(box).Transform(new Point())以获取容器相对于列表框的左上角。 (如果您希望将项目的中心保持静止,请改用new Point(container.DesiredSize.Width/2, container.DesiredSize.Height/2)。)
    3. 根据需要更改ItemTemplate或Style
    4. 强制立即重新测量(通过调用UpdateLayout来实现此目的的简便方法)
    5. 再次使用box.ItemContainerGenerator.ContainerFromItem(box.SelectedItem)获取商品容器
    6. 再次致电container.TransformToAncestor(box).Transform(new Point())以获取新容器相对于列表框的左上角
    7. 使用我的其他答案中的代码查找IScrollInfo并更新Horizo​​ntalOffset和VerticalOffset以将新容器带到与旧容器相同的位置。
    8. 这将在没有闪烁的情况下工作的原因是这里的所有内容都是同步发生的,因此Render优先级的调度程序操作不会运行。成本是UpdateLayout()相对昂贵。

      另请注意,如果您的任何单个项目已实施,以便在初始测量/安排后更改其大小(例如在调度程序回调中),那么您将需要重新定位两次:一旦进入同步代码,则再次在调度员回调中。在这种情况下,我知道防止闪烁的唯一可靠的通用方法是修复项目的实现,以便在初始布局完成之前获得它们的大小。

答案 1 :(得分:0)

这是一个品味问题,但我会触发淡出和淡入动画大概.15或.2秒,并在模板切换淡出时进行。这将隐藏滚动并平滑布局中非常突然的切换。