2

ここ数日間抱えていた問題をうまく説明できるデモを作成しました。

GenerateRandomInt() という名前の単一の public static メソッドを使用して、Data Supplierという名前の単純なクラスを作成しました。これは、時間がかかるプロセスをシミュレートするためのものです。前述のクラスのコードは次のとおりです。

class DataSupplier
    {
        public static int GenerateRandomInt()
        {
            Random rnd = new Random();
            Thread.Sleep(1000);
            return rnd.Next();
        }
    }

私の MainWindow シンプルには、 stackPanel1 という名前の StackPanel が埋め込まれた ScrollViewer とbutton1という名前のボタン (このための XAML を以下に示します) が含まれています。

<Window x:Class="ThreadingDemo.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>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="40" />
        </Grid.RowDefinitions>
        <ScrollViewer>
            <StackPanel Name="stackPanel1" />
        </ScrollViewer>
        <Button Grid.Row="1"
                Name="button1"
                Content="Generate 10 Labels"
                Click="button1_Click" />
    </Grid>
</Window>

私が達成したいのは、button1をクリックすると、静的なDataSupplier.GetRandomInt()メソッドを使用して乱数を表示する 10 個のラベルが生成されることです。ただし、個別に作成されるとすぐに、それらを 1 つずつ表示したいと考えています。私の MainWindow の分離コードを以下示します。

public partial class MainWindow : Window
    {
        private BackgroundWorker worker;

        public MainWindow()
        {
            InitializeComponent();

            worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button1.IsEnabled = true;
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            this.Dispatcher.Invoke((Action)(() =>
            {
                for (int i = 1; i <= 10; i++)
                {
                    //create a new label, and set it's content to a randomly generated number
                    Label lbl = new Label();
                    lbl.Content = DataSupplier.GenerateRandomInt();

                    //add this label to stackPanel1
                    stackPanel1.Children.Add(lbl);
                }
            }));
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            button1.IsEnabled = false;
            worker.RunWorkerAsync();
        }
    }

ただし、ランダムに生成された 10 個のラベルすべてが stackPanel1 に追加されるまで、視覚的には何も表示されません。

とにかく、これをプログラムして、各ラベルが作成されるたびに表示されるようにすることはできますか? また、UI の応答性を維持しながら?

4

4 に答える 4

0

代わりに BeginInvoke を使用してみてください。

for (int i = 1; i <= 10; i++)
  {
    string content = DataSupplier.GenerateRandomInt();
    this.Dispatcher.BeginInvoke((Action)(() =>
   {
     lbl.Content = content;
//create a new label, and set it's content to a randomly generated number
     Label lbl = new Label();  
    //add this label to stackPanel1
     stackPanel1.Children.Add(lbl);
                        }));
    Thread.Sleep(100);
  }

Invoke は同期的に実行されるため、呼び出しが実行されるとスレッドが戻り、代わりに BeginInvoke が非同期的に実行されます。バックグラウンド スレッドをしばらく中断するために、thread.sleep を追加しました。この場合、バックグラウンド スレッドによって行われるすべての作業は UI を更新することなので、UI は常にビジーです。

于 2013-09-10T08:36:43.510 に答える
0

進捗状況を報告してください。コードは次のようになります。

public partial class MainWindow : Window
{
    private BackgroundWorker worker;

    public MainWindow()
    {
        InitializeComponent();

        worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.ProgressChanged += worker_ProgressChanged;
        worker.WorkerReportsProgress = true;
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.Dispatcher.BeginInvoke((Action)(() =>
        {
            Label lbl = new Label();
            lbl.Content = e.ProgressPercentage;
            stackPanel1.Children.Add(lbl);
        }), DispatcherPriority.Background);
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        button1.IsEnabled = true;
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 1; i <= 10; i++)
        {
            worker.ReportProgress(DataSupplier.GenerateRandomInt());
        }
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        button1.IsEnabled = false;
        worker.RunWorkerAsync();
    }

    private int GenerateRandomInt(int i)
    {
        Thread.Sleep(1000);
        return i;
    }
}

class DataSupplier
{
    public static int GenerateRandomInt()
    {
        Random rnd = new Random();
        Thread.Sleep(1000);
        return rnd.Next();
    }
}
于 2013-09-10T10:05:36.750 に答える