WPF: How to create custom modal dialogs?

Usually when you open a Modal Dialog and try to click on its parent window, the Modal Dialog title bar lights up. When you create a custom, borderless, chrome window in WPF, you lose all those features and have to rebuild it yourself. I looked high and low and for me life cannot figure out how to make my Modal blink. Although it still sounds ...

I suppose I will need to keep track of some events in WndProc that I will have to handle, but I cannot figure out which event or how to do it. I've tried watching for window change and window change event as well as WM_ACTIVATE event to no avail. I'm sure I just missed something simple, but I would appreciate any help on this. Thank!

+3


source to share


2 answers


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;
    }

      

WndProc I hooked up to a custom behavior that is bound to my window. It calls an internal method on my window that will update the title color accordingly.



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

+4


source


If you didn't exactly find what you were looking for, there is a workaround that doesn't use the modal at all.

Here's how you can do it:

  • create a custom control MainContentUC and put the content of MainWindow in it
  • create another custom control named MessageBoxUC and put your mailbox content 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>
    
          

  • add boolean dependency property to MessageBoxUC named IsOpen (default = false)

  • write your main window xaml like this:

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



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

If you have multiple windows, you can implement different control patterns and choose between them using the pattern selector. so instead <local:MainContentsUC/>

you will have

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

0


source







All Articles