[ACCEPTED]-Window StateChanging event in WPF-xaml

Accepted answer
Score: 17

Found windows messages called on window 7 right before minimize using Spy++. First 6 one that is called is WM_WINDOWPOSCHANGING. I 5 didn't know windows is moving window on 4 -32000, -32000 location point when minimizing 3 widow, and those were the params in WM_WINDOWPOSCHANGING. Though, I 2 have tested is only on Vista. http://blogs.msdn.com/oldnewthing/archive/2004/10/28/249044.aspx

code used 1 here was posted by Nir here

here is sample code

xaml:

<Window x:Class="WindowStateTest2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>

        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
        <Button Click="btnClear_Click" Grid.Row="0" x:Name="btnClear">Clear</Button>            

        <TextBox Name="txt" VerticalScrollBarVisibility="Visible" Grid.Row="2"></TextBox>
</Grid>
</Window>

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace WindowStateTest2
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        this.StateChanged += new EventHandler(Window1_StateChanged);
        this.SourceInitialized += new EventHandler(Window1_SourceInitialized);

    }

    #region Event handlers

    void btnClear_Click(object sender, RoutedEventArgs e)
    {
        this.txt.Text = string.Empty;
    }
    void Window1_SourceInitialized(object sender, EventArgs e)
    {
        AttachWndProc();
    }

    void Window1_StateChanged(object sender, EventArgs e)
    {
        if (this.WindowState == WindowState.Minimized)
            Console.WriteLine("SC: " + this.WindowState);
    } 

    #endregion

    #region Const

    private int SYSCOMMAND = 0x0112;
    private int SC_MINIMIZE = 0xf020;
    private int WINDOWPOSCHANGING = 0x0046;

    #endregion

    private void AttachWndProc()
    {
        HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
        source.AddHook(new HwndSourceHook(WndProc));
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct WINDOWPOSPARAMS
    {
        public IntPtr hwnd;
        public IntPtr hwndInsertAfter;
        public int x;
        public int y;
        public int cx;
        public int cy;
        public int flags;
    }


    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WINDOWPOSCHANGING)               
        {
            WINDOWPOSPARAMS param = (WINDOWPOSPARAMS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOSPARAMS));
            if (param.x == -32000 && param.y == -32000)
            {
                Output("");

                                    // EVENT WOULD BE RAISED HERE

                Output("State before minimize:");
                Output(string.Format("CurrentState: {0}", this.WindowState));
                Output(string.Format("Location {0} {1}: ", this.Top, this.Left));
                Output("");
            }
        }

        // process minimize button
        if (msg == SYSCOMMAND && SC_MINIMIZE == wParam.ToInt32())
        {
            Output("Minimize clicked");             
        }

        handled = false;
        return IntPtr.Zero;
    }

    public void Output(object output)
    {
        this.txt.Text += output.ToString();
        this.txt.Text += Environment.NewLine;           
    }       

}
}
Score: 0

I don't think you'll be able to do it directly.

A 22 Minimize call to the window can happen from 21 a number of places, not just the minimize 20 button on the Window Chrome (e.g. The right 19 clicking on the TaskBar, or from Windows 18 Task Manager), and AFAIK, there's no way 17 to directly handle button events fired from 16 the Window Chrome (if somebody does know 15 how to do this, please let me know!).

The 14 good news is that you can fake it, but it's not trivial, so 13 you'll have to decide if it's worth it. First, you'll 12 have to replace the standard Window Chrome 11 with your own. You can find out how to 10 do that here.

Secondly, you'll have to create 9 your own "Maximize/Minimize/Close" Buttons 8 and wire up the events to the appropriate 7 behaviors. Since this is your own UI, you 6 are free to listen to and cancel the Button 5 events as you choose.

Keep in mind that you 4 still won't be able to detect or prevent 3 users from Minimizing via the TaskBar/Windows 2 Task Manager, so it may not be exactly what 1 you're looking for.

More Related questions