PropertyChanged 仅提高一次,尽管属性经常变化(ArrayList、ObservableCollection<int>)

问题描述 投票:0回答:0

经过大量研究,我确实需要你的帮助。在研究时,我发现了几篇这样的文章:
如何将模型更改从模型传达给 ViewModel
双向绑定到模型中的数组
INotifyPropertyChanged 不更新数组属性.

但是,我没有正确应用一些东西。

设置:

  • MVVM
  • 应用程序是关于解决数独(我的问题不是关于解决算法)
  • INotifyChanged
    在Model和ViewModel中实现
  • 转换器实现
  • 调试所有属性的内容没问题;存储正确的值

一个属性是一个存储某种活动的枚举。根据它的值,视图将更新背景颜色。 这工作正常.

另一个属性是存储一组候选人的整数列表。在运行时,候选集将减少,直到只剩下一个数字。我想在视图中显示这些更改。 这根本行不通.

Activity 属性运行良好。在初始化时,颜色没有设置,在运行时,颜色会根据 Activity 中存储的内容而改变。

    /// <summary>
    /// This <see cref="Enum"/> is used to define the activities, 
    /// how the algorithm is finding a candidate.
    /// </summary>
    public enum Activity
    {
        Clue,
        Singleton,
        Single,
        Twin,
        Triple,
        BruteForce,
        Initialization,
    }
    private Activity _Activity;
    /// <summary>
    /// This property stores the activity performed to manipulate the cell.
    /// This can be used in the View to make this activity visible 
    /// by using a converter changing the background color.
    /// </summary>
    public Activity Activity { get => _Activity; set => SetProperty(ref _Activity, value); }
    public class SudokuValueColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (Enum.IsDefined(value.GetType(), value) == false)
                return DependencyProperty.UnsetValue;
            var activity = (Activity)value;
            switch (activity)
            {
                case Activity.Clue:
                    return Brushes.Blue;
                case Activity.Singleton:
                    return Brushes.Orange;
                case Activity.Single:
                    return Brushes.Green;
                case Activity.Twin:
                    return Brushes.Brown;
                case Activity.Triple:
                    return Brushes.Yellow;
                case Activity.BruteForce:
                    return Brushes.Red;
                case Activity.Initialization:
                    return null;
                default:
                    return Brushes.Black;
            }
        }
    }

因此,我试图将其应用于属性 SetOfCandidates。在第一次运行中,这个属性是一个 ArrayList。这不起作用,因为更改数组的成员不会引发 PropertyChanged 事件(如果我对此进行了适当的研究)。建议是用 ObservableCollection 替换 ArrayList,我这样做了,但它仍然没有像我期望的那样工作。

    private ArrayList _IntersectingSet; //first attempt
    /// <summary>
    /// A set of digits that is the intersection of the tree 'SetOfCandidates' properties.
    /// <br></br>A digit must be out of a set, where D = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.
    /// <para>
    /// <br></br>If there is just one member in this <see cref="ArrayList"/>, then it is the <see cref="Value"/>.
    /// </para>
    /// </summary>
    public ArrayList IntersectingSet { get => _IntersectingSet; set => _IntersectingSet = value; }

    private ObservableCollection<int> _SetOfCandidates; //second attempt
    /// <summary>
    /// My test to fire EventChanged in View
    /// </summary>
    public ObservableCollection<int> SetOfCandidates { get => _SetOfCandidates; set => SetProperty(ref _SetOfCandidates, value); }

    public class SudokuCandidateToContentConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string contentValue = string.Empty;
            //var arrayList = (ArrayList)value; //first attempt
            var arrayList = (ObservableCollection<int>)value; //second attempt
            if (arrayList == null) return "+"; //just for testing
            if (arrayList.Count == 0) return "++"; //just for testing
            //if (arrayList == null) return contentValue;
            //if (arrayList.Count == 0) return contentValue;
            foreach (var item in arrayList)
            {
                if (item == (int)parameter)
                {
                    contentValue = (string)parameter;
                }
            }
             return contentValue;
        }
    }

我的期望:

我希望在应用程序启动时在视图中显示一个空字符串。稍后,用户正在加载一个数独游戏,将线索放入视图中。在这种情况下,这些特定单元格的 SetOfCandidates 计数为零,标签内容为空字符串。所有其他未设置任何值的单元格都根据算法的逻辑更新它们的 SetOfCandidates。标签的内容应该使 SetOfCandidates 在视图中可见。

发生了什么事? 只有在启动应用程序时,才会调用更新标签内容的转换器。这与每当绑定属性发生变化时调用的 SudokuValueColorConverter 形成对比。

这是xaml代码。 Border 中的转换器工作正常。 Label 中的转换器只被调用一次。

    <Border Style="{StaticResource borderSudokuCandidatesCell}" Background="{Binding Sudoku[0].Activity, Converter={StaticResource sudokuValueColorConverter}}">
        <UniformGrid>
            <Label
               Content="{Binding Sudoku[0].SetOfCandidates, Converter={StaticResource sudokuCandidateToContentConverter}, ConverterParameter=1}" 
               Style="{StaticResource labelSudokuCandidates}">
            </Label>
            <Label
    <!-- *** repeated with changing ConverterParameter from 1 to 9 ***-->
            <Label
               Content="{Binding Sudoku[0].SetOfCandidates, Converter={StaticResource sudokuCandidateToContentConverter}, ConverterParameter=9}" 
               Style="{StaticResource labelSudokuCandidates}">
            </Label>
        </UniformGrid>
    </Border>

这里有一些图片。

  • ImageA:应用程序在起点。正如预期的那样,标签的内容是 ++(用于测试的占位符)。
  • ImageB:加载数独之后。预期的是,一个标签显示内容 8,所有其他标签应该是一个空字符串。
  • ImageC:解决数独之后。预期的是,所有标签都应该是一个空字符串。

ImageA

ImageB

ImageC

亲爱的社区,如果您对我有任何建议,请帮助我。感谢您的意见。如果你看到一个更聪明的方法来实现我的想法,请告诉我。

c# mvvm observablecollection inotifypropertychanged
© www.soinside.com 2019 - 2024. All rights reserved.