1

プログラムロジックの実行中にBackgroundWorkerにUIを更新させようとしています。しかし、エラーが発生します:

編集!したがって、提供したサンプルからは明らかではないと思いますが、実際の目標は、UIを更新しながら計算を実行できるようにすることです。以下の更新されたコードサンプルを参照してください。

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

私のC#とxamlは次のとおりです。

public partial class MainWindow : Window
{
    private readonly BackgroundWorker worker = new BackgroundWorker();

    public MainWindow()
    {
        InitializeComponent();

        worker.DoWork += worker_DoWork;
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        test.Background = Brushes.Orange;

        for (double x = 0; x < 10000000000; )
        {
            x++;
        }

        test.Background = Brushes.Red;
    }

    private void test_Click(object sender, RoutedEventArgs e)
    {
        worker.RunWorkerAsync();
    }
}

そして、私のXAML:

<Button Name="test" Click="test_Click">This is a button!</Button>
4

7 に答える 7

2

バックグラウンドスレッドからユーザーインターフェイスオブジェクトに直接アクセスすることはできません。これらはすでにUIスレッドで実行されているため、(を介してDispatcher.Invoke)呼び出しをUIスレッドにマーシャリングするか、の進行状況または完了イベント内で更新を行う必要があります。BackgroundWorker

とはいえ、この場合、BWはUIを更新するだけなので、他に実行する「作業」がないため、Buttonのイベントハンドラーで直接更新する必要があります。

于 2012-09-07T18:24:54.657 に答える
2

これを試して

void worker_DoWork(object sender, DoWorkEventArgs e)
{
   Dispatcher.BeginInvoke(new Action(() => { test.Background = Brushes.Orange; }));
}

UIディスパッチャーから実行する必要があります。

于 2012-09-07T18:47:58.797 に答える
1

バックグラウンドスレッドからUIの更新を行うことはできません。RunWorkerCompletedまたはイベントのいずれかを使用してProgressChanged、UIを更新します。

worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    test.Background = Brushes.Orange;
}
于 2012-09-07T18:24:17.517 に答える
1

前にアプリをロックしました。これを試してください。

void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (double x = 0; x < 10000000000; )
        {
            x++;
        }
    }


    private void test_Click(object sender, RoutedEventArgs e)
    {
        test.Background = Brushes.Orange;

        worker.RunWorkerCompleted += (_,__) =>  test.Background = Brushes.Red; 
        worker.RunWorkerAsync();

    }
于 2012-09-07T19:42:07.013 に答える
0

これは、BackgroundWorkerのRunWorkerCompletedイベントで行う必要があります。このイベントでは、ディスパッチャーと、その2つの主要なメソッドの1つであるInvokeとBeginInvokeを使用する必要があります。

于 2012-09-07T18:28:35.663 に答える
0

これはどのコードでも機能します。

void CodeToExcecute()
{
        test.Background = Brushes.Orange;

        for (double x = 0; x < 10000000000; )
        {
            x++;
        }

        test.Background = Brushes.Red;

}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
   Dispatcher.BeginInvoke(new Action(() => CodeToExcecute() ));
}
于 2012-09-07T19:30:44.737 に答える
0

私は他のコードを試し、調査を行いました。そうです、SynchronizationContextを使用して別のスレッドからビューを変更する方法があります。

この例を参照してください。

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var sync = SynchronizationContext.Current;
            BackgroundWorker w = new BackgroundWorker();
            w.DoWork+=(_, __)=>
                {
                    //sync.Post(p => { button.Content = "Working"; }, null);
                    int j = 0;
                    for (int i = 0; i < 10; i++)
                    {
                        j++;
                        sync.Post(p => { button.Content = j.ToString(); }, null);
                        Thread.Sleep(1000);
                    }
                    sync.Post(p => { button.Background = Brushes.Aqua; button.Content = "Some Content"; }, null);
                };
            w.RunWorkerAsync();
        }

そしてこれは見解です:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button x:Name="button" Content="Some Content" Click="Button_Click"/>
    </Grid>
</Window>

このコードは、ビュー(この場合はボタン)を数回更新します。これで最初の質問は解決すると思います。

于 2012-10-02T15:37:01.313 に答える