WPF突出显示列表框中的重复项目

时间:2014-08-05 21:00:16

标签: c# wpf binding listbox

我想突出显示彼此相同的列表项。在这个例子中,我有一个名字和年龄的人物对象,如果那个人在他们两次,我希望它的两个实例都被突出显示。

有一个ObservableCollection,People包含一个Person对象列表。

XAML方

<StackPanel>
    <TextBlock>Name</TextBlock>
    <TextBox Text="{Binding CurrentPerson, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
    <Button Command="{Binding AddPersonDelegateCommand}">Add</Button>
    <Button>Remove</Button>
    <ListBox x:Name="list" ItemsSource="{Binding People}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedPerson}">

    </ListBox>
    <TextBox Name="txtName" Text="{Binding SelectedPerson.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"</TextBox>
    <TextBox Name="txtAge" Text="{Binding SelectedPerson.Age, Mode=TwoWay}"></TextBox>
</StackPanel>

我怎样才能有效地做到这一点?

我考虑过使用ItemContainerStyle,但是那里的绑定似乎引用了DataContext而不是listboxitem本身。

我认为我可以使用的另一种方法是带有文本框的数据模板,使用转换器和多个绑定绑定到背景(将使用params,但它们不可绑定),如果找到重复,则返回Red。在这种情况下,我需要找到两个重复项,因为它会遇到它,或者在值相等时进行引用比较。我对这种方法的问题是能够访问集合本身(与最后一个想法相反的问题)

另一个想法是在代码端拥有一切,并创建一个属性IsDup或类似的东西,但我再次遇到类似的问题,因为当Name或Age值更改时,从Person i的那个实例#39; d必须看看People系列,我没有办法获得。

我意识到这会被拒绝(评论会很好)但我认为它是因为我没有提供我已经厌倦的东西,问题是我不能说我已经尝试了任何东西,因为在我已经想到的所有方法,我已经遇到了让我无法前进的道路障碍。我认为而不是列出那些无法工作的方式(并且可能无法工作)我想我只想问一下最好的解决方法是什么。

由于

2 个答案:

答案 0 :(得分:1)

您使用ItemContainerStyle走在了正确的道路上。希望您在INotifyPropertyChanged上实施Person,以便选择Person通知用户界面。无论如何,看看这个简短的代码示例,它是相当不言自明的:

MainWindow.xaml

<ListBox ItemsSource="{Binding People}"
            DisplayMemberPath="Header"
            HorizontalAlignment="Center">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="IsSelected"
                    Value="{Binding IsSelected}" />
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

MainWindow.xaml.cs

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private Person _selectedPerson;
    public Person SelectedPerson
    {
        get
        {
            return this._selectedPerson;
        }
        set
        {
            this._selectedPerson = value;
            NotifyPropertyChanged("SelectedPerson");
        }
    }


    ObservableCollection<Person> _people = new ObservableCollection<Person>();
    public ObservableCollection<Person> People
    {
        get
        {
            return this._people;
        }
    }

    public MainWindow()
    {
        var guy = new Person("Me");
        this.People.Add(guy);      // <---- ADDED GUY ONCE
        this.People.Add(new Person("You"));
        this.People.Add(new Person("Us"));
        this.People.Add(guy);     // <----- SAME GUY ADDED
        this.SelectedPerson = this.People[0];

        InitializeComponent();

        this.DataContext = this;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

Person.cs

public class Person : ViewModel
{
    public string Header { get; set; }

    private bool _isSelected;
    public bool IsSelected
    {
        get
        {
            return _isSelected;
        }
        set
        {
            _isSelected = value;
            this.NotifyPropertyChanged("IsSelected");
        }
    }
    public Person(string n)
    {
        Header = n;
    }
}

ViewModel.cs

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

ListBox中选择第一个“我”后输出和查看。

Output

Bonus Snippet,更改控件模板,然后更改项目+所选项目的外观:

<ListBox ItemsSource="{Binding People}"
            DisplayMemberPath="Header"
            SelectionMode="Multiple"
            HorizontalAlignment="Center">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="IsSelected"
                    Value="{Binding IsSelected}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Border x:Name="Bd"
                                Width="100"
                                Height="40"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="Orange"
                                Padding="{TemplateBinding Padding}"
                                SnapsToDevicePixels="True"
                                Margin="0 2">
                            <Grid>
                                <TextBlock Text="{Binding Header}" />
                                <Path x:Name="checkmark"
                                        Width="11"
                                        Height="11"
                                        Margin="0 5 5 0"
                                        HorizontalAlignment="Right"
                                        VerticalAlignment="Top"
                                        SnapsToDevicePixels="False"
                                        Stroke="Black"
                                        StrokeThickness="2"
                                        Data="M 2,4 C 2,4 3,5 5,13 C 5,13 5,3 12,0"
                                        Visibility="Hidden" />
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsSelected"
                                        Value="True">
                                <Setter Property="Visibility"
                                        TargetName="checkmark"
                                        Value="Visible" />
                                <Setter Property="Background"
                                        TargetName="Bd"
                                        Value="Green" />
                            </Trigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected"
                                                Value="True" />
                                    <Condition Property="Selector.IsSelectionActive"
                                                Value="False" />
                                </MultiTrigger.Conditions>
                                <Setter Property="Background"
                                        TargetName="Bd"
                                        Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}" />
                                <Setter Property="Foreground"
                                        Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}" />
                            </MultiTrigger>
                            <Trigger Property="IsEnabled"
                                        Value="False">
                                <Setter Property="Foreground"
                                        Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

使用Bonus XAML输出:

enter image description here

答案 1 :(得分:0)

我在Observable集合中的对象上放置一个Event,以便在重要属性发生更改时触发。

该事件已在viewmodel上注册,并运行以下方法以确定它是否为dup。

 public void TagDup(ProductConnection selectedProductConnection)
    {
        selectedProductConnection.IsDup = false;

        //check to see if the 'current' item is a dup with anything in the list
        ProductConnections.Where(o => !ReferenceEquals(o, selectedProductConnection) && o.GetDupHash() == selectedProductConnection.GetDupHash()).ToList().ForEach(o => o.IsDup = selectedProductConnection.IsDup = true);
        //look for orphaned dup tags
        var grp = ProductConnections.Where(o => o.IsDup).GroupBy(o => o.GetDupHash()).Where(o => o.Count() == 1).ToList();
        ProductConnections.Where(x => grp.Select(a => a.Key).Contains(x.GetDupHash())).ToList().ForEach(o => o.IsDup = false);
    }

然后在XAML方面我使用了ItemContainerStyle和一个转换器

 <ListBox.ItemContainerStyle>
     <Style TargetType="ListBoxItem">
          <Setter Property="Foreground" Value="{Binding IsDup, Converter={StaticResource BooleanToColor}}"></Setter>
     </Style>
 </ListBox.ItemContainerStyle>

我避免使用IsSelected,因为选择用于其他区域,我没有证明它会出现问题,但似乎它可能会出现。