从SQL加载数据时显示带有动画的等待对话框

时间:2018-09-26 09:39:37

标签: c# wpf multithreading async-await busyindicator

我制作了一个用于查看,编辑和创建存储在SQL Server上的数据的应用程序。 我的问题是,与SQL Server的交互可能会花费一些时间,特别是因为该程序也被我的中国同事使用,并且我的Server位于德国。因此,我想在加载数据时显示一个带有等待动画的对话框。加载时无需继续使用我的GUI。 我的第一个解决方案是制作此类:

public class LongTimeAction
{
    public void Run(Action MyMethod)
    {
        try
        {
            var thread = new Thread(() =>
            {
                Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => new MyWindows.CMN_Splash().Show()));
                Dispatcher.Run();
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
            MyMethod();
            thread.Abort();
        }
        catch (Exception exp)
        {
            new Errorlogger().write_Error(this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name, exp.Message);
        }
    }
}

初始窗口具有XAML制作的“骑士骑士”式动画,该动画在加载窗口时自动启动:

    <Window.Triggers>
    <EventTrigger RoutedEvent="Window.Loaded">
        <BeginStoryboard>
            <Storyboard RepeatBehavior="Forever" Duration="0:0:1.4">
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Bar1" Storyboard.TargetProperty="Opacity">
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.5" />
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Bar2" Storyboard.TargetProperty="Opacity">
                    <DiscreteDoubleKeyFrame Value="0.8" KeyTime="0:0:0" />
                    <LinearDoubleKeyFrame Value="0.6" KeyTime="0:0:0.1" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.1" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.6" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:1.3" />
                    <LinearDoubleKeyFrame Value="0.8" KeyTime="0:0:1.4" />
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Bar3" Storyboard.TargetProperty="Opacity">
                    <DiscreteDoubleKeyFrame Value="0.6" KeyTime="0:0:0" />
                    <LinearDoubleKeyFrame Value="0.2" KeyTime="0:0:0.2" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.2" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.7" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:1.2" />
                    <LinearDoubleKeyFrame Value="0.6" KeyTime="0:0:1.4" />
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Bar4" Storyboard.TargetProperty="Opacity">
                    <DiscreteDoubleKeyFrame Value="0.4" KeyTime="0:0:0" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.3" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.3" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.8" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:1.1" />
                    <LinearDoubleKeyFrame Value="0.4" KeyTime="0:0:1.4" />
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Bar5" Storyboard.TargetProperty="Opacity">
                    <DiscreteDoubleKeyFrame Value="0.2" KeyTime="0:0:0" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.1" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.4" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.9" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:1" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:1.4" />
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Bar6" Storyboard.TargetProperty="Opacity">
                    <DiscreteDoubleKeyFrame Value="0" KeyTime="0:0:0" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.5" />
                    <LinearDoubleKeyFrame Value="0.2" KeyTime="0:0:0.9" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.9" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:1.3" />
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Bar7" Storyboard.TargetProperty="Opacity">
                    <DiscreteDoubleKeyFrame Value="0" KeyTime="0:0:0" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.6" />
                    <LinearDoubleKeyFrame Value="0.6" KeyTime="0:0:0.8" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.8" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:1.2" />
                </DoubleAnimationUsingKeyFrames>
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Bar8" Storyboard.TargetProperty="Opacity">
                    <DiscreteDoubleKeyFrame Value="0" KeyTime="0:0:0" />
                    <DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.7" />
                    <LinearDoubleKeyFrame Value="0" KeyTime="0:0:1.1" />
                </DoubleAnimationUsingKeyFrames>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger> 
</Window.Triggers>
<Canvas Grid.Row="1" HorizontalAlignment="Stretch" Height="100" Width="275">            
    <TextBlock Canvas.Top="12" Canvas.Left="39" FontSize="32" FontWeight="Bold" Foreground="Gray" Text="Loading Data" />
    <TextBlock Canvas.Top="10" Canvas.Left="37" FontSize="32" FontWeight="Bold" Foreground="White" Text="Loading Data" />
    <Rectangle Canvas.Top="67" Canvas.Left="15" Name="Rect"  Width="245" Height="20" Stroke="White" RadiusY="2" RadiusX="2" StrokeThickness="2" Fill="Black" />
    <Rectangle Canvas.Top="70" Canvas.Left="18" Name="Bar1" Height="14" RadiusY="2" RadiusX="2" Fill="Red" HorizontalAlignment="Left" Width="29"  />           
    <Rectangle Canvas.Top="70" Canvas.Left="48" Name="Bar2"  Height="14" RadiusY="2" RadiusX="2" Fill="Red" HorizontalAlignment="Left" Width="29" />
    <Rectangle Canvas.Top="70" Canvas.Left="78" Name="Bar3"  Height="14" RadiusY="2" RadiusX="2" Fill="Red" HorizontalAlignment="Left" Width="29" />
    <Rectangle Canvas.Top="70" Canvas.Left="108" Name="Bar4"  Height="14" RadiusY="2" RadiusX="2" Fill="Red" HorizontalAlignment="Left" Width="29" />
    <Rectangle Canvas.Top="70" Canvas.Left="138" Name="Bar5"  Height="14" RadiusY="2" RadiusX="2" Fill="Red" HorizontalAlignment="Left" Width="29" />
    <Rectangle Canvas.Top="70" Canvas.Left="168" Name="Bar6"  Height="14" RadiusY="2" RadiusX="2" Fill="Red" HorizontalAlignment="Left" Width="29" />
    <Rectangle Canvas.Top="70" Canvas.Left="198" Name="Bar7"  Height="14" RadiusY="2" RadiusX="2" Fill="Red" HorizontalAlignment="Left" Width="29" />
    <Rectangle Canvas.Top="70" Canvas.Left="228" Name="Bar8"  Height="14" RadiusY="2" RadiusX="2" Fill="Red" HorizontalAlignment="Left" Width="29" />
</Canvas>

这很好,但并不完美。有时我的程序完全崩溃(“应用程序没有响应”),因此我寻找了一个更好的解决方案。 因为在加载时无需与GUI进行交互,所以我将程序更改为async-await。因此,我将所有与SQL交互的函数都更改为异步。在那之后,我将所有调用此函数的函数更改为异步等。现在我程序的至少一半是异步的:-) 我还这样更改了我的课程LongTimeAction:

public static class LongTimeAction
{
    public static async Task Run(Func<Task> MyMethod)
    {
        MyWindows.CMN_Splash MySplashWindow = new MyWindows.CMN_Splash();
        MySplashWindow.Show();

        await MyMethod();

        MySplashWindow.Close();
    }
}

这样称呼:

await LongTimeAction.Run(VT_ReloadAllAction);

它在原则上正在运行,但是“启动画面”中的“动画”并不流畅。另外有时程序会完全冻结。

能否请您帮我找出我的问题所在?

编辑:

现在,我已经下载了Extended WPF Toolkit,并将其添加到我的MainWindow中:

<wpfx:BusyIndicator Name="BusyBar" BusyContent="Loading Data..." />

在我后面的代码中添加了此功能

public async Task StartLongRunningTask(Func<Task> MyMethod)
{
    BusyBar.IsBusy = true;
    await MyMethod();
    BusyBar.IsBusy = false;
}

我这样称呼:

await StartLongRunningTask(TT_ReloadAllAction);

我的应用程序正常运行,但未显示BusyIndi​​cator。我想念什么?

EDIT2 + 4

如果启动程序,然后使用其他一些窗口,我仍然遇到程序混乱的问题。当我回到窗口时,它完全冻结了,甚至无法关闭。已解决。我的轮询程序中有一个问题,它在每个视图分钟内检查数据库是否有特殊标志。我用DispatcherTimer做到了,将它与异步结合起来似乎有些棘手。所以我改回了同步。现在可以正常工作了。

EDIT3

这是我周围的代码:

public ICommand Cmd_OnlyMyItems { get; set; }
Cmd_OnlyMyItems = new CMN_RelayCommand(Execute => CMN_OnlyMyItems(), CanExecute => true);

private async void CMN_OnlyMyItems()
{
    //some Code here
    await StartLongRunningTask(VT_ApplyFilterAction);
    //some Code here
}

private async Task VT_ApplyFilterAction()
{
    await DBConnect.VT_Get_FilteredData_V2();
    VT_RefreshGrid();
}

public static class DBConnect
{
    public async static Task VT_Get_FilteredData_V2()
    {
        //some Code here
        SqlDataReader reader = command.ExecuteReader()
        while (await reader.ReadAsync())
        {
            //some Code here
        }
    }
}

现在,我将看一下评论部分提供的示例。

0 个答案:

没有答案