在MainWindow中的代码块开始时异步更新TextBlock

时间:2015-08-14 10:13:50

标签: c# wpf multithreading xaml asynchronous

我有一个问题,我已经困扰了好几天,我已经尝试了所有选项,而我现在正在发布我自己的问题,以便找到你们的一些具体帮助。

我需要在代码块的开头更新一个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)来说明发生了什么。虚空本身NewProject位于MainWindow上,点击按钮即可调用。

有人可以让我知道我哪里出错了吗?我已经尝试了无数可能的解决方案,所以如果我回复你说我已经尝试过,请不要被冒犯。

问候,汤姆。

3 个答案:

答案 0 :(得分:0)

您正在使用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}"/>

答案 1 :(得分:0)

你还没有提到究竟是什么问题,但看看代码,我猜猜文本框只有在你的代码完成后才会显示“正在打开项目...”,如果AppStatus显示“就绪”正在做同样的事情。

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

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

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

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

答案 2 :(得分:0)

经过几天的痛苦,我设法让这个工作。我通过查看任务调度等来完全咆哮错误的树。相反,所需要的只是一个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。