【问题标题】:Making the children of a class communicate witch eachtother让班级的孩子互相交流
【发布时间】:2020-06-18 14:35:25
【问题描述】:

我的 MVVM 模式代码的 ViewModel 有问题。

我有一堆测量值和一堆用于评估测量值的规则,存储在 Rule 和 Measurement 类中。在我的主类 MyClass 中,我将我的规则和测量值存储在 ObservableCollections (OC) 中(并连接到 DataGrid)。

对于所有 n 个规则,我在一个 OC 中创建 n 个 CollcetionOfEvaluators 并将相应的规则和所有测量值传递给每个单独的规则。 在我为一个规则创建的每个 CollectionOfEvaulators 中,以及一个 OC 中的 m 个 Measurements m Evaluators。

评估者采用一个规则和一个测量,如果相应的测量通过相应的规则,则返回一个布尔值。

然后,我有一个 ListView,它为每个 Rule 显示一个 DataGrid,如果它通过了 Rule,它会为每个 Measurement 显示。

如果我更改 MyClass 中测量值之一的属性,我的问题是让 Evaluator 类触发 OnPropertyChanged 方法。我怎样才能将信息基本上从一个孩子传递给另一个孩子的孩子?当我使用 Evaluators 的 DataGrid 时,例如单击标题以重新排列它,它可以工作。所以我想问题是c#代码而不是xaml。因此,我将把它放在一边。所有的绑定都是 Mode=TwoWay(除了 bool,因为它没有 setter)和 UpdateSourceTrigger=PropertyChanged。

我试图勾勒出这个问题:

这是我的代码:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;

namespace demo
{
    public class MyClass : INotifyPropertyChanged
    {
        public class Measurement : INotifyPropertyChanged
        {
            private double? myValue1;

            public double? MyValue1
            {
                get { return myValue1; }
                set
                {
                    myValue1 = value;
                    OnPropertyChanged("MyValue1");
                }
            }

            private double? myValue2;

            public double? MyValue2
            {
                get { return myValue2; }
                set
                {
                    myValue2 = value;
                    OnPropertyChanged("MyValue2");
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;

            private void OnPropertyChanged(string propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }

        }

        public class EvaluationRule
        {
            public EvaluationRule(double Value1Min, double Value2Min)
            {
                this.Value1Min = Value1Min;
                this.Value2Min = Value2Min;
            }

            public double Value1Min;
            public double Value2Min;

        }

        public class Evaluator : INotifyPropertyChanged
        {
            public Evaluator(Measurement Measurement, EvaluationRule Rule)
            {
                this.Rule = Rule;
                this.Measurement = Measurement;
            }

            public EvaluationRule Rule;

            private Measurement measurement;
            public Measurement Measurement
            {
                get { return measurement; }
                set
                {
                    measurement = value;
                    OnPropertyChanged("Measurement");
                }
            }

            public bool IsApproved
            {
                get
                {
                    if (measurement.MyValue1 > Rule.Value1Min
                        && measurement.MyValue2 > Rule.Value2Min)
                    {
                        return true;
                    }
                    return false;
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;

            private void OnPropertyChanged(string propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public class CollectionOfEvaluators : INotifyPropertyChanged
        {
            public CollectionOfEvaluators(EvaluationRule Rule, ObservableCollection<Measurement> Measurements)
            {
                this.Rule = Rule;
                this.Measurements = Measurements;

                var Evaluators = new ObservableCollection<Evaluator>();
                foreach (var _measurement in Measurements)
                {
                    var _evaluator = new Evaluator(_measurement, this.Rule);
                    Evaluators.Add(_evaluator);
                }
            }

            public EvaluationRule Rule;

            private ObservableCollection<Measurement> measurements;

            public ObservableCollection<Measurement> Measurements
            {
                get { return measurements; }
                set
                {
                    measurements = value;
                    OnPropertyChanged("Measurements");
                }
            }

            private ObservableCollection<Evaluator> evaluators;

            public ObservableCollection<Evaluator> Evaluators
            {
                get { return evaluators; }
                set
                {
                    evaluators = value;
                    OnPropertyChanged("Evaluators");
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;

            private void OnPropertyChanged(string propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private ObservableCollection<Measurement> measurements;

        public ObservableCollection<Measurement> Measurements
        {
            get { return measurements; }
            set
            {
                measurements = value;
                OnPropertyChanged("Measurements");
            }
        }

        private ObservableCollection<EvaluationRule> rules;

        public ObservableCollection<EvaluationRule> Rules
        {
            get { return rules; }
            set
            {
                rules = value;
                GetCollection();
            }
        }

        private ObservableCollection<CollectionOfEvaluators> collection;

        public ObservableCollection<CollectionOfEvaluators> Collection
        {
            get { return collection; }
            set
            {
                collection = value;
                OnPropertyChanged("Collection");
            }
        }

        public void GetCollection()
        {
            var Collection = new ObservableCollection<CollectionOfEvaluators>();
            foreach (var _rule in rules)
            {
                var _collection = new CollectionOfEvaluators(_rule, Measurements);
                Collection.Add(_collection);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

【问题讨论】:

    标签: c# wpf mvvm inotifypropertychanged


    【解决方案1】:

    您必须委托该事件。 Evaluator 应该监听其聚合的MeasurementPropertyChanged 事件。然后,该事件的处理程序可以引发 Evaluator.PropertyChanged 事件作为响应:

    public class Evaluator : INotifyPropertyChanged
    {
      public Evaluator(Measurement measurement, EvaluationRule rule)
      {
        this.Rule = rule;
        this.Measurement = measurement;
    
        this.Measurement.PropertyChanged += OnMeasurementPropertyChanged;
      }
    
      public void OnMeasurementPropertyChanged(object sender, PropertyChangedEventAgrs e)
      {
        OnPropertyChanged(nameof(this.Measurement));
      }
    
      private Measurement measurement;
      public Measurement Measurement
      {
        get  => this.measurement
        set
        {
          this.measurement = value;
          OnPropertyChanged(nameof(this.Measurement));
        }
      }
    
      public event PropertyChangedEventHandler PropertyChanged;
      private void OnPropertyChanged(string propertyName)
      {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    }
    

    请注意,您在命名班级时遇到了拼写错误。这是我a确信 - 你错过了一个“a”。此外,参数名称应始终为小写。

    【讨论】:

    • 当我快速打字时,我已经训练了我的肌肉来错误输入显示(变成显示)和属性(变成属性)和更改(变成 chnage)。基本上只有这三个字。当肌肉记忆训练错误并一直在愚弄你时......你应该阅读Microsoft Docs: C# Coding Conventions (C# Programming Guide)。遵循一种语言的约定总是好的,尤其是在交换代码时。
    • 不错。我很高兴能帮上忙。玩得开心。
    • 这确实让一切变得更容易。由于拼写错误,没有更多的调试会话。重命名属性将永远不会再次破坏代码(我们依赖于成员或类名的字符串表示形式)。 nameof 适用于每种类型或成员,例如方法。
    • 如果您喜欢它,请更进一步。看看CallerMemberNameAttribute。它使传递给OnPropertyChanged 的参数变得多余。您可以在 Microsoft Docs: INotifyPropertyChanged.PropertyChanged 找到一个简短的示例实现
    • 不,没关系。但是,如果一个属性为其他属性引发 PropertyChanged 事件,则可能会非常混乱或难以维护。我会在MySum 中添加一个设置器(可能是private),以便它可以自行引发PropertyChanged 事件:MySum { get =&gt; _mySum; private set {...}},然后在相关属性之一AB 更改时显式设置它:A { get =&gt; _a; set { _a = value; MySum = value + B; }}。为了更好的可读性,我什至会将MySum = value + B 移动到一个单独的方法:CreateSum() =&gt; MySum = A + B 并从AB 的两个设置器中调用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 2013-12-24
    • 1970-01-01
    • 2014-01-01
    • 1970-01-01
    • 2013-09-04
    相关资源
    最近更新 更多