5

Normally when you open a Modal Dialog and try to click on it's parent window the Modal Dialog's titlebar flashes. When creating a custom, borderless, chromeless, window in WPF you lose all that functionality and must rebuild it yourself. I've looked high and low and for the life of me cannot figure out how to get my Modal window to flash. Though it still beeps...

I figure I'm going to have to watch for some event(s) in WndProc that I'll have to handle, but I can't figure out which event or how to do it. I've tried watching the window changed and window changing event as well as the WM_ACTIVATE event to no avail. I'm sure I'm just missing something simple, but I would appreciate any help on this. Thanks!

Rabid Penguin
  • 1,084
  • 9
  • 22
  • It is the WM_NCACTIVATE message. The Spy++ utility can tell you these things. – Hans Passant Nov 26 '14 at 22:39
  • I used spy++, but from what I can tell WM_NCACTIVATE sends the same exact message whether it's a modal window that's losing focus or a nonmodal window. That doesn't seem very helpful. It also just tells me that the window is being activated, I'm not sure how to tell from that, that I need to FLASH the title bar, rather than just drawing an active title bar. Could you be more specific? – Rabid Penguin Nov 27 '14 at 00:48
  • The point is that it sends the message many times. Thus making it flash. – Hans Passant Nov 27 '14 at 00:49
  • oooooh. I gotcha... apparently just because a deactivate message was sent doesn't mean that the window's IsActive property actually changes. – Rabid Penguin Nov 27 '14 at 00:53
  • It is not the deactivate message, that's WM_ACTIVATE. The "NC" messages are the "what the frame of the window should look like" messages. "NC" == non-client. – Hans Passant Nov 27 '14 at 00:57
  • Thanks for the nudge! I was able to get it to work. I think I've just been staring it at too much. :p – Rabid Penguin Nov 27 '14 at 01:23

2 Answers2

5
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        var retVal = IntPtr.Zero;

        switch (msg)
        {
            case UnsafeNativeConstants.WM_NCACTIVATE:
                retVal = UnsafeNativeMethods.DefWindowProc(hwnd, UnsafeNativeConstants.WM_NCACTIVATE, new IntPtr(1), new IntPtr(-1));
                AssociatedObject.UpdateTitlebar((int)wParam == 1 ? true : false);
                handled = true;
                break;
        }

        return retVal;
    }

The WndProc I have hooked up in a custom behavior that's attached to my window. It calls an internal method on my window that will update the color of the Titlebar appropriately.

Thanks to @Hans Passant for pointing me in the right direction.

Rabid Penguin
  • 1,084
  • 9
  • 22
0

If you didn't exactly find what you're looking for, there is a workaround which involves not using a modal window at all.

Here's how you can do it:

  1. create a user control named MainContentUC and put the contents of MainWindow in it
  2. create another user control named MessageBoxUC and put the contents of your messagebox in it

    <UserControl x:Name="root" Visibility="{Binding ElementName=root, Path=IsOpen}">
        <Grid Background="#4FFF"/>
            <Border HorizontalAlignment="Center" VerticalAlignment="Center" 
                    x:Name="border" Background="White"/>
            <Grid.Triggers>
                <EventTrigger RoutedEvent="MouseDown">
                    <BeginStoryboard>
                        <Storyboard Duration="0:0:1">
                            <ColorAnimation 
                                 Storyboard.TargetName="border" 
                                 Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" 
                                 To="Black" Duration="0:0:.2" RepeatBehavior="Forever"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Grid.Triggers>
        </Grid>
    </UserControl>
    
  3. add a boolean dependency property in MessageBoxUC named IsOpen (default=false)

  4. write xaml code of your main window as follows:

    <Window xmlns:local="clr-namespace:MyWpfApplication">
        <Grid>
            <local:MainContentsUC/>
            <local:MessageBoxUC/>
        </Grid>
    </Window>
    

This way when the MessageBoxUC is open it will block MainContentsUC from being clicked. and when you click on the back area (where color is set to #4FFF) the trigger runs the storyboard and it blinks.

if you have several windows you can implement different control templates and choose between them using a template selector. so instead of <local:MainContentsUC/> you will have

<ContentPresenter ContentTemplateSelector="{StaticResource mySelector}"/>

Bizhan
  • 16,157
  • 9
  • 63
  • 101
  • I want it to be a new window rather than just a control. @Hans Passant got me pointed in the right direction. Thanks for the help though! – Rabid Penguin Nov 27 '14 at 01:24