自定义WPF Popup控件

解决问题

1、WPF Popup 不随着 Window 一起移动的问题

2、WPF Popup 总是显示在最前面

引用命名空间

xmlns:ctrl="clr-namespace:Micro.UI.Controls"

XAML

<ctrl:uiPopup x:Name="canvas" VerticalOffset="-410" IsOpen="True" AllowsTransparency="True" PopupAnimation="Fade">
</ctrl:uiPopup>

  

C#

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Controls.Primitives;

namespace Micro.UI.Controls
{
    public class uiPopup : Popup
    {
        /// <summary>
        /// 是否窗口随动,默认为随动(true)
        /// </summary>
        public bool IsPositionUpdate
        {
            get { return (bool)GetValue(IsPositionUpdateProperty); }
            set { SetValue(IsPositionUpdateProperty, value); }
        }

        public static readonly DependencyProperty IsPositionUpdateProperty =
            DependencyProperty.Register("IsPositionUpdate", typeof(bool), typeof(uiPopup), new PropertyMetadata(true, new PropertyChangedCallback(IsPositionUpdateChanged)));

        private static void IsPositionUpdateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as uiPopup).pup_Loaded(d as uiPopup, null);
        }

        /// <summary>
        /// 加载窗口随动事件
        /// </summary>
        public uiPopup()
        {
            this.Loaded += pup_Loaded;
        }

        /// <summary>
        /// 加载窗口随动事件
        /// </summary>
        private void pup_Loaded(object sender, RoutedEventArgs e)
        {
            Popup pup = sender as Popup;
            var win = VisualTreeHelper.GetParent(pup);
            while (win != null && (win as Window) == null)
            {
                win = VisualTreeHelper.GetParent(win);
            }
            if ((win as Window) != null)
            {
                (win as Window).LocationChanged -= PositionChanged;
                (win as Window).SizeChanged -= PositionChanged;
                if (IsPositionUpdate)
                {
                    (win as Window).LocationChanged += PositionChanged;
                    (win as Window).SizeChanged += PositionChanged;
                }
            }
        }

        /// <summary>
        /// 刷新位置
        /// </summary>
        private void PositionChanged(object sender, EventArgs e)
        {
            try
            {
                var method = typeof(Popup).GetMethod("UpdatePosition", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                if (this.IsOpen)
                {
                    method.Invoke(this, null);
                }
            }
            catch
            {
                return;
            }
        }

        //是否最前默认为非最前(false)
        public static DependencyProperty TopmostProperty = Window.TopmostProperty.AddOwner(typeof(Popup), new FrameworkPropertyMetadata(false, OnTopmostChanged));
        public bool Topmost
        {
            get { return (bool)GetValue(TopmostProperty); }
            set { SetValue(TopmostProperty, value); }
        }
        private static void OnTopmostChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            (obj as uiPopup).UpdateWindow();
        }

        /// <summary>
        /// 重写拉开方法,置于非最前
        /// </summary>
        /// <param name="e"></param>
        protected override void OnOpened(EventArgs e)
        {
            UpdateWindow();
        }

        /// <summary>
        /// 刷新Popup层级
        /// </summary>
        private void UpdateWindow()
        {
            var hwnd = ((HwndSource)PresentationSource.FromVisual(this.Child)).Handle;
            RECT rect;
            if (NativeMethods.GetWindowRect(hwnd, out rect))
            {
                NativeMethods.SetWindowPos(hwnd, Topmost ? -1 : -2, rect.Left, rect.Top, (int)this.Width, (int)this.Height, 0);
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
        #region P/Invoke imports & definitions
        public static class NativeMethods
        {
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            internal static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
            [DllImport("user32", EntryPoint = "SetWindowPos")]
            internal static extern int SetWindowPos(IntPtr hWnd, int hwndInsertAfter, int x, int y, int cx, int cy, int wFlags);
        }
        #endregion
    }
}

  

原文地址:https://www.cnblogs.com/sntetwt/p/11345072.html

时间: 2024-10-15 16:56:10

自定义WPF Popup控件的相关文章

WPF Popup 控件导致被遮挡内容不刷新的原因

WPF Popup 控件导致被遮挡内容不刷新的原因 周银辉 今天在写一个WPF控件时用到了Popup控件,很郁闷的情况是:当popup关闭时,原来被popup挡住的界面部分不刷新,非要手动刷新一下(比如最大最小化一下窗口),就连网上传说的这个方法也不行 ? 1 2 3 4 5 6 7 8 9 10 public static class UiHelper {     private delegate void NoArgDelegate();     public static void Ref

解决wpf popup控件遮挡其他程序的问题

public class PopupNonTopmost : Popup { public static DependencyProperty TopmostProperty = Window.TopmostProperty.AddOwner( typeof( PopupNonTopmost ), new FrameworkPropertyMetadata( false, OnTopmostChanged ) ); public bool Topmost { get { return (bool

WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书

原文:WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书 最近项目中使用弹出控件Popup,发现弹出框的对齐方式在不同的系统中存在不同(Popup在win10上是弹出在左边,Win7上是弹出在右边).现在记录解决方案于此: 修改弹出菜单相对于相应菜单项是左对齐还是右对齐 // 解决Popup控件在Win7以及Win10等系统中的对齐点方式不一样的问题(以下两种方法均OK) using System.Reflection;    // 方法一 using Sy

WPF第三方控件盘点

WPF统一的编程模型.语言和框架,实现了界面设计人员和开发人员工作可以分离的境界,鉴于WPF强大的优势,且一直是开发者关注的地方,下面和大家分享基于WPF项目开发需要用到的第三方控件,包括业界最受好评的网格控件.图表控件.停靠窗口和文本编辑器. 网格控件 1. Mindscape WPF Property Grid 这款表格控件是100%原生WPF表格控件,是Mindscape公司旗下WPF Elements用户界面套包里的一个商业子控件,当前已经更新到了5.1版本,新的版本在属性表格的性能以及

[转]Oracle分页之二:自定义web分页控件的封装

本文转自:http://www.cnblogs.com/scy251147/archive/2011/04/16/2018326.html 上节中,讲述的就是Oracle存储过程分页的使用方式,但是如果大量的页面要使用这个分页存储过程,如果利用上节的方式,势必要书写大量的代码.如何才能够少些代码书写量呢?当然了,利用自定义web控件进行一下封装,也许是一个好方法,但是如何进行封装呢? 首先,就是在项目中添加一个“Web 用户控件“的页面,我们定义为:MyPagination.ascx 然后,就是

自定义水晶按钮控件

namespace 自定义水晶按钮控件 { partial class Form1 { /// <summary> /// 必需的设计器变量. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 清理所有正在使用的资源. /// </summary> /// <param name="disposing&quo

wpf 修改控件Background

以TextBox 控件为例 一  Brushes.颜色 textBoxName.Background = Brushes.Blue; 二 背景色值#FFD2D2D2 1 .textBoxName.Background=new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFD2D2D2")); 2.textBoxName.Background = new SolidColorBrush(Colors.White);

自定义web用户控件ascx

在页面中使每个产品类别都展示重复的样式又想代码简洁,这时就要设置一个自定义控件. 拖入一个Repeater控件设置好样式 在page_load事件下面写一个属性: protected voidPage_Load(object sender, EventArgs e) { if(!isPostBack) { var data=new T_UserTableAdapter().GetDataById(CatId); Repeater1.DataSource=data; //手动绑定控件 Repeat

iOS开发UI篇—自定义瀑布流控件(蘑菇街数据刷新操作)

iOS开发UI篇—自定义瀑布流控件(蘑菇街数据刷新操作) 一.简单说明 使用数据刷新框架: 该框架提供了两种刷新的方法,一个是使用block回调(存在循环引用问题,_ _weak),一个是使用调用. 问题:在进行下拉刷新之前,应该要清空之前的所有数据(在刷新数据这个方法中). 移除正在显示的cell: (1)把字典中的所有的值,都从屏幕上移除 (2)清除字典中的所有元素 (3)清除cell的frame,每个位置的cell的frame都要重新计算 (4)清除可复用的缓存池. 该部分的代码如下: 1