WPF ListBox 模板绑定仅在滚动时更新

Posted

技术标签:

【中文标题】WPF ListBox 模板绑定仅在滚动时更新【英文标题】:WPF ListBox Template bindings update only on scrolling 【发布时间】:2016-08-20 20:59:10 【问题描述】:

我有以下 ListBox,其中 ContentControl 作为 DataTemplate:

<ListBox x:Name="lstActionConfigs" ItemsSource="Binding Path=AllActionConfigList" SelectedItem="Binding Path=ListSelectedItem, Mode=TwoWay" HorizontalContentAlignment="Stretch" Grid.Row="3" Margin="0,0,0,5">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="x:Type helper:ItemDetails">
            <ContentControl Template="StaticResource ResourceKey=actionDetailsListItemTemplate" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <i:Interaction.Behaviors>
                    <behaviours:BringIntoViewBehaviour CustomIsSelected="Binding Path=IsSelected, Mode=TwoWay"/>
                </i:Interaction.Behaviors>
            </ContentControl>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

每个有界实例都有 'IsSelected' 属性,通过INotifyPropertyChanged 通知 UI 更改:

public bool IsSelected

    get  return isSelected; 
    set
    
        isSelected = value;
        notify("IsSelected");
    

我构建了一个自定义行为,可以查看将其 IsSelectedProperty 更改为 true 的元素,如下所示:

public class BringIntoViewBehaviour : Behavior<FrameworkElement>

    public bool CustomIsSelected
    
        get  return (bool)GetValue(CustomIsSelectedProperty); 
        set  SetValue(CustomIsSelectedProperty, value); 
    
    public static readonly DependencyProperty CustomIsSelectedProperty =
            DependencyProperty.Register("CustomIsSelected", typeof(bool), typeof(BringIntoViewBehaviour), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(customIsSelectedPropertyChanged_Callback)));

    private static void customIsSelectedPropertyChanged_Callback(DependencyObject o, DependencyPropertyChangedEventArgs e)
    
        BringIntoViewBehaviour thisControl = o as BringIntoViewBehaviour;

        if (thisControl == null)
            return;

        bringIntoView(thisControl);
    

此项目目前不在 UI 上显示,因为它位于列表底部(有一个滚动条)。

我用true 值更新了IsSelected 属性。

然而,customIsSelectedPropertyChanged_Callback 方法应该在我们更新它的有界属性时执行。

但是,实际上,只有在将滚动条向下移动到 UI 上显示该项目时,才会调用此方法。

【问题讨论】:

【参考方案1】:

最有可能的原因是 UI 虚拟化。 ListBox 项目主机默认为 VirtualizingStackPanel。它不会生成现在看不见的项目,因此当您在模型上设置 IsSelected 时,您的 DataTemplate 以及您的行为尚未创建。只有当您向下滚动时,才会与数据模板中的行为一起创建控件,并在绑定后将CustomIsSelectedProperty 设置为true,因此会调用您的回调。

要验证此假设,您可以为您的 ListBox 禁用 UI 虚拟化,看看是否可以解决问题。

【讨论】:

我禁用了 UI 可视化,正如你所说的 ,现在它可以完美运行了。非常感谢! 不客气。确保您了解禁用虚拟化的含义,尤其是当您期望该 ListBox 中有很多项目时。

以上是关于WPF ListBox 模板绑定仅在滚动时更新的主要内容,如果未能解决你的问题,请参考以下文章

WPF中ListBox滚动时的缓动效果

WPF ListBox 未使用 ItemsSource 更新

强制数据绑定 WPF ListBox 更新的更好方法?

WPF ListBox/ListView/DataGrid 列表滚动与虚拟化

2022-03-23 WPF面试题 ListBox 与 ListView - 如何选择以及何时进行数据绑定?

2022-03-23 WPF面试题 ListBox 与 ListView - 如何选择以及何时进行数据绑定?