Hiding/showing child controls when parent control gains/loses focus - silverlight

I am creating a text editing control that contains a RichTextArea and a toolbar for formatting. I want the toolbar to only be visible when the control has focus. However I am finding this difficult to pull off in Silverlight, as Silverlight's focus API is very limited.
The control is structured like this:
<UserControl x:Class="MyRichTextBoxControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel x:Name="_formattingToolBar" Grid.Row="0" Orientation="Horizontal">
<Button Content="Bold" ... />
<!-- other buttons -->
</StackPanel>
<RichTextBox x:Name="_richTextBox" Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</Grid>
</UserControl>
Initial Stab
At first I tried the obvious, I overrode OnGotFocus and OnLostFocus on the parent UserControl and hid/showed _formattingToolbar appropriately. This does not work, because if a child control gains focus, then Silverlight considers the parent control lost focus. The net result is trying to click on the toolbar causes it to disappear.
Nasty Solution
So far the only solution I have found is to hook up event handlers to the GotFocus and LostFocus events on every single child control and the parent UserControl. The event handler will call FocusManager.GetFocusedElement() and if the returned element is found to be a child of my UserControl, then keep _formattingToolbar visible, otherwise collapse it. I'm sure this will work, but it's pretty ugly.
It's also possible this idea is faulty because GotFocus/LostFocus are fired asynchronously, while GetFocusedElement() is determined synchronously. Could there be race conditions causing my idea to fail?
Anyone know of a better solution?

Nitin Midha, you had the right idea. That brought my back to my original attempt and a slight altering of OnLostFocus does the trick:
protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
if (!IsChild(FocusManager.GetFocusedElement()))
{
HideToolbar();
}
}

protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
object focusedElement = FocusManager.GetFocusedElement();
if (focusedElement is UIElement)
{
if (!this.LayoutRoot.Children.Contains((UIElement)focusedElement))
{
// Do your thing.
}
}
else { /**/ }
}

Related

TabItem Header looks different as a Label

I have a TabItem and was previously setting the Header within the object like so,
<TabItem x:Name="Checked_Out_Items" Header="Clients In Use" Height="40" LostFocus="Checked_Out_Items_LostFocus" GotFocus="Checked_Out_Items_GotFocus" BorderThickness="0" >
However, I've run into the problem where there is not a Click event for this Tab. I found a solution where we can insert a label as the header specified here,
how to handle TabItem single click event in WPF?
But, the Label looks nothing like what I need. Here is the Tab Header defined inside the object.
Here's what it looks like with the label
<TabItem x:Name="Checked_Out_Items" Height="40" LostFocus="Checked_Out_Items_LostFocus" GotFocus="Checked_Out_Items_GotFocus" BorderThickness="0" >
<TabItem.Header>
<Label Content="Clients In Use" Height="40" MouseLeftButtonDown="Checked_Out_Items_Clicked" Width="171" />
</TabItem.Header>
Lets separate the concerns a bit.
In order to handle a mouse click event, a control needs to be prepared for receiving this event, it needs to implement a handler and the handler must actually receive the event. In case of TabItem the mouse click event is consumed by the control, without releasing the event to user defined listeners.
On the level of TabItem, the best option would be to handle the PreviewMouseLeftButtonDown event, but this is not an option if event handling shouldn't occur when child controls have their own handling functionality.
So the other option is to handle the MouseLeftButtonDown event before it reaches the TabItem, which means to handle it in a child control of the tab item.
As said, in order to receive the event, the control needs to be ready to receive the event. This means, it needs a Background not null (can be Transparent) and IsHitTestEnabled="True" (which is default in most cases) and it must actually handle the event.
For the showcase, I use a Red instead of Transparent background color. The red area is the place where mouse clicks are captured and handled.
<TabItem Padding="0">
<TabItem.Header>
<Border Height="30" Width="50"
Background="Red" MouseLeftButtonDown="Item_MouseLeftButtonDown">
<ContentPresenter
VerticalAlignment="Center" HorizontalAlignment="Center"
Content="T2"/>
</Border>
</TabItem.Header>
Test Content 2
</TabItem>
Or, in order to have a better separation between header content and click handling, a HeaderTemplate can be used:
<TabItem Header="T3" Padding="0">
<TabItem.HeaderTemplate>
<DataTemplate>
<Border MinHeight="30" MinWidth="50"
Background="Red" MouseLeftButtonDown="Item_MouseLeftButtonDown">
<ContentPresenter
VerticalAlignment="Center" HorizontalAlignment="Center"
Content="{Binding}"/>
</Border>
</DataTemplate>
</TabItem.HeaderTemplate>
Test Content 3
</TabItem>
The issue with any approach that relies on child controls is, that there is still a border of the TabItem and if the user clicks that border, the click will be outside of the child control and the tab will be selected without executing the click handler.
So a different way to handle tab changes (not clicks!) would be to handle the TabControl.SelectionChanged event and filter for events that actually originate from the TabControl and not from some inner content elements.
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.Source == sender)
{
// this selection change is actually issued because of a tab change
}
}
Another thing I just realized: The same condition could be used in TabItem.PreviewMouseLeftButtonDown in order to filter clicks to the tabitem header vs click events originating from the content area.
Edit:
The reason why Label is looking different is, that a font style is active for TabItem and Label is using some of its internal styles, ignoring the TabItem style.

WebBrowser control keyboard and focus behavior

Apparently, there are some serious keyboard and focus issues with WPF WebBrowser control. I've put together a trivial WPF app, just a WebBrowser and two buttons. The app loads a very basic editable HTML markup (<body contentEditable='true'>some text</body>) and demonstrates the following:
Tabbing is misbehaving. User needs to hit Tab twice to see the caret (text cursor) inside WebBrowser and be able to type.
When user switches away from the app (e.g., with Alt-Tab), then goes back, the caret is gone and she is unable to type at all. A physical mouse click into the WebBrowser's window client area is required to get back the caret and keystrokes.
Inconsistently, a dotted focus rectangle shows up around WebBrowser (when tabbing, but not when clicking). I could not find a way to get rid of it (FocusVisualStyle="{x:Null}" does not help).
Internally, WebBrowser never receives the focus. That's true for both logical focus (FocusManager) and input focus (Keyboard). The Keyboard.GotKeyboardFocusEvent and FocusManager.GotFocusEvent events never get fired for WebBrowser (although they both do for buttons in the same focus scope). Even when the caret is inside WebBrowser, FocusManager.GetFocusedElement(mainWindow) points to a previously focused element (a button) and Keyboard.FocusedElement is null. At the same time, ((IKeyboardInputSink)this.webBrowser).HasFocusWithin() returns true.
I'd say, such behaviour is almost too dysfunctional to be true, but that's how it works. I could probably come up with some hacks to fix it and bring it in row with native WPF controls like TextBox. Still I hope, maybe I'm missing something obscure yet simple here. Has anyone dealt with a similar problem? Any suggestions on how to fix this would be greatly appreciated.
At this point, I'm inclined to develop an in-house WPF wrapper for WebBrowser ActiveX Control, based upon HwndHost. We are also considering other alternatives to WebBrowser, such as Chromium Embedded Framework (CEF).
The VS2012 project can be downloaded from here in case someone wants to play with it.
This is XAML:
<Window x:Class="WpfWebBrowserTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="640" Height="480" Background="LightGray">
<StackPanel Margin="20,20,20,20">
<ToggleButton Name="btnLoad" Focusable="True" IsTabStop="True" Content="Load" Click="btnLoad_Click" Width="100"/>
<WebBrowser Name="webBrowser" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="300"/>
<Button Name="btnClose" Focusable="True" IsTabStop="True" Content="Close" Click="btnClose_Click" Width="100"/>
</StackPanel>
</Window>
This is C# code, it has a bunch of diagnostic traces to show how focus/keyboard events are routed and where the focus is:
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;
namespace WpfWebBrowserTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// watch these events for diagnostics
EventManager.RegisterClassHandler(typeof(UIElement), Keyboard.PreviewKeyDownEvent, new KeyEventHandler(MainWindow_PreviewKeyDown));
EventManager.RegisterClassHandler(typeof(UIElement), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(MainWindow_GotKeyboardFocus));
EventManager.RegisterClassHandler(typeof(UIElement), FocusManager.GotFocusEvent, new RoutedEventHandler(MainWindow_GotFocus));
}
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
// load the browser
this.webBrowser.NavigateToString("<body contentEditable='true' onload='focus()'>Line 1<br>Line 3<br>Line 3<br></body>");
this.btnLoad.IsChecked = true;
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
// close the form
if (MessageBox.Show("Close it?", this.Title, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
this.Close();
}
// Diagnostic events
void MainWindow_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
Debug.Print("{0}, source: {1}, {2}", FormatMethodName(), FormatType(e.Source), FormatFocused());
}
void MainWindow_GotFocus(object sender, RoutedEventArgs e)
{
Debug.Print("{0}, source: {1}, {2}", FormatMethodName(), FormatType(e.Source), FormatFocused());
}
void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
Debug.Print("{0}, key: {1}, source: {2}, {3}", FormatMethodName(), e.Key.ToString(), FormatType(e.Source), FormatFocused());
}
// Debug output formatting helpers
string FormatFocused()
{
// show current focus and keyboard focus
return String.Format("Focus: {0}, Keyboard focus: {1}, webBrowser.HasFocusWithin: {2}",
FormatType(FocusManager.GetFocusedElement(this)),
FormatType(Keyboard.FocusedElement),
((System.Windows.Interop.IKeyboardInputSink)this.webBrowser).HasFocusWithin());
}
string FormatType(object p)
{
string result = p != null ? String.Concat('*', p.GetType().Name, '*') : "null";
if (p == this.webBrowser )
result += "!!";
return result;
}
static string FormatMethodName()
{
return new StackTrace(true).GetFrame(1).GetMethod().Name;
}
}
}
[UPDATE] The situation doesn't get better if I host WinForms WebBrowser (in place of, or side-by-side with WPF WebBrowser):
<StackPanel Margin="20,20,20,20">
<ToggleButton Name="btnLoad" Focusable="True" IsTabStop="True" Content="Load" Click="btnLoad_Click" Width="100"/>
<WebBrowser Name="webBrowser" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="150" Margin="10,10,10,10"/>
<WindowsFormsHost Name="wfHost" Focusable="True" Height="150" Margin="10,10,10,10">
<wf:WebBrowser x:Name="wfWebBrowser" />
</WindowsFormsHost>
<Button Name="btnClose" Focusable="True" IsTabStop="True" Content="Close" Click="btnClose_Click" Width="100"/>
</StackPanel>
The only improvement is that I do see focus events on WindowsFormsHost.
[UPDATE] An extreme case: two WebBrowser controls with two carets showing at the same time:
<StackPanel Margin="20,20,20,20">
<ToggleButton Name="btnLoad" Focusable="True" IsTabStop="True" Content="Load" Click="btnLoad_Click" Width="100"/>
<WebBrowser Name="webBrowser" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="150" Margin="10,10,10,10"/>
<WebBrowser Name="webBrowser2" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="150" Margin="10,10,10,10"/>
<Button Name="btnClose" Focusable="True" IsTabStop="True" Content="Close" Click="btnClose_Click" Width="100"/>
</StackPanel>
this.webBrowser.NavigateToString("<body onload='text.focus()'><textarea id='text' style='width: 100%; height: 100%'>text</textarea></body>");
this.webBrowser2.NavigateToString("<body onload='text.focus()'><textarea id='text' style='width: 100%; height: 100%'>text2</textarea></body>");
This also illustrates that the focus handling issue is not specific to contentEditable=true content.
For anyone else stumbling upon this post and needing to set keyboard focus to the browser control (not a particular element within the control, necessarily), this bit of code worked for me.
First, add a project reference (under Extensions in VS) for Microsoft.mshtml.
Next, whenever you'd like to focus the browser control (say for example, when the Window loads), simply "focus" the HTML document:
// Constructor
public MyWindow()
{
Loaded += (_, __) =>
{
((HTMLDocument) Browser.Document).focus();
};
}
This will place keyboard focus inside the web browser control, and inside the "invisible" ActiveX window, allowing keys like PgUp / PgDown to work on the HTML page.
If you want to, you might be able to use DOM selection to find a particular element on the page, and try to focus() that particular element. I have not tried this myself.
The reason it behaves this way is related to the fact that it's an ActiveX control which itself is a fully windows class (it handles mouse and keyboard interaction). In fact much of the time you see the component used you'll find it is the main component taking up a full window because of this. It doesn't have to be done that way but it presents issues.
Here's a forum discussing the exact same issue and it's causes can be clarified by reading the last commentators article links:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/1b50fec6-6596-4c0a-9191-32cd059f18f7/focus-issues-with-systemwindowscontrolswebbrowser
To outline the issues you're having
Tabbing is misbehaving. User needs to hit Tab twice to see the caret (text cursor) inside WebBrowser and be able to type.
that's because the browser control itself is a window which can be tabbed to. It doesn't "forward" the tab to it's child elements immediately.
One way to change this would be to handle the WM message for the component itself but keep in mind that doing so gets tricky when you want the "child" document inside of it to be able to handle messages.
See: Prevent WebBrowser control from stealing focus? specifically the "answer". Although their answer doesn't account that you can control whether the component interacts through dialogs with the user by setting the Silent property (may or may not exist in the WPF control... not sure)
When user switches away from the app (e.g., with Alt-Tab), then goes back, the caret is gone and she is unable to type at all. A physical mouse click into the WebBrowser's window client area is required to get back the caret and keystrokes.
This is because the control itself has received the focus. Another consideration is to add code to handle the GotFocus event and to then "change" where the focus goes. Tricky part is figuring out if this was "from" the document -> browser control or your app -> browser control. I can think of a few hacky ways to do this (variable reference based on losing focus event checked on gotfocus for example) but nothing that screams elegant.
Inconsistently, a dotted focus rectangle shows up around WebBrowser (when tabbing, but not when clicking). I could not find a way to get rid of it (FocusVisualStyle="{x:Null}" does not help).
I wonder if changing Focusable would help or hinder. Never tried it but I'm going to venture a guess that if it did work it would stop it from being keyboard navigable at all.
Internally, WebBrowser never receives the focus. That's true for both logical focus (FocusManager) and input focus (Keyboard). The Keyboard.GotKeyboardFocusEvent and FocusManager.GotFocusEvent events never get fired for WebBrowser (although they both do for buttons in the same focus scope). Even when the caret is inside WebBrowser, FocusManager.GetFocusedElement(mainWindow) points to a previously focused element (a button) and Keyboard.FocusedElement is null. At the same time, ((IKeyboardInputSink)this.webBrowser).HasFocusWithin() returns true.
People have hit issues with where 2 browser controls both show the focus(well... the caret) or even had a hidden control take the focus.
All in all it's pretty awesome what you can do with the component but it's just the right mix of letting you control/change the behavior along with predefined sets of behavior to be maddening.
My suggestion would be to try to subclass the messages so you can direct the focus control directly through code and bypass it's window from trying to do so.

Forcing layout update

How to force the layout measurements update?
I have simplified layout I am problem with; when you click the button first time you get one measurement and on the second click different one.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var w = mywindow.ActualWidth;
gridx.Width = w;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
btn3.Width = 100;
var w = mywindow.ActualWidth;
gridx.Width = w - btn3.Width;
InvalidateArrange();
InvalidateMeasure();
MessageBox.Show(btn1.ActualWidth.ToString());
}
Window
<Window x:Class="resizet.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" Name="mywindow">
<DockPanel HorizontalAlignment="Stretch" LastChildFill="False">
<Grid HorizontalAlignment="Stretch" DockPanel.Dock="Left" Name="gridx">
<Button HorizontalAlignment="Stretch" Content="btn in grid" Click="Button_Click" />
</Grid>
<Button Name="btn2" Content="btn2" Width="0" DockPanel.Dock="Right" HorizontalAlignment="Left"></Button>
</DockPanel>
</Window>
This fixes the problem:
btn3.Width = 100;
btn3.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
var w = mywindow.ActualWidth;
gridx.Width = w - btn3.Width;
with additional
private static Action EmptyDelegate = delegate() { };
Changing the Width property must invalidate the layout on its own, you don't need to call InvalidateXXX() yourself.
The catch is that the layout is not updated immediately, but on the next iteration of the message loop. So the ActualWidth will not be changed immediately.
If you want the Grid to resize automatically when the button width is increasing, why not use the layout management and put the both into different columns of an outer Grid?
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid x:Name="gridx"
Grid.Column="0">
<Button HorizontalAlignment="Stretch"
Click="Button_Click"/>
</Grid>
<Button x:Name="btn2"
Content="btn2"
Width="0"
Grid.Column="1"/>
</Grid>
And in code-behind
private void Button_Click(object sender, RoutedEventArgs e)
{
btn2.Width = 100;
}
In a strict sense, #Daniel has provided some code that fixes the problem posed by the question. But the result is rather bad, putting layouting code into an event handler. The grid and the button might look good after the button got pressed, but once the user makes the window size bigger, the grid will not grow and will not use the available size. The user would have to press the button again to make the grid grow. That's most likely not how things should be and that's why #Vlad's answer is better.
WPF uses just one thread to process events and layouting, but they get executed in different phases. If width gets changed, the MeasureDirty flag of the control gets set, then the processing of the event continues immediately. Once this event and all other events needing processing are completed, only then starts WPF with the layouting (i.e. measure, arrange, render). Here is an overview how that works:
For a detailed description what happens in every step, see my article on CodeProject Deep Dive into WPF Layouting and Rendering
btn3.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
This statement halts the execution of the button event handler and forces a whole layouting / render phase to run, only then continues with the event handler code to change the width of the grid, which will force another layouting / render cycle to run.
Recommendations:
Do not set Height and Width in event handlers, unless you want them to be fixed and not to change, even the available space changes.
Use WPF controls like Grid, etc. to make best use of the available space
If you cannot find a WPF control like Grid which matches your layouting needs, write your own Control and put all the layouting code into MeasureOverride() and ArrangeOverride().

WPF Routed Event, subscribing to custom events

I am trying to get routed events working with child controls that will manually fire these events and they will bubble up and be handled at the main grid level. I basically want to do something like this:
<Grid Name="Root" WpfApplication5:SpecialEvent.Tap="Catcher_Tap">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<WpfApplication5:UserControl2 Grid.Row="0" x:Name="Catcher" />
<WpfApplication5:UserControl1 Grid.Row="1" />
<Frame Grid.Row="2" Source="Page1.xaml" />
</Grid>
But when I run my example, I get a null reference in the presentation framework, the application never initializes, it fails when it's trying to load/initialize the XAML (InitializeComponent()). Here's the small file that contains the event:
public class SpecialEvent
{
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
"Tap", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(UserControl1));
// Provide CLR accessors for the event
public event RoutedEventHandler Tap;
}
I am basically wanting to copy the behavior of how ButtonBase.Click allows parents to subscribe to any button click() methods for their children. But, this doesn't seem to be working for anything but ButtonBase.Click(). That is, when I switch out my custom WpfApplication5:SpecialEvent.Tap="Catcher_Tap" to ButtonBase.Click="Catcher_Tap" it works. Any ideas why? What is ButtonBase doing that I'm not doing?
After playing around some more, I found that it's possible to accomplish what I needed in the code behind of the main window like so:
public MainWindow()
{
InitializeComponent();
Root.AddHandler(SpecialEvent.TapEvent, new RoutedEventHandler(Catcher_Tap));
}
For some reason, specifying it in the XAML as you would do for ButtonBase() does not work, but adding the Handler in the code behind does.
The code you provided does register a custom event, however, it doesn't register an attached custom event. You'll have to explicitly implement the Add*Handler and Remove*Handler methods if you would like to use the attached syntax with your event. See the "Defining Your Own Attached Events as Routed Events" section on this MSDN article.

WPF: Handling Modal Dialogs

I found a nice solution on this webiste http://www.thesilvermethod.com/Default.aspx?Id=ModalDialogManagerAsimpleapproachtodealingwithmodaldialogsinMVVM
But had to do some changes to get it integrated into my code. Along the way I get some small problems mostly because there are certain parts of the code I'm not getting completely.
How I did it was to bind the ModalDialogManager to a MainWindow property of the Type IDialogViewModel. I then have a WindowsManager class that handles putting the right instance inside this property. One such is EditDialogViewModel that exposes a EditableViewModel to this DialogManager. I set the EditDialog view as a DataTemplate for this EditDialogViewModel but when I show it the new window only shows a part of it.
Here is the View:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="EditDataTemplates.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="7*" />
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<ContentControl Content="{Binding Path=ViewModel}" />
<TextBlock Text="{Binding Path=ViewModel.Error}" />
<UniformGrid Grid.Row="2" Columns="2">
<Button Command="{Binding SaveCommand}" />
<Button Command="{Binding CancelCommand}" />
</UniformGrid>
</Grid>
</UserControl>
But the new Dialog window only shows the ContentControl bound to the ViewModel property of EditDialogViewModel (it holds the ViewModel being edited).
My guess is it has something to do with this code in the ModelDialogManager:
void Show()
{
if (_window != null) Close();
Window w = new Window();
_window = w;
w.Closing += w_Closing;
w.Owner = GetParentWindow(this);
w.DataContext = this.DataContext;
w.SetBinding(Window.ContentProperty, ""); //This code here does something I don't fully understand
w.Title = Title;
w.Icon = Icon;
w.Height = DialogHeight;
w.Width = DialogWidth;
w.ResizeMode = DialogResizeMode;
w.ShowDialog();
}
He is applying the binding there but I guess it's only the first ContentControl that gets bound or something. It's quite tricky.
Another problem is that the mouse just doesn't work inside the Modal Dialog. I can tab into the textboxes but not click into them.
Is there a way to fix this or a better method to handle Modal Dialog boxes in WPF?
EDIT
Ok I'm going to admit it. I'm a huge idiot. This was so simple I just couldn't see it. I had set Height and Width on the UserControl to a fixed value while I was still messing around with it being a Window. So in actuality it was showing the whole thing, there just wasn't room. I have no idea why the mouse didn't work at that point but now it works perfectly.
Answering "a better method to handle Modal Dialog boxes in WPF?" there is a new control called Child Window in the WPF Extended Toolkit that addresses your Modal Dialog pains.

Resources