在ICommand操作期间更新标签

时间:2015-07-06 19:43:06

标签: c# wpf mvvm action icommand

在WPF中,使用MVVM设计,我创建了一个屏幕,用于在点击按钮时将大量日志加载到ListView。返回时,标签将更新以显示返回的日志数。这个过程有时需要一段时间。我们的DA正在优化过程中,但同时我需要进行以下更改以向用户表明搜索正在运行:

  1. 将鼠标显示为WaitCursor
  2. 更新标签文字以显示" 搜索... "。
  3. 我有一个实现ICommand的类,我WaitCursor正常工作。但是,在搜索运行时,我无法获得更新要显示的标签所需的行为。我目前的代码:

    MyScreen.xaml

    <Button 
        Name="DisplayButton"
        Content="Display Logs"
        Command="{Binding DisplayLogsCommand}"
        Margin="0,64,10,0"
        VerticalAlignment="Top"
        HorizontalAlignment="Right"
        Width="112"/>
    <Label 
        Content="{Binding LogsShowingText}"
        Margin="0,0,127,8"
        Foreground="#FF3C3B3B"
        HorizontalAlignment="Right"
        Width="145" Height="24"
        VerticalAlignment="Bottom"
        HorizontalContentAlignment="Right"
        FontSize="11"/>
    

    MyScreenVM.cs

    private Command displayLogsCommand;
    private string logShowingText;
    
    public Command DisplayLogsCommand
    {
      get
      {
        if (this.displayLogsCommand == null)
        {
          // Attempt 3 made here.
    
          bool useWaitCursor = true;
    
          Func<bool> canExecute = () => this.ValidateFields();
    
          Action execute = () =>
          {
            /*
             *  TODO: Update this.LogsShowingText to read "Searching..."
             */
    
            // Attempt 1 and 2 made here.
            LogEntry[] entries = this.ClientConnection.GetLogs();
    
            this.LogsShowingText = string.Format("Showing {0} Logs", entries.Length);
            this.FilteredEntries = new ObservableCollection<LogEntry>(entries);
          };
    
          this.displayLogsCommand = new Command(useWaitCursor, canExecute, execute);
        }
    
        return this.displayLogsCommand;
      }
    }
    
    public string LogsShowingText
    {
      get
      {
        return this.logsShowingText;
      }
      set
      {
        this.logsShowingText= value;
        OnPropertyChanged("LogsShowingText");
      }
    }
    

    到目前为止,结果和我相关的失败尝试如下:

    1. 返回日志后,Label只会读取&#34; 搜索... &#34;。

      Application.Current.Dispatcher.Invoke(new Action(() => this.LogsShowingText = "Searching..."));
      
    2. 返回日志后,Label只会读取&#34; 显示N个日志&#34;。

      this.LogsShowingText = string.Format("Searching...");
      
    3. 之前和 搜索期间,标签会读取&#34; 搜索... &#34;,然后<在返回日志后,标签显示&#34; 显示N个日志&#34;。与#2相同的代码,不同的位置。

    4. 据我所知,这可能与阻止用户界面直到操作完成有关,这清楚地解释了尝试1显示标签的最后一次排队更新,并尝试2显示标签的最后一次硬编码更新。尝试3几乎可以工作,但在用户单击按钮执行搜索之前,不应更新标签。我怎么能这样做?

1 个答案:

答案 0 :(得分:3)

由于这是一个昂贵的命令,意味着UI在处理时挂起,您应该将其转换为异步命令。

public Command DisplayLogsCommand
{
  get
  {
    if (this.displayLogsCommand == null)
    {
        bool useWaitCursor = true;
        Func<bool> canExecute = () => this.ValidateFields();

        Action execute = async () =>
        {
           this.LogsShowingText = "Searching";

          // Attempt 1 and 2 made here.
          LogEntry[] entries = await Task<LogEntry[]>.Run(() => this.ClientConnection.GetLogs());

          this.LogsShowingText = string.Format("Showing {0} Logs", entries.Length);
          this.FilteredEntries = new ObservableCollection<LogEntry>(entries);
       };

      this.displayLogsCommand = new Command(useWaitCursor, canExecute, execute);
    }

    return this.displayLogsCommand;
  }
}

通过使Action委托异步,您现在可以在Action内等待。这使您可以在Task中将调用包装到DataLayer并等待它。现在昂贵的操作正在运行UI线程,您的标签将在之前和之后正确更新。无需使用Dispatcher对更改进行编组。

仅当用户点击按钮执行命令时,才会更新标签。