简体   繁体   English

如何在WPF中长时间运行的UI进程之前(和之后)更新UI?

[英]How to update UI before (and after) long running UI process in WPF?

I apologize if this is a duplicate, but I have not been able to find a question with a similar situation. 抱歉,如果这是重复的,则无法找到类似情况的问题。 If this is a duplicate please provide a link. 如果重复,请提供链接。

I would like to show a "Loading..." overlay in my WPF application, when I am dynamically creating a lot of tabs. 当我动态创建许多选项卡时,我想在WPF应用程序中显示一个“正在加载...”叠加层。 The overlay visibility is bound to a property called "ShowIsLoadingOverlay". 叠加层可见性绑定到名为“ ShowIsLoadingOverlay”的属性。 However, the overlay is never shown. 但是,从不显示叠加层。

Due to the fact that the tabs are visual elements I can't move the creation into a BackgroundWorker. 由于选项卡是可视元素,因此无法将创建的内容移至BackgroundWorker。

I have created a small prototype trying to explain the situation. 我创建了一个小的原型来解释这种情况。 This is the xaml: 这是xaml:

<Window x:Class="WpfApplication5.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Label HorizontalAlignment="Center" VerticalAlignment="Center" 
               Visibility="{Binding ShowIsLoadingOverlay, Converter={StaticResource BooleanToVisibilityConverter}}" 
               Content="Loading..." />

        <Button Grid.Row="1" Content="Load" Click="Button_Click" />
    </Grid>
</Window>

And this is the code behind: 这是背后的代码:

public partial class MainWindow : Window, INotifyPropertyChanged
{
   private bool m_ShowIsLoadingOverlay;
   public bool ShowIsLoadingOverlay
   {
      get
      {
         return m_ShowIsLoadingOverlay;
      }
      set
      {
         if ( m_ShowIsLoadingOverlay == value )
         {
            return;
         }

         m_ShowIsLoadingOverlay = value;
         NotifyPropertyChanged( "ShowIsLoadingOverlay" );
      }
   }

   public MainWindow()
   {
      InitializeComponent();

      DataContext = this;
   }

   private void Button_Click( object sender, RoutedEventArgs e )
   {
      ShowIsLoadingOverlay = true;

      CreateTabs();

      ShowIsLoadingOverlay = false;
   }

   private void CreateTabs()
   {
      // Simulate long running process to create tabs
      Thread.Sleep( 3000 );
   }

   // Implementation of INotifyPropertyChanged has been left out.
}

The problem is that the overlay is never shown. 问题在于该覆盖图从未显示。 I know that it has something to do with the UI not updated correctly before and after the ShowIsLoadingOverlay property has changed. 我知道与ShowIsLoadingOverlay属性更改前后未正确更新的UI有关。 And I believe it also has something to do with the lack of using the dispatcher. 我认为这也与缺乏使用调度程序有关。

I have tried many, many combinations of Dispatcher.Invoke, Dispatcher.BeginInvoke surrounding when changing the property and/or surrounding the CreateTabs call. 我尝试了更改属性和/或围绕CreateTabs调用时围绕Dispatcher.Invoke,Dispatcher.BeginInvoke的许多组合。 And I have tried changing the DispatcherPriority to "force" the overlay to show before starting to create the tabs. 而且,我尝试将DispatcherPriority更改为“强制”叠加层以在开始创建选项卡之前显示。 But I just can't make it work... 但是我只是无法使其工作...

Could you please tell me how to accomplish this task? 您能告诉我如何完成这项任务吗? And more importantly; 更重要的是 provide an explanation, because I do not get this. 提供一个解释,因为我不明白这一点。

In advance, thank you. 预先谢谢你。

Best regards, Casper Korshøj 最好的问候,CasperKorshøj

You cannot manipulate UI controls in a background thread. 您不能在后台线程中操纵UI控件。 If you are using the main UI thread to create your TabItem s, then you also cannot have a 'Busy' or 'Loading' indicator... this will only work if you are using a alternative thread for your long running process. 如果您使用主UI线程创建TabItem ,那么您也将没有“忙碌”或“正在加载”指示符... 当您在长时间运行的过程中使用备用线程时,这才起作用。 This is because your 'Busy' indicator will only become updated once the long running process has completed if it runs on the same UI thread. 这是因为如果长时间运行的进程在同一UI线程上运行,则“忙碌”指示器将仅在其完成后才更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM