【问题标题】:WPF Please Wait DialogWPF 请等待对话框
【发布时间】:2014-02-12 16:53:33
【问题描述】:

我正在用 c# 4.0 开发一个 WPF 桌面应用程序,它必须处理大量长时间运行的操作(从数据库加载数据、计算模拟、优化路线等)。

当这些长时间运行的操作在后台运行时,我想显示一个 Please-Wait 对话框。当显示 Please-Wait 对话框时,应用程序应该被锁定,但仅仅禁用应用程序窗口并不是一个好主意,因为所有 DataGrids 都会失去它们的状态 (SelectedItem)。

到目前为止,我的工作有效,但存在一些问题: 使用 Create-factory 方法创建一个新的 WaitXUI。 Create 方法需要标题文本和对应该锁定的宿主控件的引用。 Create 方法设置窗口的 StartupLocation、标题文本和要锁定的主机:

WaitXUI wait = WaitXUI.Create("Simulation running...", this);
wait.ShowDialog(new Action(() =>
{
    // long running operation
}));

使用重载的 ShowDialog 方法可以显示 WaitXUI。 ShowDialog 重载确实需要一个包含长时间运行操作的 Action。

在 ShowDialog 重载中,我只是在自己的线程中启动 Action,然后禁用主机控件(将 Opacity 设置为 0.5 并将 IsEnabled 设置为 false)并调用基类的 ShowDialog。

public bool? ShowDialog(Action action) 
    {
    bool? result = true;

    // start a new thread to start the submitted action
    Thread t = new Thread(new ThreadStart(delegate()
    {
        // start the submitted action
        try
        {
            Dispatcher.UnhandledException += Dispatcher_UnhandledException;
            Dispatcher.Invoke(DispatcherPriority.Normal, action);
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            // close the window
            Dispatcher.UnhandledException -= Dispatcher_UnhandledException;
            this.DoClose();
        }
    }));
    t.Start();

    if (t.ThreadState != ThreadState.Stopped)
    {
        result = this.ShowDialog();
    }
    return result;
}

private new bool? ShowDialog() 
{
    DisableHost();
    this.Topmost = true;
    return base.ShowDialog();
}

private void DisableHost()
{
    if (host != null)
    {
        host.Dispatcher.Invoke(new Action(delegate()
        {
            this.Width = host.Width - 20;
            host.Cursor = Cursors.Wait;
            host.IsEnabled = false;
            host.Opacity = 0.5;
        }));
    }
}

这里有问题:

  • 禁用主机控件会导致状态信息丢失(SelectedItems...)
  • 当线程在 WaitXUI 显示几毫秒后结束时,WaitXUI 有时只显示几毫秒
  • 虽然线程仍在运行,但有时对话框根本不出现

这些是我目前想到的主要问题。如何改进这个概念,或者可以采用哪些其他方法来解决这个问题?

提前致谢!

【问题讨论】:

  • 甚至不会作为问题发布,因为它很难看。将每个控件设置为 IsEnabled = false。或者在 Window 中捕获任何输入并设置 e.handled = true。
  • 这肯定是重复的。
  • @Blam 但这并不能解决我的任何问题。
  • @Akane 有类似的问题,但都有其他(较低)要求!将我的问题作为重复而不发布解决方案没有帮助;-)

标签: c# .net wpf wait


【解决方案1】:

在开发 WPF 应用程序时,稍微横向思考总是有帮助的。只需 GridRectanglebool 属性(您可能已经拥有)和 BooleanToVisibilityConverter,您就可以轻松满足您的要求,并且您无需禁用任何控件。

这个想法很简单。在您的视图内容前添加一个白色Rectangle,其Opacity 属性设置在0.50.75 之间。数据将其Visibility 属性绑定到您的视图模型或代码中的bool 属性并插入BooleanToVisibilityConverter

<Grid>
    <Grid>
        <!--Put your main content here-->
    </Grid>
    <Rectangle Fill="White" Opacity="0.7" Visibility="{Binding IsWaiting, 
        Converter={StaticResource BooleanToVisibilityConverter}}" />
    <!--You could add a 'Please Wait' TextBlock here-->
</Grid>

现在,当您想禁用控件时,只需将bool 属性设置为trueRectangle 将使 UI 显示为褪色:

IsWaiting = true;

【讨论】:

  • 感谢您的回答。这与 BusyIndi​​cator(Eugene P 建议)使用的概念相同。将是一个可能的解决方案。我唯一不喜欢的是,我必须将上面的代码添加到调用 WaitXUI 的每个 UI。并且有很多 UI (> 50) 使用等待对话框。如果可以在一个地方(在 WaitXUI 中)做到这一点,那就太好了! :-/
  • 你好像误会了...如果你把这个放在MainWindow.xaml和你的bool主视图模型中的属性中,那么你只需要一个。将所有您的正常应用内容放在标有Put your main content here 的位置。
  • 好吧,你是对的。我只需要在每个窗口中而不是在每个 UI 中都需要这段代码。我会试试的。谢谢!
  • 没有给出完整的解决方案与 BoolToVisibilityConverter 的概念或任何提示答案不完整。
  • 这是你要求澄清的方式吗,@AdamRi?如果您正确阅读了我的答案,您会看到我提到了标准 BooleanToVisibilityConverter,它包含在 .NET Framework 中。因此,您会很清楚,对神秘BoolToVisibilityConverter 的引用只不过是打字错误,您应该改用前面提到的BooleanToVisibilityConverter。但是感谢您的评论。
【解决方案2】:

真的不需要创建自己的实现,我认为它是多余的。

查看已创建的组件,例如 BusyIndi​​cator,以满足类似需求。这是至关重要和有效的。 .

更多信息来自codeplex

【讨论】:

  • 感谢您的回答。 BusyIndi​​cator 使用 Sharidan 建议的相同概念。那将是一个可能的解决方案。我唯一不喜欢的是,我必须将 BusyIndi​​cator 的 UI 代码添加到调用 WaitXUI 的每个 UI。并且有很多 UI (> 50) 使用等待对话框。如果可以在一个地方(在 WaitXUI 中)做到这一点,那就太好了! :-/
  • 我不确定我是否知道您尝试访问,但无论如何,busyindicator 是可绑定的,您可以将其设置为根视图占位符,然后注入任何子(页面/等)视图。接下来您可以轻松使用 Binding 进行控件自定义
猜你喜欢
  • 1970-01-01
  • 2021-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-21
  • 2012-01-18
  • 2013-09-05
相关资源
最近更新 更多