web-dev-qa-db-ja.com

別のスレッドが所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません、WPF

ソケットを介して接続されるハードウェアがありますが、

今、私はチェックボックスで示されているハードウェアが接続されているかどうかを5秒ごとに確認する必要があります

私は機能を実装しました:

private static System.Timers.Timer aTimer;
public MainWindow()
{
    InitializeComponent();
    client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
    aTimer = new System.Timers.Timer();
    aTimer.AutoReset = true;
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    aTimer.Interval = 2000;
    aTimer.Enabled = true;
}

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    if (client.Connected == true)
    {
        Console.WriteLine("Not Connected");
        CheckBox.IsChecked = false;
    }
    else
    {
        Console.WriteLine("Connected");
        CheckBox.IsChecked = false;
    }
}

しかし、アプリケーションを実行しているときにエラーがスローされます。

別のスレッドが所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません。

Dispatcher.Invokeについて調査し、学びましたが、それをコードに実装できませんでした。

15
Vivek Saurav

Ui elememtは、1つのUIスレッドからのみアクセスできます。 CheckBoxにはUIスレッドが必要で、タイマーは別のスレッドで実行されます。 Dispatcherを使用する簡単なコード

if (client.Connected == true)
{
    Dispatcher.Invoke(()=> {
        // Code causing the exception or requires UI thread access
        CheckBox.IsChecked =true;
    });
}

OR

if (client.Connected == true)
{
    Dispatcher.Invoke(new Action(()=> {
        // Code causing the exception or requires UI thread access
        CheckBox.IsChecked =true;
    }));
}

エラーを受け取った場合An object reference is required for the non-static field, method, or propertyその後、これを使用します

 Application.Current.Dispatcher.Invoke(() =>
 {
     // Code causing the exception or requires UI thread access
 });
30

何らかの理由でDispatcherを使用したくない場合は、SynchronizationContextを使用できます。それほど大きな違いはありませんが、WPF固有のクラスではないため、SynchronizationContextを使用する場合の罪悪感は軽減されます。

private static System.Timers.Timer aTimer;
private SynchronizationContext _uiContext = SynchronizationContext.Current;

public MainWindow()
{
    InitializeComponent();

    client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
    aTimer = new System.Timers.Timer();
    aTimer.AutoReset = true;
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    aTimer.Interval = 2000;
    aTimer.Enabled = true;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{

    _uiContext.Post(new SendOrPostCallback(new Action<object>(o => {
        if (client.Connected == true)
        {
            Console.WriteLine("Not Connected");
            CheckBox.IsChecked = false;
        }
        else
        {
            Console.WriteLine("Connected");
            CheckBox.IsChecked = false;
        }
    })), null);
}
5
Fayilt

これを試して:

System.Windows.Application.Current.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate
{
    // Update UI component here
    CheckBox.IsChecked = false;
});
2
Ramashankar