当集合中的属性更改时在转换器上触发“ConvertBack”?

弗雷德里克

我正在 MVVM WPF 应用程序中使用转换器从标记的枚举中“即时”创建复选框列表。bound 属性是一个 int,表示一个标记的枚举。这是我的转换器,它从 int 转换为 ObservableDictionary<int, bool>。

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);
    }
}

关键是用户可以挑选并选择要为属性启用的枚举。我认为使用转换器是有意义的,但是当勾选/取消勾选复选框时,我很难让转换器触发它的“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); } }
    }
}

然后我实现了一个来自 StackOverflow 的 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 永远不会被触发。我认为这可能是因为集合本身实际上并没有改变,但是我怎么能强制更新呢?非常感谢任何帮助:)

编辑:我可能已经以以下评论的形式发现了我自己问题的答案:https : //stackoverflow.com/a/59637445/3390519我会试一试!

弗雷德里克

我通过更改搜索参数解决了我自己的问题!我没有搜索“当集合中的属性更改时在转换器上触发“ConvertBack”的解决方案?”,而是开始搜索“wpf - 将标志枚举转换为复选框列表”的解决方案,并找到了一个不错的解决方案!它不是动态的(必须手动更新枚举值),但对我来说已经足够了:) https://stackoverflow.com/a/59637445/3390519

感谢您的时间 XAMIMAX :)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

转换器只会触发一次,而不是每次标签内容更改时都会触发

WPF-外部更改时,datagrid中的值无法更新转换器

集合更新后转换器未触发

为什么与转换器绑定会更改GUI上未绑定的属性?

如何在 KeyDown 操作上触发转换器?

触发VS转换器

当javafx中的父属性更改时,清理绑定并更改嵌套属性上的侦听器

未触发ModelMapper中的自定义转换器

属性更改时不会触发ItemTemplate-DataTemplate中的DataTrigger

当列表中项目的属性更改时,ListCollectionView上的LiveFiltering不会重新评估筛选器

如何在JPA <= 2.0中模拟属性转换器?

基于JPA 2.1中的多个属性创建转换器

Ember.js:当控制器中的属性发生更改时,触发“ Ember.computed.filter”进行更新

未触发转换器的显示索引

如果绑定属性为空,C# WPF 绑定转换器不会触发

使用转换器时未触发数据触发

Swift Inout如何在不更改时不复制属性,不触发对象设置器

WPF 绑定文本块文本以更新属性,但文本由转换器更改

当列在另一个触发器中更改时,ORACLE“更新前”触发器不会触发

属性更改时触发的动画似乎没有触发

laravel 5.6 上的 cartalyst/转换器

忽略自定义JSON转换器中带有属性的属性

当可观察集合中的任何项目更改时,更新当前的类属性

列值更改时触发 SQL 触发器

字段更改时MVVM对象触发属性更改事件

当父属性更改时,为派生属性触发PropertyChanged

如何使用转换器或数据触发器动态设置数据网格中列中的单元格样式?

当React中的值被代码更改时,如何在输入上触发onChange事件?

JPA 2.1属性转换器转换枚举仍插入int