WPF请等待对话

时间:2014-02-12 16:53:33

标签: c# .net wpf wait

我在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我刚开始动作在它自己的线程,然后禁用主机控制(设定不透明度为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有时会显示几毫秒
  • 有时虽然线程仍在运行,但对话框根本不会出现

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

提前致谢!

2 个答案:

答案 0 :(得分:8)

在开发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;

答案 1 :(得分:1)

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

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

来自codeplex

的更多信息