“忙碌”效果叠加

时间:2012-01-03 10:01:00

标签: wpf

我有一个wpf应用程序,它执行非常繁重的操作,用户需要在应用程序“思考”时等待。

我想要做的是,当应用程序的主线程正在考虑时,另一个线程将禁用整个窗口并给它一种浅灰色,并且屏幕中间会出现一个圆形进度条。 / p>

这是一个很大的问题,我并不需要整个代码来做这个只是一般的想法。

感谢您的帮助......

4 个答案:

答案 0 :(得分:12)

除了上述建议(后台工作者,调度员) - 是的,这些是获得所需内容的正确技巧,但让我讨论您在问题中请求的UI效果。如果您正在使用MVVM模式,则可以创建一些“我很忙”UI并绑定到视图模型中的IsBusy属性以显示和隐藏UI。例如:

public class MyViewModel : INotifyPropertyChanged
{
    // Bind to this property any UI you want to 
    // show/hide during long running updates
    public bool IsBusy 
    { 
        get { return _isBusy; } 
        set 
        {
            _isBusy = true; 
            OnPropertyChanged("IsBusy");
        }
    } 

    private void OnPropertyChanged(string prop)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(prop));
        }
    }

    // Note: This is intended to be called on a background thread
    private void DoLongRunningOperationOnABackgroundThread()
    {
        try
        {
            IsBusy = true;

            // do your work
        }
        finally
        {
            IsBusy = false;
        }
    }
}

然后在UI中使用此xaml(或类似的)

<UserControl:MyControl x:Class="MyApp.MyControl"
                          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="boolToVis"/>
    </UserControl.Resources>
    <Grid>
        <!-- your UI code goes here -->

        <!-- Below this, at higher Z-Order place a control to gray out the screen when IsBusy = true -->
        <Border Background="#55000000" BorderThickness="0" Visibility="{Binding IsBusy, Converter={StaticResource boolToVis}}">
            <TextBlock Text="I AM BUSY!" Font-Size="32" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White"/>
        </Border>
    <Grid>
</UserControl>    

当您使用后台工作程序或线程池调用viewmodel中的DoLongRunningOperation函数时,将产生净效果,Xaml中定义的边框将在操作开始/停止时显示/隐藏。您不需要调度程序在此处调用,因为WPF会为您处理线程编组。

在网络上实现繁忙的控件以及whirlygig动画等......也可以增加UI的功能。

致以最诚挚的问候,

答案 1 :(得分:3)

使用Dispatcher.BeginInvoke更改UI组件的Enable-Property并显示/隐藏工作线程中的进度条

对于工作线程,您可以使用BackgroundWorker-Class

答案 2 :(得分:2)

将重击操作卸载到新线程并在主线程上执行UI内容(禁用,灰显和进度条)。请参阅BackgroundWorker and Dispatcher

可以使用新线程作为UI内容,但不能使用现有的Window。 UI控件(Dispatcher)可以由其所属的线程在线使用/调用。但是,您可以创建一个新线程并使用带有新Dispatcher的新窗口来执行UI操作。然后,您必须将新窗口放在原始窗口上。不像我的第一个建议那么容易。如果您不知道何时执行繁重操作,则可能是一个选项。请参阅hereherehere

答案 3 :(得分:2)

看一下这个样本:

    public void DoHeavyWork()
    {
        mainDispatcher = Dispatcher.CurrentDispatcher;
        DisableWindow();
        workDelegate.BeginInvoke(EnableWindowCallBack, null);
    }

    private void EnableWindowCallBack(IAsyncResult asyncResult)
    {
        workDelegate.EndInvoke(asyncResult);
        mainDispatcher.InvokeIfRequired(() => { EnableWindow(); });
    }

当你致电DoHeavyWork时,我假设我们在可以访问UI的线程上,这应该是常见的。 DisableWindow显示动画或工作时应显示的内容。然后,您调用将在新线程上运行的预定义委托workDelegate,一旦完成,回调应该恢复视图。

请注意,必须在有权访问UI的线程上调用EnableWindow