【问题标题】:I am trying to raise event at UserControl, and catch it at Main program, But the event always return null我试图在 UserControl 引发事件,并在主程序中捕获它,但事件总是返回 null
【发布时间】:2015-05-02 02:34:16
【问题描述】:

我试图在 userControl 类之一中引发事件,并在 Main 类中触发它。我尝试了两种不同的方式来触发这个事件,其中一种有效,但我仍然想知道为什么其他方式不能工作,以及如何解决它。

我的 userContol 类:

public partial class UserControl1 : UserControl
{

    public UserControl1()
    {
        InitializeComponent();
        if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
        {
            return;
        }
        Class1 c = new Class1();

        Thread accept = new Thread(
                     () =>
                     {
                         c.connection();

                     }

                     );
        accept.Start();

    }

}

还有 Class1:

   public class Class1
{
   public delegate void myhandler(object sender, EventArgs e);
   public event myhandler test;

   public Class1()
   {

   }
   public void connection()
   {
       test(this, new EventArgs());
   }


}

在 Main 中,我只是简单地添加到所指对象中,然后添加

 xmlns:my="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"

然后我尝试在 main 中订阅此事件

public partial class SurfaceWindow1 : SurfaceWindow
{
    /// <summary>
    /// Default constructor.
    /// </summary>
    public SurfaceWindow1()
    {
        InitializeComponent();
        Class1 c = new Class1();
        c.test+=new Class1.myhandler(c_test);
        // Add handlers for window availability events
        AddWindowAvailabilityHandlers();
    }
    public void c_test(object sender, EventArgs e)
    {
        MessageBox.Show("fire");
        }
}

如果我只在线程中引发这个事件,它工作正常,但如果我尝试让它在这个线程中引发,这个测试事件只返回 null,并显示:

Object reference not set to an instance of an object.

看起来我从来没有订阅过。那么如果我必须在线程中使用它,如何修复它。

【问题讨论】:

    标签: c# wpf multithreading user-controls event-handling


    【解决方案1】:

    这是您真正不应该做的事情的一个很好的例子。您正在尝试订阅由另一个类“拥有”的类的事件。您基本上是在挖掘类型层次结构以找到您想要的事件。这违背了良好的设计。

    特别是在 UI 应用程序中,有一个设计概念叫做事件冒泡。拥有引发事件的原始对象的类型处理该事件。在处理该事件时,它会引发自己的重复事件。这是一个展示这个概念的简短程序:

    public class RootEventClass
    {
        public event EventHandler SomeKindOfEvent;
    
        protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
        {
            EventHandler handler = SomeKindOfEvent;
            if (handler != null)
                handler(this, e);
        }
    
        public void RaiseEvent()
        {
            Console.WriteLine("Root Event Firing");
            OnSomeKindOfEvent(this, EventArgs.Empty);
        }
    }
    
    public class FirstOwnerClass
    {
        private RootEventClass _rootClass;
        public event EventHandler SomeKindOfEvent;
    
        public FirstOwnerClass()
        {
            _rootClass = new RootEventClass();
            _rootClass.SomeKindOfEvent += _rootClass_SomeKindOfEvent;
        }
    
        void _rootClass_SomeKindOfEvent(object sender, EventArgs e)
        {
            Console.WriteLine("First Owner Class Handling Root Owner Event");
            OnSomeKindOfEvent(this, e);
        }
    
        protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
        {
            EventHandler handler = SomeKindOfEvent;
            if (handler != null)
                handler(this, e);
        }
    
        public void RaiseEvent()
        {
            _rootClass.RaiseEvent();
        }
    }
    
    public class SecondOwnerClass
    {
        private FirstOwnerClass _firstClass;
        public event EventHandler SomeKindOfEvent;
    
        public SecondOwnerClass()
        {
            _firstClass = new FirstOwnerClass();
            _firstClass.SomeKindOfEvent +=_firstClass_SomeKindOfEvent;
        }
    
        void _firstClass_SomeKindOfEvent(object sender, EventArgs e)
        {
            Console.WriteLine("Second Owner Class Handling First Owner Event");
            OnSomeKindOfEvent(this, e);
        }
    
        protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
        {
            EventHandler handler = SomeKindOfEvent;
            if (handler != null)
                handler(this, e);
        }
    
        public void RaiseEvent()
        {
            _firstClass.RaiseEvent();
        }
    }
    
    public class Program
    {
        public static void Main(string[] args)
        {
            SecondOwnerClass secondOwner = new SecondOwnerClass();
            secondOwner.SomeKindOfEvent += secondOwner_SomeKindOfEvent;
    
            secondOwner.RaiseEvent();
    
            Console.ReadKey(true);
        }
    
        static void secondOwner_SomeKindOfEvent(object sender, EventArgs e)
        {
            Console.WriteLine("Got an event from the second owner defined in main");
        }
    }
    

    如果你运行这个程序,你会得到如下输出:

    根事件触发 第一个所有者类处理根所有者事件 第二个所有者类处理第一个所有者事件 从 main 中定义的第二个所有者那里获得了一个事件

    那么这里发生了什么。 Main 方法定义了一个 SecondOwner 对象,然后告诉它引发一个事件,这只是将所有权链传递给根对象。神奇的是事件冒泡。该事件被每个拥有的类拦截并传递。这样它就可以决定是否传递它。

    另外,Main 方法只需要知道在SecondOwner 类中创建的事件,它不必挖掘SecondOwnerFirstOwner 和最后的RootEventClass

    这是一个很容易掌握的概念,不要强迫您的用户(或您自己)挖掘类型和所有权来获取事件,如果该类的用户需要该事件,请复制该事件并将其冒泡。

    【讨论】:

    • 在哪里提出并不重要,具体提出的程度在很大程度上取决于您的代码。您的示例使用了许多默认类名,其意图难以理解。
    • 因为我的项目比较大,这里只写基本架构来提问。无论如何,我希望我能很好地理解你的代码,然后自己弄清楚
    • 归结为您的 UserControl 类应该定义一个与您拥有的 Class1 类相同的事件。您以与您相同的方式引发它,但在 UserControl 类中处理它并引发 UserControl 事件。
    • 你能用代码编辑吗?我还是很困惑。因为我知道我的问题之一是我创建了两个不同的实例,所以我的事件返回 null。如何首先解决这个问题?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-31
    相关资源
    最近更新 更多