我已经创建了一个包含项目列表的列表框,我需要在选择更改(选择和取消选择)时绑定它们。
ABCD.xalm
<ListBox Grid.Column="2" Grid.ColumnSpan="9" Height="30" Margin="0 0 5 0" Foreground="{StaticResource AcresTheme}" SelectedItem="{Binding Path=UpdateSimulationItem,UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding SmulationTypes, NotifyOnSourceUpdated=True}"
Background="{Binding }"
MinHeight="65" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Foreground="{StaticResource AcresTheme}"
Content="{Binding Item}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"></CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
ABCD.cs (视图模型)
public List<string> SimulationTypesList { get; set; } = new List<string>();
private ObservableCollection<SimulationType> _simulationTypes = new ObservableCollection<SimulationType>();
public ObservableCollection<Items> SimulationTypes
{
get
{
return _simulationTypes;
}
set
{
_simulationTypes = value;
OnPropertyChanged("SimulationTypes");
}
}
private Items _updateSimulationItem;
public Items UpdateSimulationItem
{
get
{
return _updateSimulationItem;
}
set
{
//Logic for getting the selected item
_updateSimulationItem = value;
OnPropertyChanged("UpdateSimulationItem");
}
}
public ABCD()
{
SimulationTypes.Add(new SimulationType() { Item = "Simulation 1", IsSelected = false });
SimulationTypes.Add(new SimulationType() { Item = "Simulation 2", IsSelected = false });
SimulationTypes.Add(new SimulationType() { Item = "Simulation 3", IsSelected = false });
}
Items.cs
public class Items: ViewModelBase
{
private string item;
public string Item
{
get { return item; }
set
{
item = value;
this.OnPropertyChanged("Item");
}
}
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set
{
isSelected = value;
this.OnPropertyChanged("IsSelected");
}
}
}
我确实尝试了在https://stackoverflow.com/a/34632944/12020323中给出的解决方案,这对于删除单个项或选择单个项都很有效。
当我们选择第二项时,它不会触发属性更改。
发布于 2022-11-10 08:33:27
@EldHasp,谢谢你花时间回答我的问题。对所提供的解决方案非常满意。
目前,我非常热衷于在ViewModel中使用完整的代码,我发现了我在ViewModel中所犯的错误。
旧法典:
private ObservableCollection<SimulationType> _simulationTypes = new ObservableCollection<SimulationType>();
public ObservableCollection<Items> SimulationTypes
{
get
{
return _simulationTypes;
}
set
{
_simulationTypes = value;
OnPropertyChanged("SimulationTypes");
}
}
private Items _updateSimulationItem;
public Items UpdateSimulationItem
{
get
{
return _updateSimulationItem;
}
set
{
//Logic for getting the selected item
_updateSimulationItem = value;
OnPropertyChanged("UpdateSimulationItem");
}
}
_updateSimulationItem =;将第一个选定的项绑定到UpdateSimulationItem,属性更改仅在更改该perticular项时才会触发。
例如:
SimulationTypes.Add(新项目=“模拟1",IsSelected =假};SimulationTypes.Add(新SimulationType() { SimulationType() =”模拟2",IsSelected =假});SimulationTypes.Add(新SimulationType() {项目=“模拟3",IsSelected = false });
在这三个项目中,如果我选择模拟1,那么UpdateSimulationItem将绑定到模拟1,属性的变化将缩小到一个项目,即模拟1。现在如果我们点击仿真2,那么peopertychange将不会触发,因为UpdateSimulationItem仅绑定到模拟1项更改。
我所做的改变。
更新代码:
private Items _updateSimulationItem;
public Items UpdateSimulationItem
{
get
{
return _updateSimulationItem;
}
set
{
//Removed unnecessary code and the assignment of value to _updateSimulationItem
OnPropertyChanged("UpdateSimulationItem");
}
}
我们已经将SimulationTypes绑定到ABC.XAML中的ItemSource中,如下所示
<ListBox Foreground="{StaticResource AcresTheme}"
SelectedItem="{Binding Path=UpdateSimulationItem,UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding SimulationTypes, NotifyOnSourceUpdated=True}"
MinHeight="65" SelectionMode="Multiple">
当我单击视图中的复选框时,它将自动将SimulationTypes绑定到IsSelected。
<CheckBox Foreground="{StaticResource AcresTheme}"
Content="{Binding Item}"
IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
@EldHasp我们在代码中必须做的代码更改是将赋值移除给setter属性中的OnPropertychange(nameOf(SelectedItem)).,只保留
公共物品?SelectedItem { get => _selectedItem;set => Set(ref _selectedItem,value); }粗体文本使=>绑定到一个项,这将在选择其他项时限制触发器。
再次感谢 @EldHasp在这方面花费了你的时间。
发布于 2022-11-02 17:39:53
错误不在此代码中。您可能对VM实例感到困惑。这通常是初学者的情况。SimulationType的实现可能有问题。你没表现出来。
下面是一个完整的代码示例,演示多选择绑定正确工作。
using Simplified;
using System;
using System.Collections.ObjectModel;
namespace Core2022.SO.ChaithanyaS
{
public class Item : ViewModelBase
{
private string _title = string.Empty;
public string Title
{
get => _title;
set => Set(ref _title, value ?? string.Empty);
}
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set => Set(ref _isSelected, value);
}
}
public class SimulationType : Item
{
private int _count;
public int Count { get => _count; set => Set(ref _count, value); }
}
public class ItemsViewModel : ViewModelBase
{
private static readonly Random random = new Random();
private Item? _selectedItem;
public ObservableCollection<Item> Items { get; } =
new ObservableCollection<Item>()
{
new Item() {Title = "First" },
new SimulationType() { Title = "Yield Simulation", Count = random.Next(5, 15) },
new Item() {Title = "Second" },
new SimulationType() { Title = "HLR Simulation", Count = random.Next(5, 15) },
new SimulationType() { Title = "UnCorr HLR Simulation", Count = random.Next(5, 15)},
new Item() {Title = "Third" }
};
public Item? SelectedItem { get => _selectedItem; set => Set(ref _selectedItem, value); }
}
}
<Window x:Class="Core2022.SO.ChaithanyaS.ItemsWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Core2022.SO.ChaithanyaS"
mc:Ignorable="d"
Title="ItemsWindow" Height="450" Width="800">
<Window.DataContext>
<local:ItemsViewModel/>
</Window.DataContext>
<UniformGrid Columns="2">
<ListBox Margin="10"
SelectedItem="{Binding SelectedItem}"
ItemsSource="{Binding Items}"
SelectionMode="Multiple">
<FrameworkElement.Resources>
<DataTemplate DataType="{x:Type local:Item}">
<CheckBox Foreground="Red"
Content="{Binding Title}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:SimulationType}">
<CheckBox Foreground="Green"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path="Title"/>
<Binding Path="Count"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</CheckBox>
</DataTemplate>
</FrameworkElement.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<ItemsControl ItemsSource="{Binding Items}" Margin="10"
BorderBrush="Green" BorderThickness="1"
Padding="10">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:Item}">
<DataTemplate.Resources>
<DataTemplate DataType="{x:Type local:Item}">
<TextBlock Foreground="Red"
Text="{Binding Title}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:SimulationType}">
<TextBlock Foreground="Green">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path="Title"/>
<Binding Path="Count"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</DataTemplate.Resources>
<Label x:Name="cc" Content="{Binding}" Margin="1" BorderBrush="Gray" BorderThickness="1"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter TargetName="cc" Property="Background" Value="LightPink"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UniformGrid>
</Window>
也许您的意思是,在多选择模式下,SelectedItem属性始终只有首先选定的项,直到取消选中为止?
不幸的是,这样一项任务的执行并不容易。最好是创建一个自定义AP属性,然后在XAML中使用它。
public static class MuliSelectorHelper
{
/// <summary>Returns the value of the IsSelectedItemLast attached property for <paramref name="multiSelector"/>.</summary>
/// <param name="multiSelector"><see cref="DependencyObject"/> whose property value will be returned.</param>
/// <returns><see cref="bool"/> property value.</returns>
public static bool GetIsSelectedItemLast(DependencyObject multiSelector)
{
return (bool)multiSelector.GetValue(IsSelectedItemLastProperty);
}
/// <summary>Sets the value of the IsSelectedItemLast attached property for <paramref name="multiSelector"/>.</summary>
/// <param name="multiSelector"><see cref="MultiSelector"/> whose property value will be returned.</param>
/// <param name="value"><see cref="bool"/> value for property.</param>
public static void SetIsSelectedItemLast(DependencyObject multiSelector, bool value)
{
multiSelector.SetValue(IsSelectedItemLastProperty, value);
}
/// <summary><see cref="DependencyProperty"/> for methods <see cref="GetIsSelectedItemLast(MultiSelector)"/>
/// and <see cref="SetIsSelectedItemLast(MultiSelector, bool)"/>.</summary>
public static readonly DependencyProperty IsSelectedItemLastProperty =
DependencyProperty.RegisterAttached(
nameof(GetIsSelectedItemLast).Substring(3),
typeof(bool),
typeof(MuliSelectorHelper),
new PropertyMetadata(false, OnIsSelectedItemLastChanged));
private static void OnIsSelectedItemLastChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not Selector selector || selector.GetValue(ListBox.SelectedItemsProperty) is not IList list)
{
throw new NotImplementedException("Implemented only types that derive from Selector and that use the ListBox.SelectedItems dependency property.");
}
if (Equals(e.NewValue, true))
{
selector.SelectionChanged += OnSelectionChanged;
}
else
{
selector.SelectionChanged -= OnSelectionChanged;
}
}
private static async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count == 0)
return;
Selector selector = (Selector)sender;
IList selectedItems = (IList)selector.GetValue(ListBox.SelectedItemsProperty);
if (selectedItems.Count != e.AddedItems.Count && !Equals(selectedItems[0], e.AddedItems[0]))
{
selector.SelectionChanged -= OnSelectionChanged;
int beginIndex = selectedItems.Count - e.AddedItems.Count;
var selectedItemsArray = new object[selectedItems.Count];
selectedItems.CopyTo(selectedItemsArray, 0);
selectedItems.Clear();
await selector.Dispatcher.BeginInvoke(() =>
{
for (int i = selectedItemsArray.Length-1; i >= beginIndex; i--)
{
selectedItems.Add(selectedItemsArray[i]);
}
for (int i = 0; i < beginIndex; i++)
{
selectedItems.Add(selectedItemsArray[i]);
}
});
selector.SelectionChanged += OnSelectionChanged;
}
}
}
<UniformGrid Columns="2">
<ListBox Margin="10"
SelectedItem="{Binding SelectedItem}"
ItemsSource="{Binding Items}"
SelectionMode="Multiple"
local:MuliSelectorHelper.IsSelectedItemLast="true">
<FrameworkElement.Resources>
<DataTemplate DataType="{x:Type local:Item}">
<CheckBox Foreground="Red"
Content="{Binding Title}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:SimulationType}">
<CheckBox Foreground="Green"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path="Title"/>
<Binding Path="Count"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</CheckBox>
</DataTemplate>
</FrameworkElement.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<ContentControl Content="{Binding SelectedItem}">
<ContentControl.ContentTemplate>
<DataTemplate DataType="{x:Type local:Item}">
<DataTemplate.Resources>
<DataTemplate DataType="{x:Type local:Item}">
<TextBlock Foreground="Red"
Text="{Binding Title}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:SimulationType}">
<TextBlock Foreground="Green">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path="Title"/>
<Binding Path="Count"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</DataTemplate.Resources>
<Label x:Name="cc" Content="{Binding}" Margin="1" BorderBrush="Gray" BorderThickness="1"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter TargetName="cc" Property="Background" Value="LightPink"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</UniformGrid>
https://stackoverflow.com/questions/74287084
复制相似问题