wpf 蒙版实现在控件或者窗口遮罩

<Window x:Class="CommonUI.Control.Mask.Mask" 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" WindowStyle="None"
        xmlns:local="clr-namespace:CommonUI.Control.Mask" mc:Ignorable="d" AllowsTransparency="True" Title="Mask"
        Height="450" Width="800" Background="Transparent" Activated="Window_Activated"
        Closed="Window_Closed" IsVisibleChanged="Window_IsVisibleChanged" LocationChanged="Window_LocationChanged">
    <Grid Background="#7F000000" MouseDown="container_MouseDown" Name="container" SizeChanged="Window_SizeChanged" >
    </Grid>
</Window>


using CommonUI.Control.Mask.Model;
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;

namespace CommonUI.Control.Mask
{
    /// <summary>
    /// Mask.xaml 的交互逻辑
    /// </summary>
    public partial class Mask : Window
    {
        MaskConfig model;

        //父元素
        FrameworkElement uiElement;

        //自动定位
        DependencyPropertyDescriptor descriptor;

        /// <summary>
        /// 私有构造函数避免外部主动参与控制窗口
        /// </summary>
        /// <param name="config"></param>
        private Mask(FrameworkElement uiElement, MaskConfig config = null)
        {
            InitializeComponent();
            model = config;

            //绑定需要监听的事件
            Bind(uiElement);

            container.Children.Add(uiElement);
            InitWindow();
        }

        void Bind(FrameworkElement uiElement)
        {
            if (uiElement == null)
            {
                return;
            }
            this.uiElement = uiElement;
        }


        /// <summary>
        /// 初始化
        /// </summary>
        private void InitWindow()
        {
            //Binding binding = new Binding
            //{
            //    Source = uiElement,
            //    Path = new PropertyPath(LeftProperty),
            //    Mode= BindingMode.TwoWay
            //};
            ////Control x;
            //this.SetBinding(LeftProperty, binding);

            if (model == null)
            {
                return;
            }
            this.Title = model.Title;

            CalcPosition(model.Ownner);
        }

        /// <summary>
        /// 计算窗口定位
        /// </summary>
        /// <param name="parent"></param>
        void CalcPosition(FrameworkElement parent)
        {
            if (parent == null)
            {
                this.WindowState = WindowState.Maximized;
            }
            else
            {
                //获取窗口<0,0>坐标屏幕位置
                var boundPoint = parent.PointToScreen(new Point(0, 0));
                this.Left = boundPoint.X;
                this.Top = boundPoint.Y;
                this.Width = parent.ActualWidth;
                this.Height = parent.ActualHeight;
                AutoMoving(this.model.Ownner);
            }
        }

        /// <summary>
        /// 自动更新定位
        /// </summary>
        /// <param name="parent"></param>
        private void AutoMoving(FrameworkElement parent)
        {
            Window parentWindow = null;
            if (this.Owner is Window win)
            {
                parentWindow = this.Owner;

                if (!(this.model.Ownner is Window))
                {
                    if (this.model.Ownner != null)
                    {
                        var point = this.model.Ownner.TranslatePoint(new(0, 0), (Window)this.Owner);
                        this.model.left = point.X;
                        this.model.top = point.Y;

                    }
                }

            }
            if (parent is Window par)
            {
                parentWindow = par;
            }

            //根据父窗口实时移动位置
            if (null != parentWindow && descriptor == null)
            {
                descriptor = DependencyPropertyDescriptor.FromProperty(LeftProperty, typeof(Window));
                //第一个对象为触发变化的对象
                descriptor.AddValueChanged(parentWindow, (o, handle) =>
                {
                    if (o is Window parentWindow)
                    {
                        this.Left = parentWindow.Left + this.model.left;
                        this.Top = parentWindow.Top + this.model.top;
                    }
                });
            }
        }

        private void Window_Activated(object sender, EventArgs e)
        {
            if (this.IsActive)
            {
                //this.WindowState = WindowState.Maximized;
            }
        }

        private void container_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (model == null)
            {
                return;
            }

            //点击空白处关闭窗口
            if (model.ClickBlankCanClose)
            {
                this.Close();
            }
        }

        /// <summary>
        /// 激活窗口(链式调用)
        /// </summary>
        public Mask ActiveWindow()
        {
            //激活已显示的窗口
            if (this.Visibility == Visibility.Visible)
            {
                this.Activate();
            }
            else
            {
                if (model == null)
                {
                    this.Show();
                    return this;
                }
                //设置ownner
                if (model.Ownner != null)
                {
                    if (model.Ownner is Window parWindow)
                    {
                        this.Owner = parWindow;
                    }
                    else
                    {
                        var window = GetWindow(model.Ownner);
                        this.Owner = window;
                    }
                    CalcPosition(model.Ownner);
                }

                this.Owner.SizeChanged += Window_SizeChanged;
                this.Owner.LocationChanged += Window_LocationChanged;

                //根据配置控制是否打开模态框
                if (model.ISModel)
                {
                    this.ShowDialog();
                }
                else
                {
                    this.Show();
                }
            }

            return this;
        }

        /// <summary>
        /// 关闭窗口
        /// </summary>
        public void CloseWindow()
        {
            this.Close();
        }

        /// <summary>
        /// 构造蒙版对象
        /// </summary>
        /// <param name="uiElement">需要展示的ui组件</param>
        /// <param name="config">配置</param>
        /// <returns></returns>
        public static Mask Create(FrameworkElement uiElement, MaskConfig config = null)
        {

            return new Mask(uiElement, config);
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            if (model == null)
            {
                return;
            }
            model.CloseCallback?.Invoke();
        }

        private void Window_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (model == null)
            {
                return;
            }
            if (e.NewValue is bool value)
            {
                if (value)
                {
                    AutoMoving(model.Ownner);
                }
                else
                {
                    descriptor = null;
                }

            }


            model.VisibilityChangeCallback?.Invoke(this.Visibility);
        }

        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            CalcPosition(model.Ownner);
        }

        private void Window_LocationChanged(object sender, EventArgs e)
        {
            CalcPosition(model.Ownner);
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace CommonUI.Control.Mask.Model
{
    public class MaskConfig
    {
        //如果父元素为非window时需要计算父级相对窗口的定位
        public double top;
        public double left;

        /// <summary>
        /// 任务栏显示的名称
        /// </summary>
        public string Title { get; set; } = "";

        /// <summary>
        /// 是否为模态
        /// </summary>
        public bool ISModel { get; set; } = false;

        /// <summary>
        /// 是否可以点击蒙版阴影位置关闭蒙版
        /// </summary>
        public bool ClickBlankCanClose { get; set; } = false;

        /// <summary>
        /// 相对父级
        /// </summary>
        public FrameworkElement Ownner { get; set; } = null;

        /// <summary>
        /// 关闭蒙版回调
        /// </summary>
        public Action CloseCallback { get; set; } = null;

        /// <summary>
        /// 窗口显示状态发生变化回调
        /// </summary>
        public Action<Visibility> VisibilityChangeCallback { get; set; } = null;

    }
}

wpf 蒙版实现在控件或者窗口遮罩

上一篇:从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(三) (mini-cloud) 搭建认证服务(认证/资源分离版) oauth2.0 (上)


下一篇:(转)微信小程序的抽象节点