我该怎么做才能避免在WinForms应用程序中的多个类中声明事件处理程序名称

时间:2018-06-17 13:31:56

标签: c# winforms event-handling mvp

我正在使用Model View Presenter模式处理WinForms应用程序。每次我声明要在View中引发的事件处理程序时,我最终也会在我的Presenter类中声明它,因为它必须处理该事件。

    // Code in the View Class:
//Note: Here is the declaration I am duplicating in every class that 
//handles the raising of the event (i.e. ProductSaveButtonEventRaised)

public event EventHandler ProductSaveButtonEventRaised;

private void SaveBtn_Click(object sender, EventArgs e)
{
  if (ProductSaveButtonEventRaised!= null) //Check if any subscribed )
      {
        ProductSaveButtonEventRaised(this, eventArgs); // Notify all subscribers
      }
}

// Code in the Presenter Class:
// Note: Here the EventHandler declaration (ProductSaveButtonEventRaised)
// is repeated same as in the View. Is there another way to do this
// Other than duplicating the declaration in every class that needs to
// handle the event?:

public event EventHandler ProductSaveButtonEventRaised;

private void SubscribeEvents()
{
  _view.ProductSaveButtonEventRaised += new EventHandler(OnProductSaveButtonEventRaised);
}


private void OnProductSaveButtonEventRaised(object sender, EventArgs e)
{
//Event is raised again from the Presenter so it is forwarded to another
//Presenter which is the class that created this Presenter

  if (ProductSaveButtonEventRaised!= null) //Check if any subscribed )
      {
        ProductSaveButtonEventRaised(this, eventArgs); // Notify all subscribers
      }
}

除了为两个类创建某种类的父类以共享和继承事件声明之外,我还能做什么呢?我不会多次声明事件处理程序来覆盖需要处理事件的类由观点提出?

2 个答案:

答案 0 :(得分:0)

我有一个解决方案。但我肯定会建议你继续做你正在做的事情而不是替代(我已经创造了) - 因为它是更清晰的代码。

这个答案只是为了说明如何做到这一点。 我已经编写了这个例子,因此它可能看起来不太真实

答案:

你可以拥有一个保存和引发事件的Base类,View和Presenter类都可以继承这个类(如果你的任何一个视图或presenter类已经继承了其他类,你就无法实现下面的逻辑)

public class BaseEventClass
{
  public string Name;
  public event EventHandler ProductSaveButtonEventRaised;
  public void RaiseAnEvent(BaseEventClass thisObj)
  {
    if (ProductSaveButtonEventRaised != null)
    {
        ProductSaveButtonEventRaised(thisObj, EventArgs.Empty);
    }
  }
}

public class ViewClass : BaseEventClass
{
  public void LogicWhichRaiseAnEvent(string name)
  {
    Name = name;
    base.RaiseAnEvent(this);
  }
}

public class PresenterClass : BaseEventClass
{
  public void LogicWhichRaiseAnEvent(string name)
  {
    Name = name;
    base.RaiseAnEvent(this);
  }
}

以及引发事件和听力事件的调用逻辑将如下所示。

public static void Main()
{
    ViewClass v = new ViewClass();
    v.ProductSaveButtonEventRaised += ViewEventHandler;
    v.LogicWhichRaiseAnEvent("view");

    PresenterClass p = new PresenterClass();
    p.ProductSaveButtonEventRaised += PresenterEventHandler;
    p.LogicWhichRaiseAnEvent("presenter");
}

static void ViewEventHandler(object sender, EventArgs e)
{
    Console.WriteLine(((ViewClass)sender).Name);
}
static void PresenterEventHandler(object sender, EventArgs e)
{
    Console.WriteLine(((PresenterClass)sender).Name);
}

旁注:这里我在Base类中创建了Name属性,因此通过查看Name属性,您可以确定该事件已正确引发。

答案 1 :(得分:0)

您面临的问题是事件与常规对象不同。您不能将它们传递给其他类来订阅它们,也不能将它们公开为属性。但是,您可以使用Reactive Extensions将它们变为可观察的,以便可以。对于这样的用例,它是designed

要显示这些功能,请参见以下示例:

public class View
{
    public event EventHandler ProductSaveButtonEventRaised; 
}

public class Presenter
{
    // Obervables are first class citizens, meaning you can pass them around or expose them as a property
    public IObservable<EventPattern<EventArgs>> ProductSavedEvents { get; private set;}             

    public Presenter(View view)
    {
        // Turn a regular event into an Observable
        ProductSavedEvents = Observable.FromEventPattern<EventHandler, EventArgs>(
                h => view.ProductSaveButtonEventRaised += h,
                h => view.ProductSaveButtonEventRaised -= h);
    }
}

public class PresenterCreator
{
    Presenter presenter = new Presenter(new View());

    public void Subscribe()
    {
        // Act on a save button event
        presenter.ProductSavedEvents.Subscribe(@event => Console.WriteLine(@event));

        var otherConsumer = new OtherConsumer(presenter.ProductSavedEvents);
    }
}

public class OtherConsumer
{
    // You can pass observables just like any other object. Can't do that with events
    public OtherConsumer(IObservable<EventPattern<EventArgs>> ProductSavedEvents)
    {
        // Act on a save button event
        ProductSavedEvents.Subscribe(@event => Console.WriteLine(@event));
    }
}