以下是对本质上是一个简单问题的冗长的解释。我使用的是Telerilk RadDropDownButton,它显示带有复选框的列表项。
<Controls:RadDropDownButton AutoOpenDelay="0:0:0.0" x:Name="Urgency" VerticalAlignment="Center" Width="150" Content="{Binding Path=ItemsSource, ElementName=UrgencyList, Mode=TwoWay, Converter={StaticResource ButtonTextConverter}}" HorizontalContentAlignment="Left">
<Controls:RadDropDownButton.DropDownContent>
<ListBox x:Name="UrgencyList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding Name}" ClickMode="Press" IsChecked="{Binding IsChecked, Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Controls:RadDropDownButton.DropDownContent>
</Controls:RadDropDownButton>如您所见,我将Content属性绑定到转换器。我想要的是,如果没有被选中,内容要读“全部”,如果检查了某一项,则显示选中(选中)项的#列表。
public class ButtonTextConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Debug.WriteLine("I'm Binding");
int numChecked = 0;
if (value != null)
numChecked = ((ObservableCollection<UrgencyItem>) value).Count(urgencyItem => urgencyItem.IsChecked);
return numChecked > 0 ? string.Format("{0} Items Selected", numChecked) : "All";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}根据需要,我绑定到的类实现了INotifyPropertyChanged。部分清单如下:
public class UrgencyItem : INotifyPropertyChanged
{
private int _id;
private bool _isChecked;
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
NotifyPropertyChanged("Name");
}
}我将ListBox绑定到代码隐藏中的数据,如下所示:
private void SearchParamsVertical_Loaded(object sender, RoutedEventArgs e)
{
urgencyList = new ObservableCollection<UrgencyItem>
{
new UrgencyItem {ID = 1, IsChecked = false, Name = "Non Emergent"},
new UrgencyItem {ID = 2, IsChecked = false, Name = "Emergent"},
new UrgencyItem {ID = 3, IsChecked = false, Name = "Stat Emergent"},
new UrgencyItem {ID = 4, IsChecked = false, Name = "Stroke Protocol"}
};
urgencyList.CollectionChanged += urgencyList_CollectionChanged;
UrgencyList.ItemsSource = urgencyList;
},所以问题是.
选中复选框时,应更新内容的值。事实并非如此。
原因不是因为,尽管通知触发了IsChecked被更改,但通知基本上是无处可寻的。UrgencyItem对象不知道它是ObservableCollection的一部分。关于ObservableCollection的问题是,只有当项被添加/移除到集合/从集合中删除时,它才会向它的绑定发送通知。换句话说,更改集合中项的属性不会触发CollectionChanged事件,因为没有添加/删除任何对象。
我需要做的是在修改集合的属性时触发collectionChanged事件。我以前知道怎么做,但是离Silverlight太远了,我忘了怎么做。
有没有人?
发布于 2011-03-14 16:29:39
简而言之,我认为您的诊断是正确的:如果ObservableCollection中的一个对象发生了更改,即使该对象实现了INotifyPropertyChanged,通常也不会得到一个INotifyPropertyChanged通知。据我所知,没有一种简单的方法可以通过内置Silverlight类获得您想要的行为。
我知道有三种可能的方法来解决这个问题:
(1)一个选项是为urgencyList创建自己的集合,继承自ObservableCollection,实现此行为,即订阅添加到集合中的每个对象的INPC通知,并在发生这种情况时触发CollectionChanged事件。
(2)第二种选择是使用类似于ReactiveUI框架的东西,它有自己的ReactiveCollection来实现这种行为。
(3)第三种选择是通过类似于urgencyList的东西创建Obtics还是连续Linq。它们返回的集合自动实现此行为。
发布于 2011-08-25 14:31:34
这就是我要用的东西。肯恩在nr (1)中所建议的是:
public class Person: INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set {
_name = value;
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}我将这些对象放在PLObservableNotifyList<Person>中,并将其设置为ItemsControl上的ItemsSource。一旦我更新值(使用setter),绑定就会自动更新。
public class PLObservableNotifyList<T> :
ObservableCollection<T> where T : INotifyPropertyChanged
{
public ItemPropertyChangedEventHandler ItemPropertyChanged;
public EventHandler CollectionCleared;
protected override void OnCollectionChanged(
NotifyCollectionChangedEventArgs args)
{
base.OnCollectionChanged(args);
if (args.NewItems != null)
foreach (INotifyPropertyChanged item in args.NewItems)
item.PropertyChanged += OnItemPropertyChanged;
if (args.OldItems != null)
foreach (INotifyPropertyChanged item in args.OldItems)
item.PropertyChanged -= OnItemPropertyChanged;
}
void OnItemPropertyChanged(object sender,
PropertyChangedEventArgs args)
{
if (ItemPropertyChanged != null)
ItemPropertyChanged(this,
new PLItemPropertyChangedEventArgs(sender,
args.PropertyName));
}
protected override void ClearItems()
{
foreach (INotifyPropertyChanged item in Items)
item.PropertyChanged -= OnItemPropertyChanged;
if (CollectionCleared != null)
CollectionCleared(this, EventArgs.Empty);
base.ClearItems();
}
}发布于 2019-11-21 12:02:52
你需要我的ObservableComputations库。使用该库,您可以编写以下代码:
private Computing<string> _checkedUrgencyItemsText;
public Computing<string> CheckedUrgencyItemsText = _selectedUrgencyItemsText ??
Expr.Is(() => UrgencyItems.Filtering(urgencyItem => urgencyItem.IsChecked)
.Using(checkedUrgencyItems =>
checkedUrgencyItems.Count > 0
? string.Format("{0} Items Selected", checkedUrgencyItems.Count)
: "All")).Computing(); <Controls:RadDropDownButton Content="{Binding Path=CheckedUrgencyItemsText.Value}" AutoOpenDelay="0:0:0.0" x:Name="Urgency" VerticalAlignment="Center" Width="150" HorizontalContentAlignment="Left">
<Controls:RadDropDownButton.DropDownContent>
<ListBox x:Name="UrgencyList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding Name}" ClickMode="Press" IsChecked="{Binding IsChecked, Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Controls:RadDropDownButton.DropDownContent>
</Controls:RadDropDownButton>https://stackoverflow.com/questions/5300635
复制相似问题