前言:上一个版本的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的样式效果。
添加一个类文件BlurBehind.cs,用来实现主窗体透明磨砂感。
using System;
using System.Runtime.InteropServices;
namespace WpfApp1
{
///
/// 背景磨砂
///
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 ShowTextCmd => new Lazy>(() =>
new RelayCommand(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();
}
public static ViewModelLocator Instance => new Lazy(() =>
Application.Current.TryFindResource("Locator") as ViewModelLocator).Value;
#region Vm
public DialogDemoViewModel DialogDemo => ServiceLocator.Current.GetInstance();
#endregion
}
}
MainWindow.xaml 主窗体的内容
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
{
///
/// MainWindow.xaml 的交互逻辑
///
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;
}
///
/// 获取当前应用中处于激活的一个窗口
///
///
private static Window GetActiveWindow() => Application.Current.Windows.OfType().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 对话框
TextDialog.xaml.cs 新增了一个CloseMe 用来后台调用关闭它
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using WpfApp1.ViewModel;
namespace WpfApp1
{
///
/// TextDialog_.xaml 的交互逻辑
///
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();
}
}
}
源码下载地址:https://download.csdn.net/download/5653325/11247941