WPF 数据触发器和 UI 调度程序

WPF Datatrigger and UI dispatcher

我在方法调用中多次更新 属性 值。 我的 UI 元素绑定到数据属性,我的 viewModel 实现了 INotifyPropertychnaged。 我将数据触发器设置为更新 UI 值。它适用于方法调用结束时的最终 属性 值。但是,我想根据方法调用中的 属性 值更改来刷新 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>

型号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
        }
    }

并且在 UI 中,基于这 2 个状态,我在命令控制旁边有图像图标。它从不显示更新图标,但在调用结束时显示已更新。

如何在 UI 上显示两种状态更新?

问题是您正在阻止 UI 线程进行处理,WPF 不会呈现。最骇人听闻的解决方法就像 VB6 中的旧 Application.DoEvents:在处理期间使用空操作委托定期调用 this.Dispatcher.Invoke

稍微好一点——但仍然回避了核心问题——将处理和最终更新包装在传递给 this.Dispatcher.BeginInvoke 的委托中。这是一个有点hacky的延续。

逻辑上干净的方法是通过 Task(或线程或 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