当集合中的 属性 发生变化时在转换器上触发 "ConvertBack"?
Triggering "ConvertBack" on a converter when a property in a collection changes?
我正在 MVVM WPF 应用程序中使用转换器从标记的枚举“动态”创建复选框列表。绑定 属性 是一个 int,代表一个标记的枚举。这是我的转换器,可将 int 转换为 ObservableDictionary。
public class AccessListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int realValue;
switch (value)
{
case int intValue:
realValue = intValue;
break;
case AccessEnum enumValue:
realValue = (int)enumValue;
break;
default:
return Binding.DoNothing;
}
List<AccessEnum> accessComponents = Enum.GetValues(typeof(AccessEnum)).Cast<AccessEnum>().Where(r => ((AccessEnum)realValue & r) == r).Select(r => r).ToList();
ObservableDictionary<int, bool> accessDictionary = new ObservableDictionary<int, bool>(Enum.GetValues(typeof(AccessEnum)).Cast<int>().Select(i => i).ToDictionary(i => i, i => accessComponents.Contains((AccessEnum) i)));
accessDictionary.Remove(0);
return accessDictionary;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is Dictionary<int, bool> intDict))
{
throw new NotImplementedException();
}
return intDict.Sum(x => x.Value ? x.Key : 0);
}
}
重点是用户可以挑选并选择要为 属性 启用哪些枚举。我认为使用转换器是有意义的,但是当复选框为 ticked/unticked.
时,我很难让转换器触发它的“ConvertBack”方法
这是我在 Xaml 中的绑定:
<ItemsControl ItemsSource="{Binding Access, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource AccessListConverter}}" Margin="87,0,10,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel CanVerticallyScroll="False" Margin="0"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox VerticalAlignment="Center" Margin="6,0,0,0" Content="{Binding Key, Converter={StaticResource AccessStringConverter}, UpdateSourceTrigger=PropertyChanged}"
IsChecked="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
现在我们来看看 Observable Dictionary 这就是我的 OBservableDictionary 实现的样子(删除了不相关的部分,其余部分缩小了):
[Serializable]
public class ObservableDictionary<TKey, TValue> :
ObservableCollection<ObservableKeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>
{
public ObservableDictionary() {}
public ObservableDictionary(Dictionary<TKey, TValue> dictionary) : this()
{
foreach (TKey key in dictionary.Keys) { Add(key, dictionary[key]); }
}
public ObservableDictionary(ObservableDictionary<TKey, TValue> dictionary) : this()
{
foreach (TKey key in dictionary.Keys) { Add(key, dictionary[key]); }
}
public void Add(TKey key, TValue value)
{
if (ContainsKey(key)) { throw new ArgumentException("The dictionary already contains the key"); }
Add(new ObservableKeyValuePair<TKey, TValue>() { Key = key, Value = value });
}
public ICollection<TKey> Keys => (from i in ThisAsCollection() select i.Key).ToList();
public ICollection<TValue> Values => (from i in ThisAsCollection() select i.Value).ToList();
public TValue this[TKey key]
{
get { if (!TryGetValue(key, out TValue result)) {throw new ArgumentException("Key not found"); } return result; }
set { if (ContainsKey(key)) { GetKvpByTheKey(key).Value = value; } else { Add(key, value); } }
}
}
然后我从 Whosebug 实现了一个 collectionChanged 代码片段
void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null) foreach (object item in e.NewItems){ ((INotifyPropertyChanged) item).PropertyChanged += item_PropertyChanged; }
if (e.OldItems != null) foreach (object item in e.OldItems) { ((INotifyPropertyChanged) item).PropertyChanged -= item_PropertyChanged;}
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
OnCollectionChanged(a);
}
并在空构造函数中添加了CollectionChanged += TrulyObservableCollection_CollectionChanged;
。
但是没有骰子。经过数小时的搜索,我仍然一无所获。 ConvertBack 永远不会被触发。我想这可能是因为集合本身 实际上 没有变化,但我怎样才能强制更新呢?非常感谢任何帮助:)
编辑:
我可能已经以以下评论的形式找到了我自己的问题的答案: 我会试一试!
我通过更改搜索参数解决了自己的问题!我没有搜索“当集合中的 属性 发生变化时在转换器上触发“ConvertBack”的解决方案?”,我开始搜索“wpf - 将标志枚举转换为复选框列表”的解决方案并找到了一个不错的解决方案解决方案!它不是动态的(枚举值必须手动更新),但足以满足我的目的:)
感谢您的宝贵时间 XAMIMAX :)
我正在 MVVM WPF 应用程序中使用转换器从标记的枚举“动态”创建复选框列表。绑定 属性 是一个 int,代表一个标记的枚举。这是我的转换器,可将 int 转换为 ObservableDictionary
public class AccessListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int realValue;
switch (value)
{
case int intValue:
realValue = intValue;
break;
case AccessEnum enumValue:
realValue = (int)enumValue;
break;
default:
return Binding.DoNothing;
}
List<AccessEnum> accessComponents = Enum.GetValues(typeof(AccessEnum)).Cast<AccessEnum>().Where(r => ((AccessEnum)realValue & r) == r).Select(r => r).ToList();
ObservableDictionary<int, bool> accessDictionary = new ObservableDictionary<int, bool>(Enum.GetValues(typeof(AccessEnum)).Cast<int>().Select(i => i).ToDictionary(i => i, i => accessComponents.Contains((AccessEnum) i)));
accessDictionary.Remove(0);
return accessDictionary;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is Dictionary<int, bool> intDict))
{
throw new NotImplementedException();
}
return intDict.Sum(x => x.Value ? x.Key : 0);
}
}
重点是用户可以挑选并选择要为 属性 启用哪些枚举。我认为使用转换器是有意义的,但是当复选框为 ticked/unticked.
时,我很难让转换器触发它的“ConvertBack”方法这是我在 Xaml 中的绑定:
<ItemsControl ItemsSource="{Binding Access, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource AccessListConverter}}" Margin="87,0,10,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel CanVerticallyScroll="False" Margin="0"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox VerticalAlignment="Center" Margin="6,0,0,0" Content="{Binding Key, Converter={StaticResource AccessStringConverter}, UpdateSourceTrigger=PropertyChanged}"
IsChecked="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
现在我们来看看 Observable Dictionary 这就是我的 OBservableDictionary 实现的样子(删除了不相关的部分,其余部分缩小了):
[Serializable]
public class ObservableDictionary<TKey, TValue> :
ObservableCollection<ObservableKeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>
{
public ObservableDictionary() {}
public ObservableDictionary(Dictionary<TKey, TValue> dictionary) : this()
{
foreach (TKey key in dictionary.Keys) { Add(key, dictionary[key]); }
}
public ObservableDictionary(ObservableDictionary<TKey, TValue> dictionary) : this()
{
foreach (TKey key in dictionary.Keys) { Add(key, dictionary[key]); }
}
public void Add(TKey key, TValue value)
{
if (ContainsKey(key)) { throw new ArgumentException("The dictionary already contains the key"); }
Add(new ObservableKeyValuePair<TKey, TValue>() { Key = key, Value = value });
}
public ICollection<TKey> Keys => (from i in ThisAsCollection() select i.Key).ToList();
public ICollection<TValue> Values => (from i in ThisAsCollection() select i.Value).ToList();
public TValue this[TKey key]
{
get { if (!TryGetValue(key, out TValue result)) {throw new ArgumentException("Key not found"); } return result; }
set { if (ContainsKey(key)) { GetKvpByTheKey(key).Value = value; } else { Add(key, value); } }
}
}
然后我从 Whosebug 实现了一个 collectionChanged 代码片段
void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null) foreach (object item in e.NewItems){ ((INotifyPropertyChanged) item).PropertyChanged += item_PropertyChanged; }
if (e.OldItems != null) foreach (object item in e.OldItems) { ((INotifyPropertyChanged) item).PropertyChanged -= item_PropertyChanged;}
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
OnCollectionChanged(a);
}
并在空构造函数中添加了CollectionChanged += TrulyObservableCollection_CollectionChanged;
。
但是没有骰子。经过数小时的搜索,我仍然一无所获。 ConvertBack 永远不会被触发。我想这可能是因为集合本身 实际上 没有变化,但我怎样才能强制更新呢?非常感谢任何帮助:)
编辑: 我可能已经以以下评论的形式找到了我自己的问题的答案: 我会试一试!
我通过更改搜索参数解决了自己的问题!我没有搜索“当集合中的 属性 发生变化时在转换器上触发“ConvertBack”的解决方案?”,我开始搜索“wpf - 将标志枚举转换为复选框列表”的解决方案并找到了一个不错的解决方案解决方案!它不是动态的(枚举值必须手动更新),但足以满足我的目的:)
感谢您的宝贵时间 XAMIMAX :)