2016-10-26 14 views
0

メソッド呼び出しでプロパティ値を複数回更新しています。 私のUI要素はデータプロパティにバインドされていて、私のviewModelにはINotifyPropertychnagedが実装されています。 私は、UI値を更新するようにデータトリガーを設定しました。メソッド呼び出しの最後に最終的なプロパティ値が正しく動作します。しかし、メソッド呼び出し内のプロパティ値の変更に基づいてUIを更新したい。それを行う最善の方法は何ですか?背後にWPFデータトリガーとUIディスパッチャー

コード:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
OrderViewModel model = this.DataContext as OrderViewModel; 
model.OrderStatus = OrderViewModel.OrderStatuses.Updating; 

// Processing order logic 
// takes about few seconds, Here I want to update UI with Refreshing Icon inprogress.gif 

model.OrderStatus = OrderViewModel.OrderStatuses.Updated; 

} 

XAMLコード:

<Window.Resources> 
     <BitmapImage x:Key="NotCreatedSource" UriSource="/Images/notcreated_20x20.png" /> 

     <Style TargetType="Image" x:Key="OrderLineItem"> 
      <Setter Property="Source" Value="{StaticResource NotCreatedSource}" /> 
      <Setter Property="Height" Value="32" /> 
      <Setter Property="Width" Value="24" /> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding OrderStatus, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="Updated"> 
        <Setter Property="Source" Value="/Images/checkmark_icon.png" ></Setter> 
       </DataTrigger> 
       <DataTrigger Binding="{Binding OrderStatus, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="Updating"> 
        <Setter Property="Source" Value="/Images/inprogress.gif" ></Setter> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Window.Resources> 

    <StackPanel> 
     <StackPanel Margin="12,100,30,0" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top"> 
      <Image Style="{StaticResource OrderLineItem}" Name="ConnectionImage" /> 
     </StackPanel> 
     <Button Width="250" Height="25" Margin="20" Click="Button_Click">Change status</Button> 

    </StackPanel> 

モデルクラス:私は画像のアイコンを持っているそれらの2つの状態に基づいて

public class OrderViewModel : INotifyPropertyChanged 
    { 
     public OrderStatuses OrderStatus 
     { 
      get 
      { 
       return _orderstatus; 
      } 
      set 
      { 
       _orderstatus = value; 
       RaisePropertyChanged("OrderStatus"); 
      } 
     } 
     private OrderStatuses _orderstatus; 

     public event PropertyChangedEventHandler PropertyChanged; 
     public void RaisePropertyChanged(string propertyName) 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 

     public enum OrderStatuses 
     { 
      Updated = 1, 
      Updating, 
      NotCreated, 
      Failed, 
      NotAvailable 
     } 
    } 

とUIでコントロールを注文する横。それは更新のアイコンを表示しませんが、呼び出しの最後に更新されたことを示します。

UIで両方のステータスの更新を表示するにはどうすればよいですか?

+0

ロジックをviewmodelに移動して理解できないようにすることはできません。viewmodelでコマンドを使用し、これを表示します –

+0

viewmodelへの移行をお勧めしますか?私の必要性は、処理中にUI要素(画像)を更新することです。 – rocky

+1

すべてのコードは同じ優先順位で実行され、UIを再描画するコードが実行される前にすべてが実行されます。あなたが必要とするのはそれを解くことです。 OrderStatusをUpdatingに設定し、プロセスを実行するタスクを開始し、UIを更新してからタスクが完了したらOrderStatusをUpdatedに設定してUIの更新を再開します。通常、私はDispatcherやTask Parallel Libraryのようなものを使います。例については、[この回答](http://stackoverflow.com/questions/15926743/threading-and-collections-modification-in-wpf-c-sharp/15930792#15930792)を参照してください。 – Rachel

答えて

1

問題は、処理のためにUIスレッドをブロックしていて、WPFがレンダリングされないということです。一番早い解決策はVB6の古いApplication.DoEventsのようなものです:処理中にno-opデリゲートを使ってthis.Dispatcher.Invokeを定期的に呼び出してください。

コアの問題をやや改善していますが、処理と最終更新をラップして、代理人にthis.Dispatcher.BeginInvokeに渡します。これはややハッキリな続きです。

論理的にクリーンな方法は、タスク(またはスレッドまたはBackgroundWorkerまたは他の非同期API)を使用して処理をバックグラウンドに移動し、タスクの続行でステータス更新を完了することです。

OrderViewModel model = this.DataContext as OrderViewModel; 
model.OrderStatus = OrderViewModel.OrderStatuses.Updating; 

Task.Factory.StartNew(() => /* processing order logic */) 
    .ContinueWith(t => model.OrderStatus = OrderViewModel.OrderStatuses.Updated); 

あなたの.NET Frameworkのバージョンによっては、awaitの代わりContinueWithを使用することができます。

関連する問題