WPF 无边框圆角阴影窗体 | WPF 只允许当前程序打开一个并激活先前打开的窗体

【WPF 无边框圆角阴影窗体】

XAML:

<Window x:Class="MyApps.MainWindow"
        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"
        mc:Ignorable="d"
        Title="我的应用"
        Height="720"
        Width="1280"
        WindowStyle="None"
        MinHeight="720"
        MinWidth="1280"
        SnapsToDevicePixels="True"
        UseLayoutRounding="True"
        RenderOptions.BitmapScalingMode="HighQuality"
        MaxHeight="{x:Static SystemParameters.MaximizedPrimaryScreenHeight}"
        MaxWidth="{x:Static SystemParameters.MaximizedPrimaryScreenWidth}"
        WindowStartupLocation="CenterScreen"
        ContentRendered="Window_ContentRendered"
        StateChanged="Window_StateChanged">

    <WindowChrome.WindowChrome>
        <WindowChrome GlassFrameThickness="1" CaptionHeight="46" UseAeroCaptionButtons="False"/>
    </WindowChrome.WindowChrome>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="180"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Border Background="White" Grid.ColumnSpan="2" Grid.RowSpan="2"/>

        <Border Grid.Column="0" Grid.RowSpan="2">
            <Border.Background>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF3C14C8"/>
                    <GradientStop Color="#FFB91EC8" Offset="1"/>
                </LinearGradientBrush>
            </Border.Background>
            <Grid>
                <TextBlock Text="我的应用" Margin="0,15,0,0" Foreground="White" FontFamily="Microsoft Yahei UI" FontSize="15" FontWeight="DemiBold" HorizontalAlignment="Center" VerticalAlignment="Top">
                    <TextBlock.LayoutTransform>
                        <!--文本旋转角度-->
                        <RotateTransform Angle="0"/>
                    </TextBlock.LayoutTransform>
                </TextBlock>
            </Grid>
        </Border>
    </Grid>

</Window>

CS:

namespace MyApps
{
    #region Window 窗体事件顺序
    //1.Window.Initialized
    //2.Window.Activatied
    //3.Window.Loaded
    //4.Window.ContentRendered
    //5.Window.DeActivatied
    //6.Window.Closing
    //7.Window.UnLoad
    //8.Window.Closed
    #endregion

    public partial class MainWindow : System.Windows.Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_StateChanged(object sender, System.EventArgs e)
        {
            // 使用WindowChrome属性,窗体最大化后四周会超出屏幕边缘8pixels。
            // 以下代码为修正窗体最大化后溢出屏幕边缘的问题。
            if (WindowState == System.Windows.WindowState.Maximized)
                BorderThickness = new(8);
            else if (WindowState == System.Windows.WindowState.Normal)
                BorderThickness = new(0);
        }

        private void Window_ContentRendered(object sender, System.EventArgs e)
        {

        }
    }
}

【WPF 只允许当前程序打开一个并激活先前打开的窗体】

namespace MyApps
{
    /// <summary>
    /// App.xaml 的交互逻辑
    /// </summary>
    public partial class App : System.Windows.Application
    {
        /// <summary> 
        /// 该设置窗口的显示状态,而无需等待操作完成。 
        /// </summary> 
        /// <param name="hWnd">窗口的句柄。</param> 
        /// <param name="cmdShow">控制窗口的显示方式。 有关可能值的列表,请参阅 ShowWindow 函数的说明。</param> 
        /// <returns>如果操作已成功启动,则返回值为非零值。</returns> 
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool ShowWindowAsync(System.IntPtr hWnd, int cmdShow);
        /// <summary> 
        /// 将创建指定窗口的线程引入前台并激活窗口。 键盘输入将定向到窗口,并为用户更改各种视觉提示。 系统为创建前台窗口的线程分配的优先级略高于其他线程的优先级。
        /// </summary> 
        /// <param name="hWnd">应激活并带到前台的窗口的句柄。</param> 
        /// <returns>如果将窗口带到前台,则返回值为非零值。如果未将窗口带到前台,则返回值为零。</returns> 
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(System.IntPtr hWnd);

        /// <summary>
        /// 检索其类名和窗口名称与指定字符串匹配的顶级窗口的句柄。 此函数不搜索子窗口。 此函数不执行区分大小写的搜索。若要从指定的子窗口开始搜索子窗口,请使用 FindWindowEx 函数。
        /// </summary>
        /// <param name="lpClassName">
        /// 由先前调用 RegisterClass 或 RegisterClassEx 函数创建的类名或类原子。 原子必须位于 lpClassName 的低序字中;高序字必须为零。如果 lpClassName 指向字符串,则指定窗口类名。 类名可以是使用 RegisterClass 或 RegisterClassEx 注册的任何名称,也可以是任何预定义的控件类名称。如果 lpClassName 为 NULL,它将查找其标题与 lpWindowName 参数匹配的任何窗口。</param>
        /// <param name="lpWindowName">窗口名称 (窗口标题) 。 如果此参数为 NULL,则所有窗口名称都匹配。</param>
        /// <returns>如果函数成功,则返回值是具有指定类名称和窗口名称的窗口的句柄。如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。</returns>
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern System.IntPtr FindWindow(string lpClassName, string lpWindowName);

        /// <summary>
        /// 检索创建指定窗口的线程的标识符,以及创建该窗口的进程(可选)的标识符。
        /// </summary>
        /// <param name="hWnd">窗口的句柄。</param>
        /// <param name="processId">指向接收进程标识符的变量的指针。 如果此参数不为 NULL, 则 GetWindowThreadProcessId 会将进程的标识符复制到变量;否则,它不会。 如果函数失败,则变量的值保持不变。</param>
        /// <returns></returns>
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern int GetWindowThreadProcessId(System.IntPtr hWnd, out int processId);

        private const int SW_SHOWNOACTIVATE = 4;

        /// <summary>
        /// 激活并显示已打开的窗体。
        /// </summary>
        /// <param name="process">先前已打开的进程。</param>
        private static void ActivateAndShowWindow(System.Diagnostics.Process process)
        {
            _ = ShowWindowAsync(process.MainWindowHandle, SW_SHOWNOACTIVATE);
            _ = SetForegroundWindow(process.MainWindowHandle);
        }

        /// <summary>
        /// 激活并显示已打开的窗体。
        /// </summary>
        /// <param name="hWnd">窗口句柄。</param>
        private static void ActivateAndShowWindow(System.IntPtr hWnd)
        {
            _ = ShowWindowAsync(hWnd, SW_SHOWNOACTIVATE);
            _ = SetForegroundWindow(hWnd);
        }

        /// <summary>
        /// 获取当前运行程序的进程。
        /// </summary>
        /// <param name="hWnd">匹配的窗口句柄。</param>
        /// <returns>如果匹配到先前已经打开了此程序,则返回先前程序的进程;否则返回空。</returns>
        private System.Diagnostics.Process GetCurrentProcesses(out System.IntPtr hWnd)
        {
            using (System.Diagnostics.Process current = System.Diagnostics.Process.GetCurrentProcess())
            {
                System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(current.ProcessName);
                if (processes.Length > 0)
                {
                    foreach (System.Diagnostics.Process process in processes)
                    {
                        if (process.Id != current.Id)
                        {
                            System.IntPtr hwnd = process.MainWindowHandle;
                            if (hwnd.ToInt32() == 0)
                            {
                                hwnd = FindWindow(null, "我的应用");
                                _ = GetWindowThreadProcessId(hwnd, out int id);
                                if (id == process.Id)
                                {
                                    hWnd = hwnd;
                                    return process;
                                }
                            }
                            else
                            {
                                if (current.MainModule != null)
                                {
                                    if (System.Reflection.Assembly.GetExecutingAssembly().Location.Replace("/", @"\") == current.MainModule.FileName)
                                    {
                                        hWnd = current.MainWindowHandle;
                                        return process;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            hWnd = System.IntPtr.Zero;
            return null;
        }

        protected override void OnStartup(System.Windows.StartupEventArgs e)
        {
            using (System.Diagnostics.Process process = GetCurrentProcesses(out System.IntPtr hWnd))
            {
                if (process != null)
                {
                    if (process.MainWindowHandle != System.IntPtr.Zero)
                        ActivateAndShowWindow(process);
                    else
                        ActivateAndShowWindow(hWnd);
                    System.Environment.Exit(0);
                }
                else
                    base.OnStartup(e);
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值