在主窗口的代码块开始时异步更新TextBlock

本文关键字:开始时 异步 更新 TextBlock 代码 窗口 | 更新日期: 2023-09-27 18:07:59

我有一个问题已经困扰我好几天了,我已经尝试了每一个选项,我现在的结果是张贴我自己的问题,从你们那里找到一些具体的帮助。

我需要更新一个TextBlock在代码块的开始,这是运行在一个简单的按钮点击。

下面是我的代码:

private void NewProject(bool blnCopy = false, string strFileName = null)
    {
      if (App.ApplicationBusy == false)
      {
        App.ApplicationBusy = true;
        try
        {
          Action action = delegate()
          {
            Cursor = Cursors.Wait;
            lblStatus.Text = "Opening Project...";
          };
          Dispatcher.Invoke(DispatcherPriority.Send, action);
          if (blnCopy == false) { Project = new GSProject((App.RecentProjectCount + 1)); }
          if (Project != null)
          {
            Projects.Add(Project);
            if (blnCopy == false)
            {
              if (strFileName == null)
              {
                Project.ProjectName = string.Format("GSProject{0}", Projects.Count.ToString());
                Project.ProjectDescription = string.Format("{0} - HW GS Project", Project.ProjectName);
                Project.LoadResource();
              }
              else
              {
                Project.Load(strFileName);
              }
            }
            else
            {
              Project = Project.Copy();
            }
            p_objNewPane = objDocker.AddDocument(Project.ProjectDisplayName, Project);
            if (p_objNewPane != null)
            {
              p_objNewPane.DataContext = Project;
              BindingOperations.SetBinding(p_objNewPane, ContentPane.HeaderProperty, new Binding("ProjectDisplayName") { Source = Project });
              p_objNewPane.Closing += new EventHandler<PaneClosingEventArgs>(ContentPane_Closing);
            }
            if (Project.CalculationExists == true)
            {
              InitializeCalculation(true);
            }
          }
          tabStartPage.Visibility = Visibility.Collapsed;
          objDocumentTabs.SelectedIndex = 0;
        }
        catch (Exception ex)
        {
          ModernDialog.ShowMessage(string.Format("An error has occurred:{0}{0}{1}", Environment.NewLine, ex.Message), "Error", MessageBoxButton.OK, Application.Current.MainWindow);
        }
        finally
        {
          App.ApplicationBusy = false;
          Cursor = Cursors.Arrow;
          AppStatus = "Ready";
          p_objNewPane = null;
        }
      }
    }

在try块的开始,我需要更新TextBlock (lblStatus)来说明发生了什么。void本身,NewProject,在主窗口上,通过点击按钮调用。

谁能告诉我我哪里错了?我已经尝试了无数种可能的解决方案,所以如果我回复你说我已经尝试过了,请不要生气。

问候,汤姆。

在主窗口的代码块开始时异步更新TextBlock

经过几天的痛苦,我终于把它修好了。通过查看任务调度等,我完全搞错了方向。相反,所需要的只是一个DependencyProperty。

XAML(主窗口):

    <TextBlock x:Name="lblStatus"
           Text="{Binding AppStatus, IsAsync=True}"
           Grid.Column="0"
           HorizontalAlignment="Left"
           VerticalAlignment="Center"
           FontFamily="Segoe UI"
           FontSize="12"
           Foreground="White"
           Margin="5, 0, 0, 0" />

c#(主窗口):

public string AppStatus
    {
      get { return (string)GetValue(AppStatusProperty); }
      set { SetValue(AppStatusProperty, value); }
    }
    public static readonly DependencyProperty AppStatusProperty =
        DependencyProperty.Register("AppStatus", typeof(string), typeof(MainWindow), new PropertyMetadata(null));
public void StatusBarUpdate(string strMainMessage)
    {
      Dispatcher.BeginInvoke((Action)(() => { AppStatus = strMainMessage; }));
    }

我可以在任何时候调用StatusBarUpdate方法,它将异步更新UI。

您正在使用WPF,因此实现

INotifyPropertyChanged 

,并使用正确的数据绑定。

private void NotifyPropertyChanged(String info)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}
public string StatusText
{
    get {return this.m_statusText;}
    set
    {
        if (value != this.m_statusText)
        {
            this.m_statusText= value;
            NotifyPropertyChanged("StatusText");
        }
    }
}

和XAML

<TextBox Text="{Binding Path=StatusText}"/>

你还没有提到到底是什么问题,但看看代码,我可以猜测文本框显示"打开项目…"只有在你的代码完成后或显示"准备好",如果AppStatus正在做同样的事情。

如果是,问题是你在UI线程上做所有的事情。虽然您更改了文本框的文本,但它将在您的工作完成后呈现,因此出现了问题。要解决这个问题,需要在工作线程上运行从if (blnCopy == false)objDocumentTabs.SelectedIndex = 0;的代码。这将解决你的问题。

您可以使用TPL,也可以使用.ContinueWithTaskScheduler.FromCurrentSynchronizationContextTaskContinuationOptions.OnlyOnRanToCompletion来执行finally块。

编辑:由于您不使用MVVM,因此需要大量的Invoke才能使代码正常工作。正如我所看到的p_objNewPane也是一个UI元素,就像Project是一个视图属性一样,很难将所有这些转换为TPL。你可以让p_objNewPane = ...的代码保持原样(即外部工作线程)。这似乎不是非常cpu密集,除了InitializeCalculation,你可以在另一个工作线程中运行。

更好的方法是使用await/async方法来等待所有繁重的方法。