• 【WPF】BusyIndicator做Loading遮罩层


    百度了一下,粗略看了几个国内野人的做法,花了时间看下去感觉不太好用(比如有Loading居然只是作为窗体的一个局部控件的,没法全屏遮罩,那要你有何用?),于是谷歌找轮子去。

    好用的轮子:http://wpftoolkit.codeplex.com/wikipage?title=BusyIndicator

    引入DLL(在官网或者Nuget里下载)、引入名称空间等步骤根据官方的文档来操作就好了,很简单。

    测试如下:
    前台代码 MainWindow.xaml:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApplication1"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525"
            xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    
        <!-- 如有需要,可以引入样式资源 -->
        <!--<Window.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="/Style/LoadingMaskStyle.xaml"/>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Window.Resources>-->
    
        <StackPanel VerticalAlignment="Center">
    
            <xctk:BusyIndicator x:Name="_busyIndicator" IsBusy="False" 
                                BusyContent="少女祈祷中..." Background="Red">
                <!--<xctk:BusyIndicator.OverlayStyle>
                    <Style TargetType="Rectangle">
                        <Setter Property="Fill" Value="#ffffeeee"/>
                    </Style>
                </xctk:BusyIndicator.OverlayStyle>-->
                <!--<xctk:BusyIndicator.ProgressBarStyle>
                    <Style TargetType="ProgressBar">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </Style>
                </xctk:BusyIndicator.ProgressBarStyle>-->
    
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                    <Button Click="Show" Content="LLLL" Height="40" Width="60"/>
                    <Button Click="Show" Content="LLLL" Height="40" Width="60"/>
                    <Button x:Name="btn" Click="btn_OnClick" Content="测试" Height="40" Width="60"/>
                    <Button Click="Show" Content="RRRR" Height="40" Width="60"/>
                    <Button Click="Show" Content="RRRR" Height="40" Width="60"/>
                </StackPanel>
            </xctk:BusyIndicator>
        </StackPanel>
    </Window>
    

    对应的后台代码 MainWindow.xaml.cs:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void btn_OnClick(object sender, RoutedEventArgs e)
            {
                BackgroundWorker worker = new BackgroundWorker();
                //this is where the long running process should go
                worker.DoWork += (o, ea) =>
                {
                    //no direct interaction with the UI is allowed from this method
                    for (int i = 0; i < 100; i++)
                    {
                        System.Threading.Thread.Sleep(100);
                    }
                };
                worker.RunWorkerCompleted += (o, ea) =>
                {
                    //work has completed. you can now interact with the UI
                    _busyIndicator.IsBusy = false;
                };
                //set the IsBusy before you start the thread
                _busyIndicator.IsBusy = true;
                worker.RunWorkerAsync();
            }
    
            private void Show(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("还能点!");
            }
        }
    }
    

    运行效果如下:
    这里写图片描述

    注意点:

    • 想要这个BusyIndicator全屏遮罩,需要把它作为这个Window的直接子节点。而这个BusyIndicator控件自身也只能包含一个子节点,所以可用一个Grid或StackPanel标签做包裹。
    • 官方文档中没有说到BusyIndicator的XMAL全屏遮罩写法,我是看youtube这个小哥这么写的:

    https://www.youtube.com/watch?v=1h_mLA-eE40


    2016.12.29下午更新:

    发现一个问题,当在worker.DoWork委托中执行的操作需要修改UI时,会发生运行时异常:

    Additional information: 该类型的 CollectionView 不支持从调度程序线程以外的线程对其 SourceCollection 进行的更改。
    

    谷歌一下:
    http://stackoverflow.com/questions/18331723/this-type-of-collectionview-does-not-support-changes-to-its-sourcecollection-fro
    这里写图片描述

    意思是说,UI是由UI线程创建并维护的,BackgroundWorker对象作为一个新建的子线程,无法跨线程操作UI(这点跟Android很像嘛),想要跨线程操作UI,需要使用Dispatcher分发器机制。所以worker.DoWork的代码修改一下就好了:

    worker.DoWork += (o, ea) =>
    {
        //no direct interaction with the UI is allowed from this method
        // 不需要操作UI的代码
        // ...
    
        // 需要操作UI的代码
        App.Current.Dispatcher.Invoke((Action)delegate
        {
            // 如MVVM中其他Controller、ViewModel中操作UI的方法
            designController.Initialize();
            webImageViewModel.UpdateImages(designId);
        });
    };

    重要参考:

    https://elegantcode.com/2009/07/03/wpf-multithreading-using-the-backgroundworker-and-reporting-the-progress-to-the-ui/
    https://elegantcode.com/2011/10/07/extended-wpf-toolkitusing-the-busyindicator/ 最后一个例子有提及Dispatcher
    https://vkishorekumar.wordpress.com/2011/07/18/what-is-thread-affinity/ 报错原因:线程的紧密性(亲和性?)

  • 相关阅读:
    数组和矩阵问题
    Memcached安装以及PHP的调用
    php函数ob_start()、ob_end_clean()、ob_get_contents()
    Nginx
    电影大全 API接口
    找电影资源最强攻略,知道这些你就牛B了!
    CSS3 图片旋转
    curl网站开发指南
    Redis 集群方案
    从12大技巧、30个案例、99个模板谈怎么写标题
  • 原文地址:https://www.cnblogs.com/guxin/p/csharp-wpf-busyindicator-loading-mask-layer-by-backgroundworker.html
Copyright © 2020-2023  润新知