1

ユーザーに計算のステータスと進行状況を通知するために、計算集約型のメソッドを使用してオブジェクトから UI にメッセージを渡す方法を実装したいと考えています。これを実行している間、UI は応答性を維持する必要があります。つまり、計算は別のスレッドで実行されます。デリゲート、バックグラウンド ワーカーなどについて読んだことがありますが、非常にわかりにくく、アプリケーションに実装できませんでした。これは、私のアプリケーションと同じ一般的な考え方を持つ単純化されたアプリケーションです。UI のテキスト ボックスは、計算量の多いメソッドが完了した後に更新されます。

<Window x:Class="UpdateTxtBox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="UpdateTxtBox" Height="350" Width="525">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
    </Grid.ColumnDefinitions>
    <Button Content="Start" Height="23" HorizontalAlignment="Left" Margin="94,112,0,0" Name="btnStart" VerticalAlignment="Top" Width="75" Click="btnStart_Click" />
    <TextBox Grid.Column="1" HorizontalAlignment="Stretch"  Margin="0,0,0,0" Name="txtBox" VerticalAlignment="Stretch" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible" />
</Grid>

namespace UpdateTxtBox
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            MyTextProducer txtProducer = new MyTextProducer();
            txtProducer.ProduceText();
            txtBox.Text = txtProducer.myText;
        }
    }
}

計算集約型クラス:

namespace UpdateTxtBox
{
    public class MyTextProducer
    {
        public string myText { get; private set; }

        public MyTextProducer()
        {
            myText = string.Empty;
        }

        public void ProduceText()
        {
            string txt;

            for (int i = 0; i < 10; i++)
            {
                txt = string.Format("This is line number {0}", i.ToString());
                AddText(txt);
                Thread.Sleep(1000);
            }
        }

        private void AddText(string txt)
        {
            myText += txt + Environment.NewLine;
        }
    }
}

AddText メソッドが呼び出されるたびにテキスト ボックスが更新されるように、このコードを変更するにはどうすればよいでしょうか。

4

2 に答える 2

2

ここでの基本的な問題は、UI スレッドで計算負荷の高い操作を行っているため、UI がロックされることです (ご自身でおわかりのように)。これに対する解決策は、別のスレッドを開始してから、そこから UI を更新することです。しかし、UI スレッドのみが UI の更新を許可されているという問題に直面します。Dispatcherこれは、この面倒なことをすべて処理するクラスを使用することで解決されます。

これは、Dispatcher とその使用方法に関する素晴らしい肉付きの良い記事です: http://msdn.microsoft.com/en-us/magazine/cc163328.aspx

遅延/遅いタスクでこの種の UI 更新を処理する方法は他にもあることに注意してください。

于 2012-07-23T12:35:04.123 に答える
1

WPFを使用しているので、データバインディングを使用することをお勧めします。コードの実装例を次に示します。

<Window x:Class="UpdateTxtBox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="UpdateTxtBox" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <Button Content="Start" Height="23" HorizontalAlignment="Left" Margin="94,112,0,0" Name="btnStart" VerticalAlignment="Top" Width="75" Click="btnStart_Click" />
        <TextBox Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="txtBox" VerticalAlignment="Stretch" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible" Text="{Binding Path=myText}" />
    </Grid>
</Window>

テキストボックスのContentプロパティがデータバインドされていることに注意してください。

public partial class MainWindow : Window
{
    MyTextProducer txtProducer;

    public MainWindow()
    {
        InitializeComponent();

        txtProducer = new MyTextProducer();
        this.DataContext = txtProducer;
    }

    private void btnStart_Click(object sender, RoutedEventArgs e)
    {
        Task.Factory.StartNew(txtProducer.ProduceText);
        txtBox.Text = txtProducer.myText;
    }
}

行に注意してくださいthis.DataContext = txtProducer。これは、値を探す場所をバインディングに指示する方法です。

public class MyTextProducer : INotifyPropertyChanged
{
    private string _myText;
    public string myText { get { return _myText; } set { _myText = value; RaisePropertyChanged("myText"); } }

    public MyTextProducer()
    {
        myText = string.Empty;
    }

    public void ProduceText()
    {
        string txt;

        for (int i = 0; i < 10; i++)
        {
            txt = string.Format("This is line number {0}", i.ToString());
            AddText(txt);
            Thread.Sleep(1000);
        }
    }

    private void AddText(string txt)
    {
        myText += txt + Environment.NewLine;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
}

MyTextProducerを実装するINotifyPropertyChangedようになったため、プロパティへの変更myTextは自動的にUIに反映されます。

于 2012-07-23T12:44:03.890 に答える