简体   繁体   中英

How to make an eventlistener in a UI thread to listen to an event from another UI thread started from the first thread?

I have tried to look for a solution to this problem for some time, but nothing I've found solves my problem.

I have two UI threads, Window A and Window B, in a single instance application where B is created and started from A. When I try to add an event listener in the A to listen for when B is visible or not, I get an NullReferenceException in System.Threading.Tasks.dll with the note " Object reference not set to an instance of an object. ". I have tried to use a Dispatcher without any luck. Here is a mock up of my code (both classes are in the same namespace):

public partial class A : Window 
{
    private B _b;
    private Thread _bThread;
    private Dispatcher _bDispatcher;

    public A ()
    {
        InitializeComponent();

        _bThread = new Thread(() => 
        {
            try
            {
                _bDispatcher = Dispatcher.CurrentDispatcher;
                _b = new B();
                Dispatcher.Run();
            }
            catch (Exception ex)
            {
                Logger.Log(ex.message);
            }
        });
        _bThread.SetApartmentState(ApartmentState.STA);
        _bThread.Start();

       _b.VisibleChanged+= _b_VisibleChanged; // <= if this line is removed the program can start, but with this line I get the exception and the program crasches..
    }

    private void _b_VisibleChanged(object sender, EventArgs e)
    {
        // change margin values on A..
    }
}



public partial class B : Window
{

    private static EventHandlerList Events = new EventHandlerList();
    private static readonly object EventVisibleChanged = new object();

    public B () 
    {
        InitializeComponent();
        // other stuff
    }

    private void Window_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        TriggerOnVisibleChanged();
    }

    #region Triggers

    private void TriggerOnVisibleChanged()
    {
        ((EventHandler<EventArgs>)Events[EventVisibleChanged])?.Invoke(this, null);
    }

    #endregion

    #region Event add/remove handlers

    public event EventHandler<EventArgs> VisibleChanged
    {
        add
        {
            Events.AddHandler(EventVisibleChanged, value);
        }
        remove
        {
            Events.RemoveHandler(EventVisibleChanged, value);
        }
    }

    #endregion
}

I don't know what I am doing wrong and I don't know how to make this work, can someone help me?

PS. this is for wpf, not Forms.. DS.

PS2. I know I did not have to create my own event and trigger and could just have used the IsVisibleChanged event in window B, but I have tried that with the same result..DS.

I don't believe what you want is possible as WPF uses an 'apartment' model that adheres to thread affinity, ie threads cannot interact with each other.

Furthermore, you may be falling into this trap more tightly... as it says in the article "WPF objects that have thread affinity derive from the Dispatcher object."

See here for more information on threading in WPF

EDIT: Why do it in multiple threads? Perhaps what you are looking for is the RoutedEventHandler (defined in the child window)... see this SO post for an example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM