• WPF实现背景透明磨砂,并通过HandyControl组件实现弹出等待框


    前言:上一个版本的Winform需要改成WPF来做界面,第一次接触WPF,在转换过程中遇到的需求就是一个背景透明模糊,一个是类似于 加载中…… 这样的等待窗口,等后台执行完毕后再关掉。在Winform中是通过一个类指定等待窗口的parent为调用者,并指定topmost为最顶层来实现。在WPF中这个方法不太灵光,通过这几天的摸索,找到一个WPF下的UI利器--HandyControl(https://github.com/HandyOrg/HandyControl)感谢作者分享。通过它来实现一些界面的效果,它里面带的有个顶部弹出对话框的功能(带遮罩),但没找到后台代码关闭的方法。所以我就单独从里面把这个功能提取出来,实现了弹出提示框,后台可以关闭的模式。

    最新更新:控件作者提供了有一个自动关闭的Demo,请以Demo的使用方法为准。下载地址:点击下载

    先看一下HandyControl提供的Demo中的这种对话框。

     

    由于我需要的是弹出后,后台会执行代码,代码执行完后主动关闭对话框的操作。于是我把里面的这块代码单独提取出来改造了一下,实现效果如下。

     

    这是在新接触WPF开发中,学习到的,如何让主窗体背景磨砂透明、如何Grid背景透明模糊、如何让Grid的控件不随Grid来模糊。

    下面进入代码:

    首先新建一个WPF项目,然后通过Nuget引用HandyControl。

    在App.xaml中添加以下内容,来引用HandyControl的样式效果。

        <Application.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary>
                        <ResourceDictionary.MergedDictionaries>
                            <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
                            <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
                        </ResourceDictionary.MergedDictionaries>
                    </ResourceDictionary>
                    <ResourceDictionary>
                        <viewModel:ViewModelLocator x:Key="Locator" />
                    </ResourceDictionary>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Application.Resources>
    

      添加一个类文件BlurBehind.cs,用来实现主窗体透明磨砂感。

    using System;
    using System.Runtime.InteropServices;
     
    namespace WpfApp1
    {
        /// <summary>
        /// 背景磨砂
        /// </summary>
        public class BlurBehind
        {
            internal enum AccentState
            {
                ACCENT_DISABLED = 1,
                ACCENT_ENABLE_GRADIENT = 0,
                ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
                ACCENT_ENABLE_BLURBEHIND = 3,
                ACCENT_INVALID_STATE = 4,
                ACCENT_ENABLE_ACRYLICBLURBEHIND = 5
            }
     
            [StructLayout(LayoutKind.Sequential)]
            internal struct AccentPolicy
            {
                public AccentState AccentState;
                public int AccentFlags;
                public int GradientColor;
                public int AnimationId;
            }
     
            [StructLayout(LayoutKind.Sequential)]
            internal struct WindowCompositionAttributeData
            {
                public WindowCompositionAttribute Attribute;
                public IntPtr Data;
                public int SizeOfData;
            }
     
            internal enum WindowCompositionAttribute
            {
                // ...
                WCA_ACCENT_POLICY = 19
                // ...
            }
        }
    }
    

    然后新建两个目录:ViewModel和Images

    在Images中放入一张图片,并设置生成时自动复制

    在ViewModel中新建三个类文件

    DialogDemoViewModel.cs 用来实现弹出框

    using System;
    using GalaSoft.MvvmLight;
    using GalaSoft.MvvmLight.Command;
    using HandyControl.Controls;
     
    namespace WpfApp1.ViewModel
    {
        public class DialogDemoViewModel : ViewModelBase
        {
            private string _dialogResult;
            public string DialogResult
            {
                get => _dialogResult;
    #if netle40
                set => Set(nameof(DialogResult), ref _dialogResult, value);
    #else
                set => Set(ref _dialogResult, value);
    #endif
            }
            public RelayCommand<TextDialog> ShowTextCmd => new Lazy<RelayCommand<TextDialog>>(() =>
                new RelayCommand<TextDialog>(ShowText)).Value;
     
            private static void ShowText(TextDialog d)
            {
                Dialog.Show(d);
                //获得句柄
                //var dialogShow = Dialog.Show(d);
                //var dialogShowHwnd = (HwndSource)PresentationSource.FromVisual(dialogShow);
                //if (dialogShowHwnd == null) return;
                //var hwnd = dialogShowHwnd.Handle;
            }
        }
    }
    

      DialogInfo.cs 用来实现数据绑定给弹出框,比如指定显示文字

    using System.Windows.Automation.Peers;
    using System.Windows.Automation.Provider;
    using System.ComponentModel;
     
    namespace WpfApp1.ViewModel
    {
      public class DialogInfo : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
     
            public DialogInfo()
            {
                MyTxt = "加载中,请稍后。";
            }
            private string myTxt;
            public string MyTxt
            {
                get => myTxt;
                set
                {
                    myTxt = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MyTxt"));
                }
            }
        }
    }
    

      ViewModelLocator.cs用来实现构建弹出框实例

    using System;
    using System.Windows;
    using CommonServiceLocator;
    using GalaSoft.MvvmLight.Ioc;
     
    namespace WpfApp1.ViewModel
    {
        public class ViewModelLocator
        {
            public ViewModelLocator()
            {
                ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
                SimpleIoc.Default.Register<DialogDemoViewModel>();
                 
            }
     
            public static ViewModelLocator Instance => new Lazy<ViewModelLocator>(() =>
                Application.Current.TryFindResource("Locator") as ViewModelLocator).Value;
            #region Vm
            public DialogDemoViewModel DialogDemo => ServiceLocator.Current.GetInstance<DialogDemoViewModel>();
            #endregion
        }
    }
    

      MainWindow.xaml 主窗体的内容

    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        x:Class="WpfApp1.MainWindow"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        DataContext="{Binding DialogDemo,Source={StaticResource Locator}}"
        Loaded="MainWindow_OnLoaded"
        Background="#727A7A7A"
        AllowsTransparency="True"
        WindowStyle="None"
        MouseDown="MainWindow_OnMouseDown" 
        >
        <Grid HorizontalAlignment="Left" Height="397" Margin="10,10,0,0" VerticalAlignment="Top" Width="790" ZIndex="0" >
            <Grid Margin="0,10,10,97">
                <Grid.Background>
                    <ImageBrush ImageSource="/WpfApp1;component/Images/wow_cataclysm_artwork-wallpaper-960x540.jpg"></ImageBrush>
                </Grid.Background>
                <Grid.Effect>
                    <BlurEffect Radius="8"></BlurEffect>
                </Grid.Effect>
            </Grid>
            <Button x:Name="Btn_Show" Content="Button" HorizontalAlignment="Left" Margin="430,185,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"  />
            <TextBlock x:Name="txtBlock" HorizontalAlignment="Left" Margin="614,120,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Height="120" Width="145" Foreground="White"/>
        </Grid>
    </Window>
    

      MainWindow.xaml.cs

    using System;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Timers;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Interop;
    using WpfApp1.ViewModel;
    namespace WpfApp1
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow 
        {
            [DllImport("user32.dll")]
            private static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref BlurBehind.WindowCompositionAttributeData data);
            private uint _blurOpacity;
            public double BlurOpacity
            {
                get { return _blurOpacity; }
                set { _blurOpacity = (uint)value; EnableBlur(); }
            }
     
            private uint _blurBackgroundColor = 0x990000; /* BGR color format */
            public MainWindow()
            {
                InitializeComponent();
            } 
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                var newWindow = new TextDialog();
                var dialog = new DialogDemoViewModel();
                if (dialog.ShowTextCmd.CanExecute(newWindow))
                {
                    dialog.ShowTextCmd.Execute(newWindow);
                } 
                newWindow.info.MyTxt="加载中";
                //if (DataContext is DialogDemoViewModel MyVM && MyVM.ShowTextCmd.CanExecute(newWindow))
                //    MyVM.ShowTextCmd.Execute(newWindow);
     
                var i = 0;
                var timer = new Timer(1000);
                
                timer.Elapsed+=delegate
                {
                    Dispatcher.BeginInvoke(new Action(() =>
                    { 
                        if (i < 5)
                        {
                            txtBlock.Text +=$"{5 - i}秒后关闭"+ Environment.NewLine;
                            i++;
                        }
                        else
                        {
                            newWindow.CloseMe();
                        }
                    }));
                      
                };
                timer.AutoReset = true;
                timer.Enabled = true;
            }
            /// <summary>
            ///     获取当前应用中处于激活的一个窗口
            /// </summary>
            /// <returns></returns>
            private static Window GetActiveWindow() => Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
     
            private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
            {
                EnableBlur();
            }
     
            private void EnableBlur()
            {
                var windowHelper = new WindowInteropHelper(this);
     
                var accent = new BlurBehind.AccentPolicy
                {
                    AccentState = BlurBehind.AccentState.ACCENT_ENABLE_BLURBEHIND,
                    //GradientColor = (int) ((_blurOpacity << 24) | (_blurBackgroundColor & 0xFFFFFF))
                };
     
                var accentStructSize = Marshal.SizeOf(accent);
     
                var accentPtr = Marshal.AllocHGlobal(accentStructSize);
                Marshal.StructureToPtr(accent, accentPtr, false);
     
                var data = new BlurBehind.WindowCompositionAttributeData
                {
                    Attribute = BlurBehind.WindowCompositionAttribute.WCA_ACCENT_POLICY,
                    SizeOfData = accentStructSize,
                    Data = accentPtr
                };
     
                SetWindowCompositionAttribute(windowHelper.Handle, ref data);
     
                Marshal.FreeHGlobal(accentPtr);
            }
     
            private void MainWindow_OnMouseDown(object sender, MouseButtonEventArgs e)
            {
                if (e.ChangedButton == MouseButton.Left)
                    DragMove();
            }
        }
     
    }
    

      TextDialog.xaml 对话框

    <Border x:Class="WpfApp1.TextDialog"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            xmlns:hc="https://handyorg.github.io/handycontrol"
            CornerRadius="10"
            Width="400"
            Height="247"
            Background="{DynamicResource RegionBrush}"
            >
        <hc:SimplePanel>
            <TextBlock x:Name="TextBlock" Style="{StaticResource TextBlockLargeBold}" Text="{Binding MyTxt,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="100,0,0,119" VerticalAlignment="Bottom" Height="68" Width="100"/>
            <Button x:Name="BtnClose" Width="22" Height="22" Command="hc:ControlCommands.Close" Style="{StaticResource ButtonIcon}" Foreground="{DynamicResource PrimaryBrush}" hc:IconElement.Geometry="{StaticResource ErrorGeometry}" Padding="0" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,4,4,0" Visibility="Hidden" />
        </hc:SimplePanel>
    </Border>
    

      TextDialog.xaml.cs 新增了一个CloseMe 用来后台调用关闭它

     1 using System.Windows.Automation.Peers;
     2 using System.Windows.Automation.Provider;
     3 using WpfApp1.ViewModel;
     4 
     5 namespace WpfApp1
     6 {
     7     /// <summary>
     8     /// TextDialog_.xaml 的交互逻辑
     9     /// </summary>
    10     public partial class TextDialog
    11     {
    12         public DialogInfo info = new DialogInfo { MyTxt = "加载中……" };
    13         public TextDialog()
    14         {
    15             DataContext = info;
    16             InitializeComponent();
    17         }
    18         public void CloseMe()
    19         {
    20             try
    21             {
    22                 BtnClose.Visibility = Visibility.Visible;
    23                 BtnClose.OnClick();
    24             }
    25             catch
    26             {
    27                 //
    28             }
    29 
    30         }
    31     }
    32     /// <summary>
    33     /// ButtonBase 扩展
    34     /// </summary>
    35     public static class ButtonBaseExtension
    36     {
    37         /// <summary>
    38         /// 引发 <see>
    39         /// <cref>Primitives.ButtonBase.Click</cref>
    40         /// </see>
    41         /// 路由事件。
    42         /// </summary>
    43         /// <param name="buttonBase">要引发路由事件的按钮</param>
    44         public static void OnClick(this System.Windows.Controls.Primitives.ButtonBase buttonBase)
    45         {
    46             buttonBase.GetType().GetMethod(nameof(OnClick), BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(buttonBase, null);
    47         }
    48     }
    49 
    50 }
  • 相关阅读:
    C#多线程学习笔记(三)——线程池
    html解析工具
    怎么样获取手机的主题
    我改进的《豆瓣搜》前后对比及源代码
    【收藏】Silverlight Style (二) 自定义样式在后台代码中应用
    C#多线程学习笔记(一)
    学习Linux——学习正确的思考方式(转)
    电信禁路由上网的破解方法
    印度软件业
    中国与印度软件工程师之比较
  • 原文地址:https://www.cnblogs.com/wdw984/p/11049550.html
Copyright © 2020-2023  润新知