Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c#从另一个类中的另一个静态事件引发事件_C#_Events - Fatal编程技术网

c#从另一个类中的另一个静态事件引发事件

c#从另一个类中的另一个静态事件引发事件,c#,events,C#,Events,需要从其他类调用事件的帮助。 我有一个已声明事件的类: public class MxPBaseGridView : GridView { public event AddNewItemsToPopUpMenuEventHandler AddNewItemsToPopUpMenu; ... } 我需要从中调用事件的另一个类具有方法和“AddNewItemStoppOpMenuEventHandler”委托 public d

需要从其他类调用事件的帮助。 我有一个已声明事件的类:

     public class MxPBaseGridView : GridView
    {

        public event AddNewItemsToPopUpMenuEventHandler AddNewItemsToPopUpMenu;
          ...
    }
我需要从中调用事件的另一个类具有方法和“AddNewItemStoppOpMenuEventHandler”委托

    public delegate void AddNewItemsToPopUpMenuEventHandler(PopupMenuShowingEventArgs e);
    public static class GridViewUtils
{
public static void gridView_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e)
    {                     
        if (e.MenuType != DevExpress.XtraGrid.Views.Grid.GridMenuType.Row)
        {
           if (menu != null)
            {               
                if (sender is MxPBaseAdvBandedGridView)
                {
                    MxPBaseAdvBandedGridView currentGrid = sender as MxPBaseAdvBandedGridView;

...

                    currentGrid.AddNewItemsToPopUpMenu();
                    if (currentGrid.AddNewItemsToPopUpMenu != null) //there i need to call event
                        currentGrid.AddNewItemsToPopUpMenu(e); // how you understand it doesn't work 
                }

那么,做相同工作的正确方法是什么呢?

您只能在定义事件的类中调用事件。常见的是使用特定的方法触发事件,必须将其添加到定义事件的类中。在您的例子中,在类MxPBaseGridView中。添加以下内容:

public void OnAddNewItemsToPopUpMenu(<eventargstype> e) {
    var addNewItemsToPopUpMenu = AddNewItemsToPopUpMenu;
    if (addNewItemsToPopUpMenu != null)
        addNewItemsToPopUpMenu(this, e);
}
ADDNewItemStopOppMenu(e)上的公共无效{ var addNewItemsToPopUpMenu=addNewItemsToPopUpMenu; if(addNewItemStopOppMenu!=null) addNewItemsToPopUpMenu(这个,e); } 注意:我不确定eventargs类型是什么,所以我将其保留为打开状态

然后可以从静态方法调用此方法

注:通常情况下,我定义On。。。方法作为私有的,如果需要,作为受保护的。在本例中,我将其定义为public,因为您需要从类外调用它。

C#中的事件是一种有趣的事情。它们非常类似于自动属性,但有一个私有get方法和一个公共(或您选择的任何访问)set方法

请允许我示范一下。让我们用假设事件创建一个假设类

class SomeObject{
    public event EventHandler SomeEvent;

    public void DoSomeStuff(){
        OnSomeEvent(EventArgs.Empty);
    )

    protected virtual void OnSomeEvent(EventArgs e){
        var handler = SomeEvent;
        if(handler != null)
            handler(this, e);
    }
}
此类遵循公开事件的类的典型模式。它公开事件,但有一个受保护的虚拟“On…”方法,默认情况下,该方法只调用事件(如果它有任何子服务器)。此受保护的虚拟方法不仅封装了实际调用事件的逻辑,而且为派生类提供了一种方法:

  • 以较少的开销方便地处理事件
  • 在所有外部订阅服务器接收事件之前或之后执行一些处理
  • 调用完全不同的事件,或
  • 完全抑制事件
但是这个叫做SomeEvent的“事件”对象是什么?在C#中,我们熟悉字段、属性和方法,但事件到底是什么

在我们开始之前,它帮助我们认识到C#中实际上只有两种类型的类成员:字段和方法。属性和事件或多或少只是这些之上的语法糖

属性实际上是一个或两个方法,以及存储在元数据中的名称,C#编译器允许您使用该名称引用这两个方法之一。也就是说,当您定义这样的属性时:

public string SomeProperty{
    get{return "I like pie!";}
    set{
        if(string.Compare(value, "pie", StringComparison.OrdinalIgnoreCase) == 0)
            Console.WriteLine("Pie is yummy!");
        else Console.WriteLine("\"{0}\" isn't pie!", value ?? "<null>");
    }
}
编译器查找分配给
SomeProperty
的getter和setter方法,并将代码转换为:

string foo = someObject.get_SomeProperty();
someObject.set_SomeProperty(foo);
这就是为什么如果定义了一个带有公共字段的类,但后来决定将其更改为属性,以便在读取或写入该类时可以执行一些有趣的操作,则必须重新编译包含对此成员的引用的任何外部程序集,因为字段访问指令需要改为方法调用指令

现在这个属性有些不正常,因为它不依赖任何支持字段。它的getter返回一个常量值,而setter不将其值存储在任何地方。很明显,这是完全正确的,但大多数情况下,我们对属性的定义更像这样:

var foo = someObject.SomeProperty;
someObject.SomeProperty = foo;
string someProperty;

public string SomeProperty{get{return someProperty;}set{someProperty = value;}}
string someProperty;

public string SomeProperty{get{return someProperty;}}
public event EventHandler SomeEvent;
void Awe_SomeEventHandler(object sender, EventArgs e){}

void SomeMethod(SomeObject Awe){
    Awe.SomeEvent += Awe_SomeEventHandler
    Awe.SomeEvent -= Awe_SomeEventHandler
}
此属性除了对字段执行读写操作外,不执行任何操作。它与名为
SomeProperty
的公共字段几乎相同,只是您可以在以后向getter和setter添加逻辑,而无需重新编译类的使用者。但这种模式非常普遍,以至于C#3添加了“自动属性”以实现相同的效果:

public string SomeProperty{get;set;}
编译器将其转换为与我们上面编写的代码相同的代码,只是支持字段有一个只有编译器知道的超级机密名称,因此我们只能在代码中引用该属性,即使在类本身中也是如此

因为我们无法访问备份字段,而您可能具有如下只读属性:

var foo = someObject.SomeProperty;
someObject.SomeProperty = foo;
string someProperty;

public string SomeProperty{get{return someProperty;}set{someProperty = value;}}
string someProperty;

public string SomeProperty{get{return someProperty;}}
public event EventHandler SomeEvent;
void Awe_SomeEventHandler(object sender, EventArgs e){}

void SomeMethod(SomeObject Awe){
    Awe.SomeEvent += Awe_SomeEventHandler
    Awe.SomeEvent -= Awe_SomeEventHandler
}
您几乎永远不会看到只读的自动属性(编译器允许您编写它们,但您会发现它们几乎没有什么用处):

相反,您通常会看到:

public string SomeProperty{get;private set;}
附加到
set
private
访问修饰符使类内的方法可以设置属性,但该属性在类外仍显示为只读

你可能会问:“现在这些和事件有什么关系?”。事实上,事件很像一个自动属性。通常,当您声明一个事件时,编译器会生成一个超级机密支持字段和一对方法。除了支持字段不是超级机密,这对方法不是“get”和“set”,它们是“add”和“remove”。让我示范一下

当您编写这样的事件时:

var foo = someObject.SomeProperty;
someObject.SomeProperty = foo;
string someProperty;

public string SomeProperty{get{return someProperty;}set{someProperty = value;}}
string someProperty;

public string SomeProperty{get{return someProperty;}}
public event EventHandler SomeEvent;
void Awe_SomeEventHandler(object sender, EventArgs e){}

void SomeMethod(SomeObject Awe){
    Awe.SomeEvent += Awe_SomeEventHandler
    Awe.SomeEvent -= Awe_SomeEventHandler
}
编译器编写的是:

EventHandler SomeEvent;

public void add_SomeEvent(EventHandler value){
    SomeEvent = (EventHandler)Delegate.Combine(SomeEvent, value);
}
public void remove_SomeEvent(EventHandler value){
    SomeEvent = (EventHandler)Delegate.Remove(SomeEvent, value);
}
它还添加了一些元数据粘合剂,以便以后编写类似这样的代码时:

var foo = someObject.SomeProperty;
someObject.SomeProperty = foo;
string someProperty;

public string SomeProperty{get{return someProperty;}set{someProperty = value;}}
string someProperty;

public string SomeProperty{get{return someProperty;}}
public event EventHandler SomeEvent;
void Awe_SomeEventHandler(object sender, EventArgs e){}

void SomeMethod(SomeObject Awe){
    Awe.SomeEvent += Awe_SomeEventHandler
    Awe.SomeEvent -= Awe_SomeEventHandler
}
编译器将其重写为(仅有趣的行):

这里需要注意的是,与
SomeEvent
相关的唯一可公开访问的成员是那些add和remove方法,这些方法在使用
+=
-=
操作符时被调用。支持字段,即名为SomeEvent的委托对象,包含事件的订阅者,是一个只有声明类的成员才能访问的私有字段

但是,就像自动属性只是手工编写backing字段和getter与setter的快捷方式一样,您也可以显式声明委托并添加和删除方法:

internal EventHandler someEvent;

public event EventHandler SomeEvent{
    add{someEvent = (EventHandler)Delegate.Combine(someEvent, value);}
    remove{someEvent = (EventHandler)Delegate.Remove(someEvent, value);}
}
然后,程序集中的其他类可以触发事件:

var handler = Awe.someEvent;
if(handler != null)
    handler(Awe, EventArgs.Empty);
但是,以正常(自动)方式定义事件更容易、更习惯,只需公开一个“Raise”方法:

但现在你有希望了解为什么你必须这样做,以及英国广播公司发生了什么