I am updating a property value with in a method call multiple times. My UI elements are bound to data properties and my viewModel has INotifyPropertychnaged implemented. I have data triggers set to update UI values. It works fine for the final property value at the end of the method call. However, I want to refresh UI based on property value change within method call. What is the best way to do it?
Code Behind:
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 Code:
<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>
Model Class:
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
}
}
and in UI based on those 2 statuses I have Image icons next to order Control. It never shows Icon for Updating, But at the end of call it shows updated.
How do I show both statuses update on UI?
The problem is you're blocking the UI thread for processing and WPF won't render. The hackiest workaround is like the old Application.DoEvents
in VB6: periodically call this.Dispatcher.Invoke
with a no-op delegate during the processing.
Slightly better--but still sidestepping the core issue--is to wrap the processing and final update in a delegate passed to this.Dispatcher.BeginInvoke
. This is a somewhat hacky continuation.
A logically clean way is to move the processing to the background via a Task (or thread or BackgroundWorker or any other async API) and complete the status update in a task continuation.
OrderViewModel model = this.DataContext as OrderViewModel;
model.OrderStatus = OrderViewModel.OrderStatuses.Updating;
Task.Factory.StartNew(() => /* processing order logic */)
.ContinueWith(t => model.OrderStatus = OrderViewModel.OrderStatuses.Updated);
Depending on your .NET Framework version, you can use await
instead of ContinueWith
.