WPF实现背景透明磨砂,并通过HandyControl组件实现弹出等待框
前言:上一個版本的Winform需要改成WPF來做界面,第一次接觸WPF,在轉換過程中遇到的需求就是一個背景透明模糊,一個是類似于 加載中…… 這樣的等待窗口,等后臺執行完畢后再關掉。在Winform中是通過一個類指定等待窗口的parent為調用者,并指定topmost為最頂層來實現。在WPF中這個方法不太靈光,通過這幾天的摸索,找到一個WPF下的UI利器--HandyControl(https://github.com/HandyOrg/HandyControl)感謝作者分享。通過它來實現一些界面的效果,它里面帶的有個頂部彈出對話框的功能(帶遮罩),但這個不支持后臺關閉(作者說是可以調用帶回調的模式,但沒有找到,也沒有明確說明是哪個)。所以我就單獨從里面把這個功能提取出來,實現了彈出提示框,后臺可以關閉的模式。
先看一下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 netle40set => Set(nameof(DialogResult), ref _dialogResult, value); #elseset => 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 Vmpublic DialogDemoViewModel DialogDemo => ServiceLocator.Current.GetInstance<DialogDemoViewModel>();#endregion} }MainWindow.xaml 主窗體的內容
<Windowxmlns="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 用來后臺調用關閉它
using System.Windows.Automation.Peers; using System.Windows.Automation.Provider; using WpfApp1.ViewModel;namespace WpfApp1 {/// <summary>/// TextDialog_.xaml 的交互邏輯/// </summary>public partial class TextDialog{public DialogInfo info = new DialogInfo { MyTxt = "加載中……" };public TextDialog(){DataContext = info;InitializeComponent(); }public void CloseMe(){var bam = new ButtonAutomationPeer(BtnClose);var iip = bam.GetPattern(PatternInterface.Invoke) as IInvokeProvider;iip?.Invoke();}} }posted on 2019-06-27 23:09 NET未來之路 閱讀(...) 評論(...) 編輯 收藏
轉載于:https://www.cnblogs.com/lonelyxmas/p/11100215.html
總結
以上是生活随笔為你收集整理的WPF实现背景透明磨砂,并通过HandyControl组件实现弹出等待框的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 换个语言学一下 Golang (9)——
- 下一篇: The method getTextCo