【问题标题】:Binding {RelativeSource PreviousData} breaks binding in specific case绑定 {RelativeSource PreviousData} 在特定情况下会中断绑定
【发布时间】:2017-08-23 21:31:56
【问题描述】:

我尝试在ListBox.ItemTemplate 中使用{RelativeSource PreviousData},它工作正常。

但是,当使用下面提供的特定代码时,当向上和向下滚动几次并且一些 Rectangles 丢失时绑定停止工作。

即使使用单个 DataTrigger,问题也会重现,但当 ListBox.Height 大于 178 时,它不会重建。

示例 GIF - 缺少绿线!:


MainWindow.Xaml 源代码:

<Window
    x:Class="PreviousDataBindingWheelIssue.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:PreviousDataBindingWheelIssue"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="PreviousData Issue"
    d:DataContext="{d:DesignInstance Type=local:MyModel}"
    SizeToContent="WidthAndHeight"
    mc:Ignorable="d">
    <StackPanel>

        <!--  Height must be less or equal to 178  -->
        <ListBox
            Width="300"
            Height="178"
            HorizontalContentAlignment="Stretch"
            ItemsSource="{Binding MyData}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <DockPanel Background="#FFFFFFED">
                        <Rectangle
                            Height="2"
                            Margin="0"
                            DockPanel.Dock="Top">
                            <Rectangle.Style>
                                <Style TargetType="Rectangle">
                                    <Setter Property="Fill" Value="#FF63605C" />
                                    <Style.Triggers>

                                        <!--
                                            Hide our magnificent separator if this is the first item on the list
                                            see http://stackoverflow.com/a/22705507/426315
                                            but, it seems to have some issues when using mouse wheel
                                            some of the rows does NOT have the rectangle even when PreviousData SHOULD not be null
                                        -->
                                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
                                            <Setter Property="Visibility" Value="Collapsed" />
                                        </DataTrigger>

                                        <DataTrigger Binding="{Binding}" Value="Fun Item">
                                            <Setter Property="Fill" Value="SpringGreen" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Rectangle.Style>
                        </Rectangle>

                        <TextBlock
                            Margin="5,7,5,7"
                            VerticalAlignment="Center"
                            FontSize="12"
                            Text="{Binding}" />
                    </DockPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
</Window>

后面的主窗口代码:

using System.Windows;
namespace PreviousDataBindingWheelIssue
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MyModel();
        }
    }
}

MyModel.cs 来源:

using System.Collections.ObjectModel;

namespace PreviousDataBindingWheelIssue
{
    public class MyModel
    {
        public ObservableCollection<string> MyData { get; set; }

        public MyModel()
        {
            MyData = new ObservableCollection<string>()
            {
                "Lorem ipsum dolor", "sit amet, consectetur", "adipiscing elit. Sed",
                "Fun Item",
                "rhoncus leo convallis", "pulvinar tellus at",
                "Fun Item",
                "porta metus. Mauris", "sed mauris quis", "neque congue semper",
                "Fun Item",
                "vitae non leo", "Donec aliquet feugiat", "massa vitae luctus",
                "Fun Item",
                "Duis pharetra velit", "et lorem blandit"
            };
        }
    }
}

【问题讨论】:

    标签: wpf data-binding relativesource


    【解决方案1】:

    由于PreviousData 绑定与虚拟化不可靠,您可以通过在ListBox 上设置VirtualizingPanel.IsVirtualizing="False" 来禁用虚拟化,或者让您的绑定虚拟化准备就绪。

    处理此类问题的一种方法是创建一个自定义列表框(在我的示例代码中为ListBox2),覆盖PrepareContainerForItemOverride 并设置一些可用于进一步操作的属性。为此,我创建了一个附加属性ItemIndex

    public class ListBox2 : ListBox
    {
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            SetItemIndex(element, ItemContainerGenerator.IndexFromContainer(element));
        }
    
    
        // helper attached property to indicate the index of listbox items
    
        public static int GetItemIndex(DependencyObject obj)
        {
            return (int)obj.GetValue(ItemIndexProperty);
        }
    
        protected static void SetItemIndex(DependencyObject obj, int value)
        {
            obj.SetValue(ItemIndexPropertyKey, value);
        }
    
        private static readonly DependencyPropertyKey ItemIndexPropertyKey =
            DependencyProperty.RegisterAttachedReadOnly("ItemIndex", typeof(int), typeof(ListBox2), new PropertyMetadata(-1));
    
        public static readonly DependencyProperty ItemIndexProperty = ItemIndexPropertyKey.DependencyProperty;
    }
    

    然后将xaml更改为使用ListBox2并依赖ItemIndex而不是PreviousData

    <local:ListBox2
        Width="300"
        Height="178"
        HorizontalContentAlignment="Stretch"
        ItemsSource="{Binding MyData}">
        <local:ListBox2.ItemTemplate>
            <DataTemplate>
                <DockPanel Background="#FFFFFFED">
                    <Rectangle
                        Height="2"
                        Margin="0"
                        DockPanel.Dock="Top">
                        <Rectangle.Style>
                            <Style TargetType="Rectangle">
                                <Setter Property="Fill" Value="#FF63605C" />
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding Path=(local:ListBox2.ItemIndex),RelativeSource={RelativeSource AncestorType=ListBoxItem}}" Value="0">
                                        <Setter Property="Visibility" Value="Collapsed" />
                                    </DataTrigger>
    
                                    <DataTrigger Binding="{Binding}" Value="Fun Item">
                                        <Setter Property="Fill" Value="SpringGreen" />
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </Rectangle.Style>
                    </Rectangle>
    
                    <TextBlock
                        Margin="5,7,5,7"
                        VerticalAlignment="Center"
                        FontSize="12"
                        Text="{Binding}" />
                </DockPanel>
            </DataTemplate>
        </local:ListBox2.ItemTemplate>
    </local:ListBox2>
    

    【讨论】:

    • 谢谢,确实很有趣。能否请您详细说明“PreviousData binding is not可靠与虚拟化”这句话?
    • @itsho 抱歉,这更像是一种实际探索(关闭虚拟化 - 它可以工作,打开它,相关绑定具有不适当的更新触发器并产生错误的值)。我没有找到任何以有用的方式解决此问题的权威来源。
    猜你喜欢
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 2014-12-01
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多