我想突出显示彼此相同的列表项。在这个例子中,我有一个名字和年龄的人物对象,如果那个人在他们两次,我希望它的两个实例都被突出显示。
有一个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系列,我没有办法获得。
我意识到这会被拒绝(评论会很好)但我认为它是因为我没有提供我已经厌倦的东西,问题是我不能说我已经尝试了任何东西,因为在我已经想到的所有方法,我已经遇到了让我无法前进的道路障碍。我认为而不是列出那些无法工作的方式(并且可能无法工作)我想我只想问一下最好的解决方法是什么。
由于
答案 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
中选择第一个“我”后输出和查看。
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输出:
答案 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,因为选择用于其他区域,我没有证明它会出现问题,但似乎它可能会出现。