【问题标题】:Basic of Event and Delegate. Event Subscribe line of PropertyChange Event from INotifyPropertyChanged in the class using it事件和代表的基础。从使用它的类中的 INotifyPropertyChanged 中订阅 PropertyChange 事件的事件行
【发布时间】:2019-04-27 19:19:28
【问题描述】:

您好,我从https://www.youtube.com/watch?v=jQgwEsJISy0&t=1230s 了解到事件和委托。在这他说要使事件发生,我们需要三个步骤

  1. 定义委托
  2. 根据该委托定义事件
  3. 引发该事件

我跟随他并在控制台中制作了应用程序,但由于我在 WPF 中工作,我将在此处发布我在 WPF 中使用的代码,代码如下:

namespace WpfApp5
{
    public delegate void step1DelegateDefinition(); // Step-1: Define a delegate

    public interface INotifyOnVideoEncoded
    {
        event step1DelegateDefinition EventDefinedInInterface;// Step-2a:  Define an event based on that delegate
    }

    public partial class MainWindow : Window, INotifyOnVideoEncoded
    {
        public event step1DelegateDefinition EventDefinedInInterface; //Step-2b:  Define an event based on that delegate

        public MainWindow()
        {
           InitializeComponent();
           this.DataContext = this;
           ObservableCollection<string> NotificationText = new ObservableCollection<string>();
            EventDefinedInInterface += SubscriberMethodForConection;// A method corresponding to delegate is subscribed for that event 
            Encode();
        }

        public void Encode()
        {
            MessageBox.Show("Encoding Video...");
            Thread.Sleep(3000);
            PublisherMethodForConnection(); //Step-3: Raise an event
        }

        public void PublisherMethodForConnection()
        {
            if (EventDefinedInInterface != null)
                EventDefinedInInterface();
            else
                MessageBox.Show("No Subscriber");
        }

        public void SubscriberMethodForConection()
        {
            MessageBox.Show("MailService: Sending an email...");
        }
    }       
}

所以我的知识是这样的

必须订阅事件才能使用 += 符号执行。

但与我的知识相比,当我使用 INotifyPropertyChange 中的 propertychange 事件时,不需要 += 符号。而且奇怪的是似乎+ =(订阅事件)是动态完成的,但是因为如果我首先初始化属性(在我的情况下,如果我初始化FirstName = Jeff和LastName = Buckley的值,则在下面的代码中显示)然后它会触发我的代码中的 else 部分在开头显示消息“没有 MyOnPropertyChanged 函数可以调用的订阅者”。我相信这是因为事件订阅者是空的(即没有像我期望的那样 += 事件分配语句)但是稍后一旦加载窗口,似乎有事件订阅者虽然我没有在代码上这样做。下面是我的代码实现属性更改。

namespace UnderstandingINotifyPropertyChanged
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string _FirstName;
        private string _FullName;
        private string _LastName;

        public string FirstName
        {
            get { return _FirstName; }
            set
            {
                if (_FirstName != value)
                {
                    _FirstName = value;
                    MyOnPropertyChanged_PublisherMethod("FirstName");
                    MyOnPropertyChanged_PublisherMethod("FullName");
                }
            }
        }
        public string LastName
        {
            get { return _LastName; }
            set
            {
                if (_LastName != value)
                {
                    _LastName = value;
                    MyOnPropertyChanged_PublisherMethod("Lastname");
                    MyOnPropertyChanged_PublisherMethod("FullName");
                }
            }
        }
        public string FullName
        {
            get { return _FullName = _FirstName + " " + _LastName; }

        }

        private void MyOnPropertyChanged_PublisherMethod(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
            else
                MessageBox.Show("There is no Subscriber to which MyOnPropertyChanged function can call ");
        }

        public MainWindow()
        {
            InitializeComponent();
            FirstName = "Jeff";
            LastName = "Buckley";
            this.DataContext = this;
           
        }
    }
}

所以我的困惑是在第一个代码中我必须使用 += 分配事件,但在第二个代码中它可以在不执行 += 的情况下工作。我无法弄清楚第二个代码如何在不使用 += 的情况下运行,因为需要使用 += 将事件链接到订阅者。

我尝试在线阅读并查看视频以进行解释,但不明白这是我在这里问的原因。到目前为止,我已经从这里学到了很多东西,谢谢你,也感谢你花时间阅读这个问题,我可以在你的帮助下掌握这一点。

【问题讨论】:

  • 您正在实现接口,这意味着您通常只通过MyOnPropertyChanged_PublisherMethod(这是一个奇怪的名称)触发事件。订阅它的是事件的消费者。例如一个绑定。
  • 触发事件的方法通常称为 NotifyPropertyChanged 或 RaisePropertyChanged,并且应该只有一行:PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  • @Clemens 感谢您的回复,我很困惑的是,如果 MyOnPropertyChanged_PublisherMethod 是与事件 PropertyChanged 相关联的函数,那么我们不必按顺序执行 PropertyChanged+= MyOnPropertyChanged_PublisherMethod 之类的操作调用它,或者因为我在我的属性的设置器中调用它,所以在这种情况下我不必做 += 。我很困惑,因为我们在另一个示例中使用 += 将方法链接到事件而不是此处(EventDefinedInInterface += SubscriberMethodForConection),而不是在这个示例中。
  • 不,我们没有。如前所述,您不订阅生产者端的事件。您只能通过PropertyChanged?.Invoke 触发它。
  • @Clemens 我已经根据您关于名称和使用的建议更改了我的代码?运算符而不是 If else。同时,我还想问是否可以更改我的代码(第二个代码)以使用 += 而不是在属性设置器中调用事件绑定函数,前提是我想要相同的函数。如果您有任何来源,那就太好了,再次感谢您的回复:D

标签: c# wpf events delegates inotifypropertychanged


【解决方案1】:

我希望通过上面提供的描述和下面的代码,其他人也可以从中受益

MainWindow.xaml.cs

namespace UnderstandingINotifyPropertyChanged
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        Class1 Class1Object = new Class1();
        private string _FirstName;
        private string _FullName;
        private string _LastName;

        public string FirstName
        {
            get { return _FirstName; }
            set
            {
                if (_FirstName != value)
                {
                    _FirstName = value;
                    RaisePropertyChanged("FirstName");
                    RaisePropertyChanged("FullName");
                }
            }
        }
        public string LastName
        {
            get { return _LastName; }
            set
            {
                if (_LastName != value)
                {
                    _LastName = value;
                    RaisePropertyChanged("Lastname");
                    RaisePropertyChanged("FullName");
                }
            }
        }
        public string FullName
        {
            get { return _FullName = _FirstName + " " + _LastName; }

        }

        protected virtual void RaisePropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));           
        }
        Class1 ObjectOfClass1 = new Class1();

        public MainWindow()
        {
            InitializeComponent();
            FirstName = "Jeff";
            LastName = "Buckley";
            this.DataContext = this;
            PropertyChanged += ObjectOfClass1.MethodToBeTracked;
        }
    }

    public class Class1
    {
        public void MethodToBeTracked(object sender, PropertyChangedEventArgs e)
        {
            MessageBox.Show("propertychanged event fired due to change in property " + e);
        }
    }
}

用于在 WPF 中运行的 XAML

<Window x:Class="UnderstandingINotifyPropertyChanged.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UnderstandingINotifyPropertyChanged"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="400">
    <StackPanel HorizontalAlignment="Center" Margin="0,30,0,0">
        <StackPanel Orientation="Horizontal" Margin="10">
            <Label Content="First Name : "  />
            <!--<TextBox Width="200" VerticalContentAlignment="Center" Text="{Binding Path=FirstName,Mode=TwoWay,  UpdateSourceTrigger=PropertyChanged}"/>-->
            <TextBox Width="200" VerticalContentAlignment="Center" Text="{Binding Path=FirstName,Mode=TwoWay}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="10">
                <Label Content="Last Name : "  />
                <!--<TextBox Width="200" VerticalContentAlignment="Center" Text="{Binding LastName,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>-->
                <TextBox Width="200" VerticalContentAlignment="Center" Text="{Binding LastName,Mode=TwoWay}"/>
            </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="10">
            <Label Content="Full Name : "  />
            <!--<TextBox Width="200" VerticalContentAlignment="Center" Text="{Binding Path=FullName,Mode=TwoWay,  UpdateSourceTrigger=PropertyChanged}"/>-->
            <Label Width="200" VerticalContentAlignment="Center" Content="{Binding Path=FullName,Mode=OneWay}"/>
        </StackPanel>
    </StackPanel>
</Window>

【讨论】:

    【解决方案2】:

    简答。

    第一个代码示例在MainWindow.ctor() 中订阅EventDefinedInInterface,并在PublisherMethodForConnection 中引发它。

    第二个代码示例根本不订阅PropertyChanged。它只是在MyOnPropertyChanged_PublisherMethod 中引发了这个事件。

    长答案。

    通常,事件旨在通知外部订阅者有关对象内部发生的某些更改(属性已更改其值,视频已编码等)。

    虽然技术上您可以订阅自己的事件,但这通常没有意义。例如,如果MainWindow 实例想要做某事,当LastName 被更改时,它可以处理这个内部属性设置器或MyOnPropertyChanged_PublisherMethod 方法。无需订阅事件。

    因此,当您想要订阅某个对象的事件时,您必须使用+= 语法来添加您的事件处理程序。当您想引发事件时,通常会调用私有或受保护的方法,它们会执行此操作,但这不是事件处理/订阅。

    以下是在 C# 中实现事件之前需要阅读的三个链接:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-16
      • 1970-01-01
      • 1970-01-01
      • 2010-11-04
      • 2021-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多