让我在这个问题之前声明我对 C# 和 WPF 都很陌生。
我正在尝试将一组
Boolean
值连接到包含 6 个复选框的容器,并在按下按钮时存储这些值的状态。我假设有一种简单的方法可以做到这一点,因为将复选框绑定到集合似乎是一件非常自然的事情,但到目前为止我看到的所有解决方案似乎都过于复杂(例如:http://merill .net/2009/10/wpf-checked-listbox/)。
我通过修改
ListBox
的数据模板来创建复选框,并将ItemsSource
的ListBox
设置为ObservableCollection
,但我的问题是我不知道将IsChecked
绑定到什么,因为我试图将它绑定到集合中的实际对象而不是对象的属性。
使用
IsChecked="{Binding}"
直接绑定集合的item。
<ListBox ItemsSource="{Binding MyBooleanCollection}" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Mode=OneWay}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
但是,无法使用此方法绑定到源。因为
IsChecked
的 CheckBox
属性上的绑定不是绑定项的索引。因此,它不能更改集合,只能更改集合的项目。
要解决该限制,您可以创建布尔值的包装器:
public class Wrapper<T> : INotifyPropertyChanged
{
private T value;
public T Value
{
get { return value; }
set
{
{
this.value = value;
OnPropertyChanged();
}
}
}
public static implicit operator Wrapper<T>(T value)
{
return new Wrapper<T> { value = value };
}
public static implicit operator T(Wrapper<T> wrapper)
{
return wrapper.value;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
这是一个用法示例:
public partial class MainWindow : Window
{
public ObservableCollection<Wrapper<bool>> MyBooleanCollection { get; private set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyBooleanCollection = new ObservableCollection<Wrapper<bool>>() { false, true, true, false, true };
}
}
在 XAML 中:
<CheckBox IsChecked="{Binding Value}"/>
在
ItemTemplate
中你可以写
<CheckBox IsChecked="{Binding Path=.}"/>
或
<CheckBox IsChecked="{Binding Mode=OwnWay}"/>
直接绑定到项目对象,即集合中的
bool
值。
IsChecked
的对象。在您的情况下,这可能如下所示简单(因为您的问题听起来像您不需要属性更改通知):
public class BooleanHelper
{
public bool Value { get; set; }
}
绑定现在看起来像这样:
<CheckBox IsChecked="{Binding Path=Value}"/>
该集合现在将是一个
ObservableCollection<BooleanHelper>
,您可能会添加如下项目:
Items.Add(new BooleanHelper { Value = true });
public class CheckedListItem : INotifyPropertyChanged
{
private int _Id;
public int Id
{
get;
set; NotifyIfAnythingChanged("Id");
}
private string _Name;
public string Name
{
get;
set; NotifyIfAnythingChanged("Name");
}
private bool _IsChecked;
public bool IsChecked
{
get;
set; NotifyIfAnythingChanged("IsChecked");
}
private void NotifyIfAnythingChanged(String propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
你的列表框应该是这样的:
<ListBox x:Name="MyListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content={Binding Path=Name} IsChecked="{Binding Mode=TwoWay, Path=IsChecked}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
在后面的代码中,您应该只初始化 ObservableCollection 一次,因为对其进行的每次更改都会导致 UI 更新。
ObservableCollection<CheckedListItem> MyList = new ObservableCollection<CheckedListItem>();
MyListBox.ItemsSource = MyList;
现在对 MyList 所做的每一个更改,例如 Add()、Remove() 等都会影响您的 UI。
ObservableCollection 和 мне нужно было отслеживать изменения в этой колекции поэтому создании экземпляра класса я подписывался на события изменений колекции и выполнял свое событие о том что данное изменено.
//Наследую для обратной связи о каких либо изменениях
public class Company : INotifyPropertyChanged
{
//Собитие
public event PropertyChangedEventHandler PropertyChanged;
//Обработчик события
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
...
//Та самя колекция в которой я хочу отслеживать измения
private ObservableCollection<bool> _companyBuldVisible;
public ObservableCollection<bool> CompanyBuldVisible
{
get => _companyBuldVisible;
set
{
_companyBuldVisible = value;
OnPropertyChanged(); //Это вызывается только при создании или переприсвоению
}
}
...
public ICommand SelectCompany { get; set; }
public Company()
{
SelectCompany = new Command(async p =>
{
...
//Подписываться на собитие возможно только когда колекция инициализирована, поэтому я повесил его на Клик
CompanyBuldVisible.CollectionChanged += CompanyBuldVisible_CollectionChanged; // Подписка на событие что какое значение было изменено
});
}
private void CompanyBuldVisible_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
//Отписываюсь для того чтобы подписки не скапливались и обработка не срабатывала несколько раз
CompanyBuldVisible.CollectionChanged -= CompanyBuldVisible_CollectionChanged;
OnPropertyChanged("CompanyBuldVisible"); //Сообщаю об этом изменении свой класс
}
}