【问题标题】:WPF Startup Screen like BlendWPF 启动屏幕,如 Blend
【发布时间】:2010-01-20 21:06:02
【问题描述】:

我们的 WPF 主窗口(“主窗口”)需要花费大量时间来创建(它使用类似于 Visual Studio 的功能区和停靠面板)。就像在 Blend 中一样,第一个动作总是选择一个现有项目来处理或创建一个新项目。因此,我们希望尽快显示此“选择项目”窗口并在后台创建沉重的“主窗口”(在用户单击“选择项目”窗口上的确定之前不可见)。

构建此启动方案的最佳方式是什么,最好使用 2 个 WPF 窗口(一个用于项目选择,一个用于主控件)?

我知道this sample 演示了如何在应用程序启动后立即加载 Win32 窗口,但我更喜欢仅 WPF 的解决方案。

另一个潜在的解决方案是使用multiple WPF UI threads,但是生命周期管理和窗口到窗口的通信并非易事。

问题:

与简单地创建“主窗口”而不实现“选择项目”窗口相比,在实现 2 WPF 窗口解决方案时,我能否看到更快的启动时间(假设我可以找到一个处理窗口生命周期的实现)?

是否应该在主应用程序线程上创建“选择项目”窗口,而在后台线程上创建“主窗口”(反之亦然)?

如果我需要使用 Win32 启动窗口来提高速度,我将如何将用户选择的项目名称传达给主 WPF 应用程序窗口

有谁知道 Blend 实际是如何实现他们的启动窗口(我在这里试图模仿)?

任何实现指针将不胜感激!

【问题讨论】:

  • 哪个 Expresson Blend 版本表现出您正在寻找的行为?
  • 我还没有查看最近的版本。它肯定存在于第一个版本中。它只是显示带有最近项目列表的小窗口以及创建新项目或选择现有项目之一的选项。用户选择一个项目后,窗口消失,主应用程序窗口显示加载所选项目。
  • 最新版本的 Blend (3) 不同。首先它显示一个简短的 Win32 启动画面,然后是长时间的 WPF 启动画面,然后它打开主窗口,然后打开一个窗口以选择新项目或现有项目。

标签: wpf performance winapi startup


【解决方案1】:

构建此场景的最佳方式

我愿意:

  1. 创建类来管理“选择项目”窗口的数据(例如 MRU 列表、模板等),确保它们是独立的并且不需要与主线程交互。

  2. 将有关“当前”项目的信息存储在 Application 对象或单例对象中。

  3. 创建“选择项目”窗口以完全独立于主窗口进行操作。

  4. 设置“选择项目”窗口的“打开”和“创建”按钮以触发 Application.Open 命令,并将按钮上的 CommandParameter 绑定到包含要打开的文件名(或要打开的模板)的属性实例化)。

  5. 在窗口级别为Application.Open命令添加CommandBinding,以获取命令参数并在Application对象中设置当前项目。

  6. 在您的应用程序的启动代码中,立即生成一个线程以创建“选择项目”窗口,然后立即执行 {a Dispatcher.Invoke at ApplicationIdle 优先级,然后执行非常短的 Thread.Sleep} 几次,然后继续, 允许创建主窗口但使其最初不可见。

  7. 在主窗口中设置一个触发器,使其在第一次设置当前项目后可见。

下面是“选择项目”窗口中的Open 命令处理程序如何更新应用程序对象中的项目路径:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Send, new Action(() =>
{
  ((App)Application.Current).CurrentProjectPath = e.Parameter;
}

以下是应用程序的启动代码:

public override void OnStartup(StartupEventArgs e)
{
  new Thread(() => { new SelectProject().Show(); }).Start();
  for(int i=0; i<10; i++)
  {
    Dispatcher.Invoke(DispatcherPriority.ApplicationIdle, () => {});
    Thread.Sleep(20);
  }
  _guts = new MainWindowContent(); // probably a UserControl
  _guts.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
  _guts.Arrange(new Rect(0, 0, guts.DesiredSize.Width, guts.DesiredSize.Height));
  _guts.SetBinding(VisibilityProperty,
    new Binding { Source = this, Path="StartupFinished",
                  Converter = BoolToVisibiltyConverter.Instance });

  _mainWindow = new MainWindow { Content = guts };
  // Note: Title and other properties of MainWindow would be set in the XAML
}

注意额外的代码,以确保提前测量和安排胆量。

这里是设置当前项目路径的代码:

public string CurrentProjectPath
{
  get { return _currentProjectPath; }
  set
  {
    _currentProjectPath = value;
    LoadProject();
    _startupFinished = true;
    OnPropertyChanged("StartupFinished");
  }
}

此代码假定 XAML 绑定 _mainWindow 的 Visibility 属性

StartupFinished 是主窗口的 Visibility 属性绑定到的 DependencyProperty,但可以通过其他方式完成。

您能否通过这种方式看到更快的启动时间?

是的。

应该在主线程和其他线程上创建选择项目,反之亦然

您应该在主线程上创建 MainWindow,以便它与 Application 对象共享同一个 Dispatcher。这意味着“选择项目”必须在第二个线程中。

如果您需要使用 Win32 启动窗口来提高速度

可能没有必要。 WPF 本身的启动只需几分之一秒。但如果有必要,上述Application.Current.Dispatcher.Invoke 技术将起作用。

你知道 Blend 是如何实现它的启动窗口的吗?

没有

【讨论】:

    【解决方案2】:

    您是否有完整的工作示例可供我查看?我试图从上面包含的代码 sn-ps 中解决一些问题,但无法获得一个可以工作的示例......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多