2017-02-18 7 views
-1

私は、TCPストリームを介してデータを受け取り、解析し、それに従ってプロパティを変更するクラスを持っているとします。WPFは変数の変更を待ってからUIを更新します

public static class SomeClass 
{ 
    static bool myBool; 
    static string myMessage; 

    public static void ToggleBool() 
    { 
     myBool = !myBool; 
     // Do some other stuff here 
    } 

    public static UpdateMessage(string message) 
    { 
     System.Diagnostics.Debug.WriteLine(message); 
     ProcessMessage(message); 
     myMessage = message; 
    } 
} 

ここで私がしたいことは、設定を視覚的に表示する「デバッグウィンドウ」を持つことです。基本的にウィンドウの一部を更新するループを実行します。

ような何か:

public partial class LogWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    public Async Task UpdateUI() 
    { 
     while(checkForUpdates) 
     { 
      myCheckbox.IsChecked = await SomeClass.UpdatedBoolValue(); 

      string newMessage = await SomeClass.NewMessageRCVD(); 
      txtBox.Append(newMessage); 
     } 
    } 
} 

しかし、それは2つの明らかに問題があります。 1つは、私はどのように私は常にループをチェックしてCPUを燃やさない関数を作るだろうか分からない。私はgetter/setterアプローチを使うことができると思います。 2つ、私は再びそのループを実行するために両方を更新する必要があります。

これにはどのような方法が最適ですか?更新する必要があるUIの部分だけを更新するにはどうすればよいですか?

EDIT:同様の質問:Write an Async method that will await a bool

+0

タイマーを使用して、特定のインターバル内のすべての値を更新します。 – CSharpie

+0

Caliburn MicroまたはReactiveUIを使用する場合は、これらの問題を完全に解決するアプリ内メッセージディスパッチ用のいくつかのpub-sub実装があります。 –

答えて

0

これを行う最善の方法はデータバインディングです。

私たちのデータがどこから来ているのかを最初に定義する必要があります。これはコンテキストと呼ばれます。これは、MVVM用語であるViewModelから来る予定です。あなたがMVVMを認識していない場合、心配する必要はありません、これはちょうどあなたが持っているどのクラスから来ることができます。バックエンドの.xaml.csコードでは、ウィンドウのDataContextにクラスを追加する必要があります。ここではそれは次のようになります。

public partial class DebugView : Window 
{ 
    public DebugView() 
    { 
     InitializeComponent(); 
     DataContext = new DebugViewModel(); 
    } 
} 

そして、我々はそのように定義されたラベルとテキストボックスを持っていますウィンドウの私たちのWPFのXAMLファイルで:

<Label Content="{Binding ClientCount, FallbackValue='Clients: 00'}" ... /> 
<TextBox Text="{Binding Port, UpdateSourceTrigger=PropertyChanged}" ... /> 

ラベルのテキストは、それが "だですテキストボックスのテキストは単なる「テキスト」です。そこにbindingキーワードを追加すると、それぞれのテキストは変数ClientCountPortにリンクしています。だから、私たちのDebugViewModelクラスが最初で、次のようになります。

private string _ClientCount; 
    public string ClientCount 
    { 
     get { return _ClientCount; } 
     set { _ClientCount= value; RaisePropertyChanged("ClientCount"); } 
    } 
    private string _Port; 
    public string Port 
    { 
     get { return _Port; } 
     set { _Port= value; RaisePropertyChanged("Port"); } 
    } 

今、あなたは機能は、私がやったのでRaisePropertyChanged()と呼ばれていない(と私は一般的な方法だと思う)私はINotifyPropertyChangedを実装基本クラスを作りましたそこのすべての作業を処理します。

BaseViewModelという基本クラスはINotifyPropertyChangedクラスから継承し、私たちのためにすべてをセットアップします。それはちょうど、この(ちょうどペーストをコピーしているように使用して自由に感じる)のようになります。

using System.ComponentModel; 

public class BaseViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    internal void RaisePropertyChanged(string prop) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop)); 
    } 

    // Other functions we want all ViewModels to have 
} 

ので、その後、私たちのDebugViewModelクラスには、次のようになります。あなたがプログラムを起動し、その後

public class ServerViewModel : BaseViewModel 
{ 
    private string _ClientCount; 
    public string ClientCount 
    { 
     get { return _ClientCount; } 
     set { _ClientCount= value; RaisePropertyChanged("ClientCount"); } 
    } 
    private string _Port; 
    public string Port 
    { 
     get { return _Port; } 
     set { _Port= value; RaisePropertyChanged("Port"); } 
    } 

    public DebugViewModel() 
    { 
     // Initialize to default values 
     ClientCount = $"Clients {server.clientCount}"; 
     Port = $"{server.port}"; 
    } 

    // Rest of code 
} 

とをフィールドを自動入力し、テキストボックス内のデータを変更すると文字列が変更され、その逆もあります。 XAML宣言のUpdateSourceTrigger=PropertyChanged部分は、テキストボックスのデータが変更されるとすぐに変数が更新されるようにします(デフォルトの動作は、テキストボックスがフォーカスを失ったとき、たとえば次のテキストボックスに移動するときやクリックしたときです)。

これは、タイプされた入力を動的に検証することができるだけでなく、UIスレッドに切り替えてUIを更新することを心配する必要がなく、IMOによってコードが簡単に見えるようになります。

0

は、実装/あなたのニーズはどのように複雑に依存します。

SomeClassにINotifyPropertyChangedを実装した場合、WPFウィンドウを簡単にアタッチすることができ、バインディングを使用すると、ループのないフォームが自動的に更新されます。

複数のクラスについて話していて、すべてのクラスにプロパティ情報を同じウィンドウに表示させたい場合は、おそらくキューを作成するのがベストでしょう。あなたが追跡したい各プロパティでは、セッターはキューに書き込みます。 (グローバルまたはシングルトン)次に、その情報をウィンドウで簡単に前に表示するか、Observer patternで複数の情報を簡単に表示できます。本番環境のキューに書き込まないように設定することもできますし、条件付きコンパイル文を使用しても、それがあなたの望みであれば、コードを作成することさえできません。

+0

ありがとう!それを見つけ出し、他の人が手伝ってくれるようにいくつかのサンプルコードで回答をタイプアップしましたが、ここでも良い情報があります。 –

関連する問題