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!
source to share
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.
source to share
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}"/>
source to share