让一个类'inform'需要更改的另一个类(Events?)

本文关键字:另一个 Events inform 一个 | 更新日期: 2023-09-27 18:18:35

好了,我一直在网站和谷歌上搜索,但我不太明白委派和事件处理程序之类的东西需要在哪里,所以希望这里有人能帮助/解释我需要做什么。

所以,我写一个简单的数据库应用程序(使用SQLite)。有一个主窗体,它是MDI父窗体(它基本上是一个顶部有菜单的大窗口)。菜单启动其他窗口,允许查看、编辑和插入数据库的各种表。

其中一个窗口是LOG窗口,它显示我的日志表。

目前,如果用户在显示TABLE中的数据的窗口中更改了某些内容。该操作还写入日志表。但是,如果日志窗口打开,则日志视图不会更新。

所以,我发现我可能需要从我的TABLE UPDATE代码中"触发"一个事件,我的LOG窗口"订阅"(所以它可以更新DataGridView)。

我不知道的是这个事件的不同"部分"去了哪里。

MdiParent应该有public delegate void EventHandler();吗?如果不是,在哪里?

哪个类获得public static event EventHandler logGoneStale; ?

唯一的位我相当肯定的是,显示日志的窗口(它有一个方法称为公共无效UpdateLogDataGridView() -它调用数据库对象/方法(重新)填充datagridview)需要有:

里面有logGoneStale += new EventHandler(UpdateLogDataGridView);之类的。这至少是对的吧?

完全困惑-似乎没有一个事件的例子/教程在MSDN试图做我想要实现的。

让一个类'inform'需要更改的另一个类(Events?)

您需要在发送事件的类中定义一个event,并在应该接收事件的类中附加一个事件处理程序。为了使事情简单一点,从c# 3.5开始,您可以完全忘记delegate关键字,而使用lambda表达式作为事件处理程序。还要注意,在大多数情况下,将事件设置为static是没有意义的,因为事件通常由实例触发,而不是由触发。

的例子:

class SendsEvent
{
    public event EventHandler MyEvent;
    public void FireEvent()
    {
        if(MyEvent != null) // MyEvent is null if no handlers have been attached
        {
            MyEvent(this, new EventArgs()); // event fired here
        }
    }
}
class ReceivesEvent
{
    private SendsEvent eventSource;
    public ReceivesEvent(SendsEvent eventSource)
    {
        this.eventSource = eventSource;
        // Attach event handler - can be a lambda expression
        // or method with signature 
        // "void HandleEvent(object sender, EventArgs e)"
        this.eventSource.MyEvent += (sender, args) =>
        {
            // do something when event was fired
            Console.Out.WriteLine("Hello. Event was fired.");
        };
    }
}
class Program
{
    public static void Main()
    {
        var eventSource = new SendsEvent();
        var eventReceiver = new ReceivesEvent(eventSource);
        eventSource.FireEvent(); 
    }
}

处理事件需要同时拥有事件发布者和事件订阅者。

@chris' s 答案是正确的

此外,您需要在您想要通知的操作发生的最近点上引发事件。

例如,实现INotifyPropertyChanged接口

public class Customer : INotifyPropertyChanged {
    public string Name { get; set; }
    public string Address {
        get { return address; }
        set {
            address = value;
            if (thereArePropertyChangedEventSubcribers()) 
                raisePropertyChangedEventFor("Address");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void raisePropertyChangedEventFor(string propertyName) {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    private bool thereArePropertyChangedEventSubcribers() { 
        return PropertyChanged != null; 
    }
    private string address;
}

所以这里,Customer类允许发布它的地址更改。因此,每当有人对地址更改时的通知感兴趣时,它就像这样订阅事件:

Customer.PropertyChanged += new PropertyChangedEventHandler(customerPropertyChanged);

或者像这样:

Customer.PropertyChanged += customerPropertyChanged;

你甚至可能已经注意到,地址最近的改变点是在它实际改变后直接发生的。唯一的要求是用作事件处理程序的方法具有与事件本身相同的签名。如果您看一下PropertyChangedEventHandler委托,您可能会注意到它的签名等待一个object作为第一个参数,即触发事件的对象,以及一个PropertyChangedEventArgs实例来通知已更改的属性。

回到您的示例,您希望无论何时将日志插入到底层数据库中,都能被注意到,以便可能出现log窗口的刷新。当你想要使用事件时,有两个问题需要回答。

  • 我的出版商应该是什么?
  • 我的订户应该是什么?

我的出版商应该是什么?

MdiParent应该有public delegate void EventHandler();吗?

简短的回答:不!

If not where?

事件声明最适合发布者。如果您有一个负责日志记录的类,那么public delegate void EventHandler();应该驻留在这里,因为它负责在有订阅者时引发事件。

每当成功插入一条日志时,它应通知任何有兴趣知道新日志条目的订阅者。

public class Log {
    public void UpdateLog(string description) {
        // insert the new Log line into your database.
        if (thereIsAtLeastOneNewLogEntryAddedSubscriber())
            raiseTheNewLogEntryAddedEvent();
    }
    public event EventHandler NewLogEntryAdded;
    private raiseTheNewLogEntryAddedEvent() {
        NewLogEntryAdded(this, EventArgs.Empty);
    }
    private bool thereIsAtLeastOneNewLogEntryAddedSubscriber() {
        return NewLogEntryAdded != null;
    }
}

我的订户应该是什么?

这个问题可以通过另一个问题来回答:

  • 当事件触发时,您需要做什么?

在您的案例中,您希望在打开日志窗口时更新日志窗口。

我唯一可以合理确定的是,显示日志的窗口(它有一个名为public void UpdateLogDataGridView()的方法-它调用数据库对象/方法(重新)填充datagridview)需要有:

里面有logGoneStale += new EventHandler(UpdateLogDataGridView);之类的东西。这至少是对的吧?

是的,你是对的!= D

您实际上订阅了每行的事件。因此,它告诉应用程序,显示日志的窗口有兴趣了解数据库中的日志更改。

public class WindowThatDisplaysTheLog : Form {
    public WindowThatDisplaysTheLog() { 
        InitializeComponent(); 
        log = new Log();
        log.NewLogEntryAdded += UpdateLogDataGridView;
    }
    private void UpdateLogDataGridView(object sender, EventArgs e) {
        // Reload your Log entries from the underlying database.
        // You now shall see the LogDataGridView updating itself 
        // whenever a new log entry is inserted.
    }
    
    private Log log;
}