WPF: How do I make a custom modal dialog flash?

1.9k views Asked by At

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!

2

There are 2 answers

0
Rabid Penguin On BEST ANSWER
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.

1
Bizhan On

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}"/>