【问题标题】:How to invalidate layout of listbox from custom children如何使自定义子项的列表框布局无效
【发布时间】:2010-03-22 06:06:21
【问题描述】:

我有一个用于列表框的自定义面板

<ItemsPanelTemplate x:Key="FloatPanelTemplate">
    <Controls:FloatPanel x:Name="CardPanel" />
</ItemsPanelTemplate>

面板使用其 X 和 Y 依赖属性来布置其子级。 当 FloatPanel 单独使用时,这一切都很好 - 我正在使用 FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure 对子项的依赖属性进行测量,以告知 FloatPanel 重绘其布局。

当我在列表框(上面的代码)中使用它时,它第一次画得很好,但是当我拖动子项(修改项目的 X 和 Y)时,它没有通知列表框它需要重绘 FloatPanel 的孩子们。我认为这个问题与绑定集合中的每个项目都用 ListBoxItem 包装的事实有关。

希望我已经描述了我做得很好,有人可以告诉我如何让面板(或其子面板)告诉它需要再次执行布局例程。正如我所说,它工作一次(初始绘制),但随后拖动项目不起作用(列表框不知道其子项已更改并需要重新布局。)如果我拖动一个项目然后调整窗口大小,列表框会进行布局和这些项目被绘制在它们的新位置。

如何通知 ListBox(或更重要的是 ItemsPanelTemplate 中的 FloatPanel)它需要进行布局传递?

【问题讨论】:

    标签: wpf wpf-controls


    【解决方案1】:

    改为尝试 FrameworkPropertyMetadataOptions.AffectsParentMeasure 和 FrameworkPropertyMetadataOptions.AffectsParentArrange。

    那些名字...感谢上帝的智能,嗯?

    正如您所指出的,由于 ListBoxItem 是您元素的直接布局父级,因此对影响父级布局的依赖属性的更改将不会被位于可视树上方的面板“看到”。

    因此,不幸的是,您可能需要做的是遍历可视化树,直到找到派生自 Panel 的元素并调用其 InvalidateArrange 方法。

    DependencyObject obj=this;
    while ( (obj=VisualTreeHelper.GetParent(obj)) != null) {
        Panel p = obj as Panel;
        if (p != null) {
            p.InvalidateArrange();
            break;
        }
    }
    

    这很难看,但也许 WPF 大师会有更好的建议。

    【讨论】:

    • 忘了说我已经尝试过了,但没有成功。 FloatPanel 似乎不是 ListBoxItems 内 FloatElements 的父级。
    • 确实如此,但我想知道为什么它甚至在第一个布局通道中也能工作,因为 ListBoxItem 容器将始终位于您的面板和项目本身之间。
    • 好点。作为测试,我放了一个 cardPanel.InvalidateVisual();在 ItemPanelTemplate 中卡片面板的 mousemove 事件上,当我拖动项目时它会正确重绘面板。所以这不是 Panel 绘制不正确的问题,而是孩子没有通知 ListBox 它已更改的问题。
    • 我认为您可能是对的,因为 ListBoxItem 是您的直接布局父级,依赖属性更改不会触发祖先元素中的布局。我会用另一个建议更新我的答案。
    • 我也尝试获取依赖对象的父对象。它是空的,所以没有工作。刚刚尝试设置父级,但 Parent 属性没有设置器。也许我需要向我的 FloatElement(我放入 FloatPanel 的子类型)添加一个属性,以便稍后再使用?
    【解决方案2】:

    您确定您的ListBoxListView 面板似乎没有显示不正确的尺寸,因为它有...

    ScrollViewer.CanContentScroll="True"
    

    ...哪个是默认值?

    当列表控件处于此模式时,当它滚动到底部时,其面板的底部可能会有额外的空白,以确保一个完整的项目排列整齐在其内部ScrollViewer顶部,这可能看起来像ScrollViewer--因此列表控件--不会自行调整大小。

    要防止面板底部出现空白,您必须在 ListBox 或 ListView 控件上启用像素级滚动:

    ScrollViewer.CanContentScroll="False"
    

    或在代码中:

    ScrollViewer.SetCanContentScroll(list_ctrl, false);
    

    另请参阅:WPF ListView non integral scrolling

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      相关资源
      最近更新 更多