另一个类中的方法在调用类时调用一个事件?

时间:2011-06-01 12:37:22

标签: c# events windows-phone-7 delegates

我需要开始下载一些html,所以我在另一个类中调用void GetHTML。当它完成后,我想传递它应该在调用类中引发的事件。我怎么能这样做?

所以它看起来像这样:

public class Stuff
{
    public void GetHTML(string url, event to raise here)
    {
       //Do stuff then raise event
    }
}
public class Other
{
    public Other()
    {
        Stuff stuff = new Stuff();
        stuff.GetHTML(someUrl, somehow sending info that HTML_Done should be called);
    }
    void HTML_Done(string result, Event e)
    {
         //Do stuff with the result since it's done
    }
}

我意识到我不清楚自己想做什么,我很乐意填写任何缺失的部分。

感谢您的任何建议!

5 个答案:

答案 0 :(得分:12)

  

活动订阅和通知

public class Stuff
{
    // Public Event to allow other classes to subscribe to.
    public event EventHandler GetHtmlDone = delegate { };

    public void GetHTML(string url)
    {
        //Do stuff

        // Raise Event, which triggers all method subscribed to it!
        this.GetHtmlDone(this, new EventArgs());
    }
}

public class Other
{
    public Other()
    {
        Stuff stuff = new Stuff();

        // Subscribe to the event.
        stuff.GetHtmlDone += new EventHandler(OnGetHtmlDone);

        // Execute
        stuff.GetHTML("someUrl");
    }

    void OnGetHtmlDone(object sender, EventArgs e)
    {
        //Do stuff with the result since it's done
    }
}

使用此模式可以允许更多订阅者。

您也不会将通知程序Stuff类与调用者Other类绑定。

您是否拥有订阅者,与Stuff类没有区别。

Stuff类不应该知道订阅者,它应该仅仅提出它为订阅公开的事件。

修改
正如 ctacke 在评论中正确指出的那样,如果没有人订阅,则使用this.GetHtmlDone(this, new EventArgs());引发事件会导致异常。
我更改了上面的代码,以确保通过初始化我的事件处理程序来始终安全地引发事件 因为我一直在使用它(通过提高它)我确信始终初始化你正在使用的东西是一个好习惯。

我本可以在事件处理程序上添加一个空检查,但在我个人意见中,我不同意必须由stuff类负责。我觉得应该总是提出这个事件,因为它是“负责任”的事情。

我在SO上发现了这个thread哪种情况向我证实这样做似乎没有错。

此外,我还对该代码运行代码分析,以确保我没有通过初始化EventHandler来破坏CA1805规则。没有引发CA1805,也没有违反任何规则。

在评论中使用我的汽车类比,我认为不会初始化事件处理程序并一直提高它会比说“当你在车里转弯时只使用你的指示器,如果有人正在观看,如果没有,请” “打扰”。你永远不知道是否有人在看,所以你不妨确保你总是这样做。

这只是我个人的偏好。如果您喜欢这样做,请随时添加!= null检查。

非常感谢您对 ctacke 的评论以及指出这一点。我从中学到了很多东西 我现在必须回到我的一些项目并更新一些代码,以确保如果没有人订阅我的事件,我的库就不会崩溃。在我的任何测试中,我都感觉很傻。

答案 1 :(得分:5)

我不确定这是否是您所追求的,但您可以使用内置的Action委托类型:

public class Stuff
{
  public void GetHTML(string url, Action<string, Event> callback)
  {
     //Do stuff 

     //raise event
     callback("result here", new Event());       
  }
}

stuff.GetHTML(someUrl, HTML_Done);

或者,使用standard event patternEventHandler<T>委托类型。您需要创建自己的EventArgs类型。

答案 2 :(得分:1)

你想要一个回调。

public class Stuff
{
    public void GetHTML(string url, Action callback)
    {
       // Do stuff

       // signal we're done 
       callback();
    }
}

public class Other
{
    public Other()
    {
        Stuff stuff = new Stuff();

        // using a lambda callback
        stuff.GetHTML(someUrl, ()=> Console.WriteLine("Done!") );
        // passing a function directly
        stuff.GetHTML(someUrl, MyCallback);
    }

    public void MyCallback() 
    {
        Console.WriteLine("Done!");
    }
}

如果要传递参数,请相应地定义Action,即; Action<string>,然后回调变为callback("some string")

您拥有的另一个选择是使用事件。当你问这个问题时,看起来这就是你的目标。我不推荐它,回调选项是更好的IMO。但是,为了将来参考,这就是你在这种情况下使用事件的方式。

public delegate void DoneEventHandler(object sender, string result);

public class Stuff
{
    public event DoneEventHandler DoneEvent = delegate {}; // avoid null check later

    public void GetHtml(string url)
    {
        // do stuff
        DoneEvent(this, "result");
    }
}

public class Other
{
    public void SomeMethod()
    {
        Stuff stuff = new Stuff();
        stuff.DoneEvent += OnDone;
        stuff.GetHtml(someUrl)
    }

    public void OnDone(objects sender, string result)
    {
        Console.WriteLine(result);
    }
}

有关如何使用Events in C#的信息。

答案 3 :(得分:0)

如果我不理解你错了。我想你应该这样试试

public class Stuff 
{
     public void GetHTML(string url, event to raise here)
     {
        //Do stuff  and instead of raising event here
     }
 } 
public class Other
 {
     public Other()
     {
         Stuff stuff = new Stuff();
         stuff.GetHTML(someUrl, somehow sending info that HTML_Done should be called);
         //Raise event here once that method is finished
     }
     void HTML_Done(string result, Event e)
     {
          //Do stuff with the result since it's done
     }
 } 

答案 4 :(得分:0)


你可以尝试这种方法


public class Stuff
{
     public delegate void DownloadComplete("you can pass whatever info you like here");
     public event DownloadComplete OnDownloadComplete;
     public void GetHtml(string UrlToDownload)
     {
         //Download the data here
         //After data download complete
         if(OnDownloadComplete)
            OnDownloadComplete("arguments to be passed");
     }

} public class Other { public Other() { Stuff myStuff=new Stuff(); myStuff.OnDownloadComplete+=new EventHandler(myStuff_OnDownloadComplete); }

 void myStuff_OnDownloadComplete("arguments will be passed here")
 {
    //Do your stuff
 }

}