问题描述:

Is the Dispatcher an object that you can pass in C#? I have one thread that calls another thread. The second thread gives me this error when I try to do Dispatcher.CheckAccess():

An object reference is requied for the non-static field, method or property 'System.Windows.Threading.Dispatcher.CheckAccess()'.

So I try to create a dispatcher object in the original class and pass it to the second class, but the program doesn't like that and crashes.

The code has the general structure:

public public partial class MainView : UserControl{

public myButtonClick(Event eventObj, Session session)

{

//does some stuff and invokes Dispatcher.CheckAccess()

secondClass.startProcess(passThruString);

}

}

public class SecondClass

{

public startProcess(string passThru){

//does some other stuff and calls Dispatcher.CheckAccess() which throws error

}

}

I have corrected the error by replacing Dispatcher.CheckAccess() with Dispatcher.Currentdispatcher.CheckAccess(), but why can't I just create a dispatcher object?

网友答案:

A dispatcher can be passed around just like any other object in C#. However, a dispatcher can't be constructed because the constructor is made private:

var dispatcher = new Dispatcher(); //compile error

To pass a dispatcher around, you need to get some other already existing dispatcher. One option (as you noted in your updated question) is to use Dispatcher.CurrentDispatcher:

var dispatcher = Dispatcher.CurrentDispatcher;
SomeFunction(dispatcher);

This creates a reference to Dispatcher.CurrentDispatcher which can be stored and passed around.

In one of my own projects, I use a dispatcher to avoid errors like "The calling thread cannot access this object because a different thread owns it". This is because in this particular class I have, it is possible for a background thread to attempt to do an operation on an object created on the UI thread. I am guessing you have a similar issue.

Here is a minimal example of how I use it:

public class SomeClass
{
  private readonly Dispatcher _dispatcher;

  public SomeClass()
  {
    _dispatcher = Dispatcher.CurrentDispatcher;
  }

  public void SomeOperation()
  {
    InvokeIfNeeded(() => Console.WriteLine("Something"));
  }

  private void InvokeIfNeeded(Action action)
  {
    if (_dispatcher.Thread != Thread.CurrentThread)
      _dispatcher.Invoke(action);
    else
      action();
  }
}

This may not be the best way to use Dispatchers, but it demonstrates how you can store a reference to it as a field, just like other objects in C#.

网友答案:

As the error message says, to call CheckAccess() you need an instance of Dispatcher on the left side of the dot. For example, a code like this would work:

Dispatcher dispatcher = /* something here */;
dispatcher.CheckAccess();

This explains why simply writing Dispatcher.CheckAccess() in SecondClass doesn't work. But then why does it work in MainView? Because it inherits from UserControl, which has a property called Dispatcher. So, when you write Dispatcher.CheckAccess() there, it's basically a shorter way of writing:

UserControl control = this;
control.Dispatcher.CheckAccess();

Ok, so now you should understand why MainView works and why SecondClass doesn't. The only question that remains: how to make SecondClass work? What you need to do is to get access to an instance of Dispatcher. But to answer that, I need to ask a question of you: Why are you trying to call CheckAccess()?

Generally, you should do this when you want to call a method on a Dispatcher-bound object and you don't know if you're on the right thread for that. But if you're in that situation, you don't need a Dispatcher, you need the Dispatcher that's associated with the object you're trying to access. And to get that, you should use the Dispatcher property of that object (the same property that caused the confusion above).

If you're doing something else, the answer might be different, but it's hard for me to guess what that would be.

相关阅读:
Top