【问题标题】:WPF Frame in separate thread?WPF框架在单独的线程中?
【发布时间】:2010-01-27 12:47:56
【问题描述】:

我有一个应用程序,当一个人键入或选择一个列表框时,屏幕的一部分会动态更新为新视图。

问题在于,由于 WPF 在单个线程中运行所有内容,因此视图的显示可能会干扰键入或导航,从而降低应用程序的响应速度。我想做的是在不同的线程中运行视图部分。

我的第一个想法是使用在不同线程上运行的窗口,但不仅仅是一个 hack,还有当单击主窗口时窗口失去焦点并被置于主窗口后面的问题。我可以把它放在最上面,但我还需要在它前面放置其他窗户。

那么实现这一点的最佳方法是什么,我可以将视图放在一个框架中并在不同的线程中运行它吗?

【问题讨论】:

    标签: wpf multithreading frame


    【解决方案1】:

    您可以在后台线程中加载/生成数据,然后使用 Dispatcher.BeginInvoke 更新 UI。

    【讨论】:

      【解决方案2】:

      我建议您使用要显示的这块屏幕的 Visibility 属性,并在用户键入或选择时使用触发器将其从“不可见”或“折叠”设置为“可见”。或者您可以为 Opacity 属性设置动画以产生很酷的淡入淡出效果;-) 我将添加一些代码来说明这一点。 编辑:一个耗时的后台任务,比如文件操作,可以使用BackgroundWorker来完成

      <Window x:Class="VisibleOnTypingSpike.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="Window1" Height="300" Width="300">
      <StackPanel>
          <StackPanel Orientation="Horizontal">
              <Label Name="TypingSnooper"
                     Visibility="{Binding TypingSnooperVisibility}">
                  You are typing!</Label>
              <Label>
                  <Label.Style>
                      <Style>
                          <Setter Property="Label.Opacity" Value="0"/>
                          <Style.Triggers>
                              <DataTrigger Binding="{Binding HasListBoxNewSelection}" Value="True">
                                  <DataTrigger.EnterActions>
                                      <BeginStoryboard >
                                          <Storyboard>
                                              <DoubleAnimation From="0" To="1"
                                                               Duration="0:0:1"
                                                               Storyboard.TargetProperty="Opacity"/>
                                          </Storyboard>
                                      </BeginStoryboard>
                                  </DataTrigger.EnterActions>
                                  <DataTrigger.ExitActions>
                                      <BeginStoryboard >
                                          <Storyboard>
                                              <DoubleAnimation From="1" To="0"
                                                               Duration="0:0:1"
                                                               Storyboard.TargetProperty="Opacity"/>
                                          </Storyboard>
                                      </BeginStoryboard>
                                  </DataTrigger.ExitActions>
                              </DataTrigger>
                          </Style.Triggers>
                      </Style>
                  </Label.Style>
                  You selected!
              </Label>
          </StackPanel>
          <TextBox TextChanged="TextBox_TextChanged"></TextBox>
          <ListBox Name="SimpleListBox"
                   SelectionChanged="SimpleListBox_SelectionChanged">
              <ListBoxItem>1</ListBoxItem>
              <ListBoxItem>2</ListBoxItem>
          </ListBox>
      </StackPanel>
      

          using System.Windows;
          using System.Windows.Controls;
      
      namespace VisibleOnTypingSpike
      {
          public partial class Window1 : Window
          {
              public Visibility TypingSnooperVisibility
              {
                  get { return (Visibility)GetValue(TypingSnooperVisibilityProperty); }
                  set { SetValue(TypingSnooperVisibilityProperty, value); }
              }
      
              public static readonly DependencyProperty TypingSnooperVisibilityProperty =
                  DependencyProperty.Register("TypingSnooperVisibility",
                                              typeof(Visibility),
                                              typeof(Window1),
                                              new UIPropertyMetadata(System.Windows.Visibility.Collapsed));
      
              public bool HasListBoxNewSelection
              {
                  get { return (bool)GetValue(HasListBoxNewSelectionProperty); }
                  set { SetValue(HasListBoxNewSelectionProperty, value); }
              }
      
              public static readonly DependencyProperty HasListBoxNewSelectionProperty =
                  DependencyProperty.Register("HasListBoxNewSelection",
                                              typeof(bool),
                                              typeof(Window1),
                                              new UIPropertyMetadata(false));
      
              public Window1()
              {
                  InitializeComponent();
                  DataContext = this;
              }
      
              private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
              {
                  var textbox = (TextBox) sender;
                  if (textbox.Text.Length > 0) TypingSnooperVisibility = Visibility.Visible;
                  else TypingSnooperVisibility = Visibility.Hidden;
              }
      
              private void SimpleListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
              {
                  HasListBoxNewSelection = true;
                  HasListBoxNewSelection = false;
              }
          }
      }
      

      【讨论】:

      • 恐怕仍然对线程问题没有帮助,问题是例如加载文档的单纯功能会在界面中产生“口吃”,我真的需要运行它在一个单独的线程中
      • 我还是添加了代码 ;-) 诸如加载文档之类的事情可以使用 BackgroundWorker 完成。我在上面的答案中包含了指向 msdn 的链接。 WPF 绝不允许同一 UI 的两个部分在单独的线程上运行。您必须在后台执行耗时的任务,然后通过事件通知 UI 新数据已准备就绪。
      • 当然可以,我可以将窗口层叠在一起,每个窗口都运行自己的线程,甚至是透明的。这有点骇人听闻,但它确实有效。我现在明白为什么框架不能在它自己的线程中运行的原因
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多