Link to home
Start Free TrialLog in
Avatar of Russ Suter
Russ Suter

asked on

How do I get my WPF window to ignore mouse events (except for the close button)?

Having the following very simple Xaml:
<Window x:Class="WPF_Tests.MainWindow"
        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"
        xmlns:local="clr-namespace:WPF_Tests"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        WindowStyle="None"
        AllowsTransparency="True">
    <Window.Background>
        <SolidColorBrush Opacity="0.5" Color="Black"/>
    </Window.Background>
    <Grid>
        <Button HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,10,10,0">
            Close
        </Button>
        <TextBlock x:Name="textBlock" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" Foreground="White" FontSize="36">
            This is a sample message
        </TextBlock>
    </Grid>
</Window>

Open in new window

How do I make it such that all mouse events are passed through the window except for when in the button control? I want to be able to not only see through the window but click through it as well but still have a way of closing the window by clicking on the button.
Avatar of Unimatrix_001
Unimatrix_001
Flag of United Kingdom of Great Britain and Northern Ireland image

I don't know if I can help, but for clarification, do you mean you want the mouse events to pass through the window as though the window wasn't even present other than the close button? For example in the image, you could select text under the window that is infact a different application?

User generated image
Avatar of Russ Suter
Russ Suter

ASKER

Yes, that's what I want to be able to do. In the above screenshot the C# code should still be selectable, clickable, etc... via mouse. The text "This is a sample message" would not interact with the mouse at all. The close button in the top right corner should still respond to mouseover and click events. Mouseover would be used to change the foreground color of the button to show the user that they can click on it. The mouse click event would be used (obviously) to dismiss the overlay window.
There are two parts to your question:

1. You want the window to be visible but being invisible to user input, you can do this as follows:

<Window x:Class="WpfApp1.MainWindow"
        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"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        WindowStyle="None"
        AllowsTransparency="True"
        Topmost="True">
    <Window.Background>
        <SolidColorBrush Opacity="0.5" Color="Black"/>
    </Window.Background>
    <Grid>
        <Button HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,10,10,0" Name="Button_Close">
            Close
        </Button>
        <TextBlock x:Name="textBlock" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" Foreground="White" FontSize="36">
            This is a sample message
        </TextBlock>
    </Grid>
</Window>

Open in new window

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace WpfApp1
{

    public partial class MainWindow : Window
    {

        [DllImport("user32.dll")]
        static extern int GetWindowLong(IntPtr hwnd, int index);

        [DllImport("user32.dll")]
        static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);

        public const int WS_EX_TRANSPARENT = 0x00000020;
        public const int GWL_EXSTYLE = (-20);

        public MainWindow()
        {
            InitializeComponent();
            Loaded += (a, b) => { var hwnd = new WindowInteropHelper(this).Handle; SetWindowExTransparent(hwnd); };
            Button_Close.Click += (a, b) => { Close(); };
        }

        public static void SetWindowExTransparent(IntPtr hwnd)
        {
            var extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
            SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
        }

        public static void UnsetWindowExTransparent(IntPtr hwnd)
        {
            int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
            SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle & ~WS_EX_TRANSPARENT);
        }

    }

}

Open in new window

2. The second part of the question I would suggest you make a new one for as it would be more focused and garner more attention. What you want to do which I have tried but not had any success with, you need to hook the mouse move event globally and check on each mouse move if the cursor is within the bounds of the close button. If so and the left mousen button is clicked then you fire the close button click event.
This question needs an answer!
Become an EE member today
7 DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.