AvalonDock Now Loses Alt Key Adornments - wpf

I've been using AvalonDock (2.0) for some time now, being key for managing documents in an IDE. In the last month or so, I've noticed that Alt key adornments are no longer showing up for controls within AvalonDock, though the Alt key commands are executing as expected. See the image below where the Alt key adornments are showing up in the menu, but not for the buttons inside AvalonDock:
What is particularly interesting about this issue, that it appears to be triggered by an environmental setting or condition.
As demonstrated in this video (at 2:07), the alt key adornments are working for a control within AvalonDock. But, if I now use the very same executable I used in that video, the alt key adornments do not work.
I'm currently using build 2.0.1746, but I also tried build 2.0.2000 (with the Xceed namespace) and found the same issue. I also tried the version packaged with the Xceed Extended WPF Toolkit, and found that the issue persists.
I also built a very simple test application which loads a couple of documents of type Item, where Item is a simple class with a Name property:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:avalonDock="clr-namespace:Xceed.Wpf.AvalonDock;assembly=Xceed.Wpf.AvalonDock"
xmlns:avalonDockLayout="clr-namespace:Xceed.Wpf.AvalonDock.Layout;assembly=Xceed.Wpf.AvalonDock"
xmlns:avalonDockControls="clr-namespace:Xceed.Wpf.AvalonDock.Controls;assembly=Xceed.Wpf.AvalonDock"
Title="MainWindow" Height="500" Width="500">
<Window.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type local:Item}">
<StackPanel Orientation="Vertical">
<Label Content="Item:" />
<TextBox Text="{Binding Name}"/>
<Button Content="_ClickMe" />
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<avalonDock:DockingManager Grid.Row="0" DocumentsSource="{Binding}">
<avalonDockLayout:LayoutRoot>
<avalonDockLayout:LayoutPanel Orientation="Horizontal">
<avalonDockLayout:LayoutDocumentPane/>
</avalonDockLayout:LayoutPanel>
</avalonDockLayout:LayoutRoot>
</avalonDock:DockingManager>
<Button Grid.Row="1" Content="_Test" />
</Grid>
</Window>
Even with this simple application, the Alt key adornments show up for the Test button outside of AvalonDock, but not for the ClickMe buttons for the controls within AvalonDock.
I also posted the issue here on the AvalonDock codeplex site, but there appears to be very little response activity. I also posted the issue here on the Extended Toolkit codeplex site.
Any ideas on how to correct or workaround this issue?

It sounds as though this will be fixed with the next version of AvalonDock.
In the meantime, the following Blend behavior is a workaround:
public class FixKeyboardCuesBehavior : Behavior<UIElement>
{
private static readonly DependencyProperty ShowKeyboardCuesProperty;
static FixKeyboardCuesBehavior()
{
Type keyboardNavigation = typeof(KeyboardNavigation);
var field = keyboardNavigation.GetField("ShowKeyboardCuesProperty", BindingFlags.NonPublic | BindingFlags.Static);
Debug.Assert(field != null, "field != null");
ShowKeyboardCuesProperty = (DependencyProperty)field.GetValue(null);
}
protected override void OnAttached()
{
base.OnAttached();
Window rootWindow = Window.GetWindow(this.AssociatedObject);
if (rootWindow == null)
{
return;
}
BindingOperations.SetBinding(
this.AssociatedObject,
ShowKeyboardCuesProperty,
new Binding("(KeyboardNavigation.ShowKeyboardCues)") { Source = rootWindow });
}
}
Use this from XAML by adding the following to the root element of your DataTemplate for the AvalonDock LayoutItemTemplate:
<i:Interaction.Behaviors
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<my:FixKeyboardCuesBehavior />
</i:Interaction.Behaviors>
This workaround uses internal implementation details of WPF to re-introduce the Alt behaviour below the broken AvalonDock logical tree. So, I'll be looking forward to being able to zap it from my code when AD itself is fixed!

Related

Using named in reusable WPF control

I recentrly discovered "reusable controls" in WPF and I have a project where they seem to provide me with a solution to a problem I have.
Let me sketch the situation:
I need to make several UI elements. All of them share a common base, a common style/layout/template let's say, and they also share some common logic.
Next to that, all of these elements have some element-specific stuff.
You could say that I have some kind of inheritance here, but then for both XAML and CS.
The way I wanted to solve this, was by making an outer reusable element, I made a small example. The common part Is the Title label and the border. The element-specific UI can then be inserted into UserContent.
The code looks something like this (although it's simplified for the sake of brevity and conciseness, I also have an eventhandler and a routed event in my actual application):
ReusableControl.xaml
<UserControl x:Class="StackOverflowQuestion4.ReusableControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root">
<Border BorderBrush="Black"
BorderThickness="1"
Width="400"
Height="200">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="{Binding Title, ElementName=root}"
Grid.Row="0"/>
<ContentControl Content="{Binding UserContent, ElementName=root}"
Grid.Row="1"/>
</Grid>
</Border>
</UserControl>
ReusableControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace StackOverflowQuestion4
{
public partial class ReusableControl : UserControl
{
public ReusableControl()
{
InitializeComponent();
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(ReusableControl), new PropertyMetadata(string.Empty));
public object UserContent
{
get { return GetValue(UserContentProperty); }
set { SetValue(UserContentProperty, value); }
}
public static readonly DependencyProperty UserContentProperty =
DependencyProperty.Register("UserContent", typeof(object), typeof(ReusableControl), new PropertyMetadata(string.Empty));
}
}
Lovely, I can now use my special control in other parts of my code, and I can insert whatever I want into the UserContent field.
MainWindow.xaml
<Window x:Class="StackOverflowQuestion4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StackOverflowQuestion4"
mc:Ignorable="d"
Title="MainWindow"
SizeToContent="WidthAndHeight">
<Grid Width="800"
Height="600">
<local:ReusableControl Title="Test">
<local:ReusableControl.UserContent>
<Rectangle Width="300"
Height="100"
Fill="Blue"/>
</local:ReusableControl.UserContent>
</local:ReusableControl>
</Grid>
</Window>
This works great, but the problem arises when I start to name things. Simply adding a name to an element inside of my ReusableControl causes a compilation error.
<Rectangle Width="300"
Height="100"
Fill="Blue"
Name="LolWhatAmIDoing"/>
I get the following error:
MC3093 - Cannot set Name attribute value 'LolWhatAmIDoing' on element 'Rectangle'. 'Rectangle' is under the scope of element 'ReusableControl', which already had a name registered when it was defined in another scope.
This seems like such a small issue, but I cannot find an easy solution to this problem.
I found this thread on the forum, but it does not really provide a solution.
Since I'm pretty new to all of this, I also don't really get what the issue is, so apologies if I'm slow minded.
Should I move to CustomControls?
What you show is a simple property assignment: you set the value of type Rectangle to the property ReusableControl.UserContent. It's important to understand that the Rectangle is not part of the visual tree at this point. It's a simple property value that is only accessible via the property and not via the visual tree.
This all happens in the scope of MainWindow.
But the Rectangle is not a member of this scope. The ReusableControl is adding it to its own visual subtree or scope by binding the value of ReusableControl.UserContent to a ContentControl. This is were the Rectangle exists i.e. is rendered in the visual tree.
It effectively doesn't exist in the scope of MainWindow. It effectively only exists inside the ReusableControl in the "shape" of a ContentControl. This means that the scope of ReusableControl is the only name scope where you can register a name for child elements. It's also the only scope where you can directly reference it (if it had been defined and registered in this scope).
If you understand this, then you understand that the Rectangle is currently trying to register a name in the wrong scope, a scope in which it doesn't exist.
As a consequence, you cannot directly refer to it in the scope of MainWindow. You would have to dig into the ContentTemplate of the UserControl (which is a ContentControl) in order to get the nested ContentControl that actually hosts the Rectangle.

WPF C# Show images in stack panel

I am actually solving the issue with stack panel and images I would like to show in it.
What my approach was:
Because of just about 50 pictures to be shown , I just get ti image , make a thumbnail from it , and place that one by one to the stackpanel on left side of my program. (As bitmap)
User is able to click on image and do the action with a image.
Required amount was about 50 images.
New state:
New state is that the required amount of images is about 500 so 10 times more.
The problem is even my thumbnail is too small when I am adding it like :
foreach image in list do :
create thumbnail
add on click or and on touch event to that thumbnail
add that thumbnail to the stack panel
I saw somewhere was used a picture box , not sure if that will help me.
I am thinking about creating lists of pictures links (50 in every ) and put for instance first in a scroll bar and when scrollbar reaches the bottom, load next and when the top reaches load previous list.
The problem is I am reaching with ~ 175 images the maximum of process memory.
I am waiting for garbage collector to do its job after every cycle.
Maybe my approach is not good or should be different so this is why I am asking which approach use in order to solve this problem you suggest.
The source of the photos is simply folder of thumbnails of size 150x150 .
The images are added one by one in certain period of time ( one foto every one second or so )
Thank you
An example of implementation.
Create a collection of images sources.
The collection can contain a string or an Url with a path to the image.
In this case, the image will be created only when it is shown in the Window.
You can also set an instance of ImageSource (or rather classes derived from it).
In this case, the image will be immediately loaded into memory.
Also set the property for specifying the selected image.
using System;
using System.Collections.ObjectModel;
using System.Windows.Media.Imaging;
namespace ImagesViewer
{
public class ImagesViewerViewModel
{
public ObservableCollection<object> ImagesSource { get; }
= new ObservableCollection<object>()
{
"https://miro.medium.com/max/2400/0*UEtwA2ask7vQYW06.png",
new Uri("https://149351115.v2.pressablecdn.com/wp-content/uploads/2021/06/stackoverflow-prosus-blue-orange.png"),
new BitmapImage(new Uri("https://amazinghiring.com/wp-content/uploads/2019/03/jpddcgb89ow.jpg"))
};
public object SelectedImage { get; set; }
}
}
Bind the ListBox source to the created collection.
In the Element Template, specify the Image with the binding to the element and the thumbnail sizes you need.
Assign the selected item to the property for the selected image.
The ListBox has a VirtualizingStackPanel built in by default, so you don't need to take any additional steps to limit using memory.
In the viewing region, set the Image with a binding to the property for the selected image.
<Window x:Class="ImagesViewer.ImagesViewerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ImagesViewer"
mc:Ignorable="d"
Title="ImagesViewerWindow" Height="450" Width="800">
<FrameworkElement.DataContext>
<local:ImagesViewerViewModel/>
</FrameworkElement.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding ImagesSource}"
SelectedItem="{Binding SelectedImage}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Margin="5"
Width="100" Height="100"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Image Grid.Column="1"
Source="{Binding SelectedImage}"/>
</Grid>
</Window>
Ok but scoriling of list of 170 150x150 causing the slowinest of the program as I already mentioned . I did the test already. Can you confirm or refute that please ?
Тестирование.
More than 1200 images in JPG and PNG formats are pre-recorded in the folder "C:\150x150".
The ViewModel gets a list of files in this folder and creates a string array with their paths.
The time for this operation is also recorded.
public class ImagesViewModel
{
public IEnumerable<string> ImagesPaths { get; }
public long ExecutionTimeGetPaths {get;}
public ImagesViewModel()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
ImagesPaths = Directory.GetFiles("C:/150x150")
.Where(path => path.EndsWith(".jpg") || path.EndsWith(".png"))
.ToArray();
stopwatch.Stop();
ExecutionTimeGetPaths = stopwatch.ElapsedMilliseconds;
}
}
In View in the upper right corner displays the time taken to get the paths of all files.
On the left side is a ListBox showing images in size 150x150 for all files.
<Window x:Class="Eee.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Eee"
mc:Ignorable="d"
Title="MainWindow" Height="1000" Width="300">
<Window.DataContext>
<local:ImagesViewModel/>
</Window.DataContext>
<Grid>
<TextBlock Text="{Binding ExecutionTimeGetPaths}"
HorizontalAlignment="Right" VerticalAlignment="Top"
FontSize="30" Margin="10"/>
<ListBox ItemsSource="{Binding ImagesPaths}" HorizontalAlignment="Left">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"
Width="150" Height="150"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Results: the time of obtaining the paths is 12-14 ms, the images are displayed instantly.
There are NO LAGS AT ALL when scrolling.
The same was verified for image files of arbitrary format from 128x128 to 4200x2800.
The result is the same.

WPF Caliburn Micro: Exchanging UserControls in a Window dynamically using ContentControl

This question is related to Add a usercontrol to caliburm micro dynamically.
I have read any other related threads before open this new thread, but I still don't understand and find no solution. Please accept my apology if some of you take this as duplicate.
I have a window (MainView) contains "main" Grid (aka LayoutRoot) with 2 columns.
On left column there are 2 buttons: "Display View 1" and "Display View 2".
If user click "Display View 1", the "Display1View" (is a UserControl contains TextBlock with Text "View 1") should be shown on the right column, replace the current one.
If user click "Display View 2", the "Display2View" (is a UserControl contains TextBlock with Text "View 2") should be shown on the right column, replace the current one.
My sample code contains following views and viewmodels:
MainView.xaml and MainViewModel.cs
Display1View.xaml and Display1ViewModel.cs
Display2View.xaml and Display2ViewModel.cs
In my sample code the ContentControl doesn't recognize the UserControl. What am I doing wrong? How to bind ContentControl correctly? Please feel free to modify my sample code. Thank you in advance
MainView.xaml
<Window x:Class="TestCaliMiContentControl.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main View"
Width="525"
Height="350">
<Grid x:Name="LayoutRoot" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*" />
<ColumnDefinition Width="100*" />
</Grid.ColumnDefinitions>
<StackPanel x:Name="LeftNavPanel" Grid.Column="0">
<Button x:Name="Display1" Content="Display View 1" />
<Button x:Name="Display2" Content="Display View 2" />
</StackPanel>
<ContentControl x:Name="MainGridContent" Grid.Column="1" />
</Grid>
</Window>
MainViewModel.cs
public class MainViewModel : PropertyChangedBase
{
private ContentControl _mainGridContent;
public ContentControl MainGridContent
{
get { return _mainGridContent; }
set
{
_mainGridContent = value;
NotifyOfPropertyChange(() => MainGridContent);
}
}
public void Display1()
{
//MainGridContent = new Display1ViewModel(); // cannot convert source type error
}
public void Display2()
{
// MainGridContent = new Display2ViewModel(); // cannot convert source type error
}
}
Display1View.xaml
<UserControl x:Class="TestCaliMiContentControl.Display1View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid>
<TextBlock HorizontalAlignment="Center" FontSize="72"
Text="View 1"/>
</Grid>
</UserControl>
Display1ViewModel.cs
using System;
using System.Windows.Controls;
using Caliburn.Micro;
namespace TestCaliMiContentControl
{
public class Display1ViewModel : PropertyChangedBase {}
}
First, I would start by recommending you read the Caliburn.Micro documentation, specifically the part about Screens, Conductors, and Composition: http://caliburnmicro.com/documentation/composition
That being said, we can modify your code to get it working.
1) Since your MainViewModel is supposed to be conducting other items, it should descend from Conductor<T>. In this case, we will have it conduct the Caliburn Screen class.
public class MainViewModel : Conductor<Screen>
2) In MVVM, you view models should know nothing of your view. You should not see UI classes such as ContentControl. We could change your property to be of type Screen, but we actually don't need that property at all since we are using a conductor. So, remove the MainGridContent property and backing field.
3) Within your Display1 and Display2 methods, invoke Caliburn's conductor method ActivateItem to show the appropriate item.
public void Display1()
{
ActivateItem(new Display1ViewModel());
}
4) In your MainView.xaml you will need to bind your ContentControl to the conductor's active item property, which is, by convention, ActiveItem.
<ContentControl x:Name="ActiveItem" Grid.Column="1" />
5) Finally, since your conductor is conducting Screens, you need to make them screens. Screens are helpful because they have lifecycle and allow you to know when they are activated/deactivated. Do this for both Display1 and Display2.
public class Display1ViewModel : Screen {}
This should get you up and running.

Combobox Dropdown event triggers parent window Z index to change

I have a problem with a WPF business line application prototype that I do not know where to start to debug.
My Master Window (A) opens a "dialog" window using Dialog.Show(). The child window (B) has a combobox on it.
When the combobox is clicked (to expand and to show all the options) the entire second window (B) is hidden except the dropdownlist appearing from the combobox. The combobox isn't there, the window isn't there. Nothing is there except the dropdownlist and the master window behind it. If I click the master window then focus is once again set to window B and it shows as it should (because I set the Owner of window B to be window A).
To make it more interesting this bug is not consistent. It appears maybe 1 of 20 times I use the application, and when it starts appearing it can appear several times in a row and then stop happening again.
Possibly related is the fact that I think I have the same bug some times with MessageBoxes. When using MessageBox.Show() (Win forms msgbox) from a viewmodel when only the master window (A) is showing the box occationally appears behind the master window making it invisible for the user.
My application is using GalaSoft MvvmLight (if that could have anything to do with it) and quite a few telerik components. Other than that I am not sure what data to provide. I don't think anyone can tell me the source of the problem based on this information, but where would you start looking for the problem?
Update :
Good news! I have isolated the problem and found the combination of prerequisites for the phenomena to occur:
a) A component showing a PDF file is currently open anywhere withing the application.
b) A telerik component has been undocked and redocked.
I will include the code below, but I think the issue is buried deep within the RadDocking or WebBrowser component.
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void OpenWindowClick(object sender, RoutedEventArgs e)
{
var w = new TestWindow { Owner = this, DataContext = new TestViewModel()};
w.Show();
}
}
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerikDocking="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Docking"
x:Class="TelerikGridDockingVsBrowserVsWindowBug.MainWindow"
Title="MainWindow" Height="750" Width="925">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<telerikDocking:RadDocking Grid.Row="0">
<telerikDocking:RadSplitContainer>
<telerikDocking:RadPaneGroup>
<telerikDocking:RadPane Header="I make bugs combined with a webbrowser showing a pdf document">
<TextBlock Text="1. Drag me and dock on the same or another location"/>
</telerikDocking:RadPane>
</telerikDocking:RadPaneGroup>
</telerikDocking:RadSplitContainer>
</telerikDocking:RadDocking>
<Button Grid.Row="1" Click="OpenWindowClick" Content="2. Open window" Height="50" Margin="0,20"/>
<WebBrowser Grid.Row="2" Source="http://www.kb.nl/sites/default/files/docs/pdf_guidelines.pdf"/>
</Grid>
TestWindow :
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
}
}
<Window x:Class="TelerikGridDockingVsBrowserVsWindowBug.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestWindow" Height="150" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock> 3. Click on the combobox.</TextBlock>
<ComboBox Grid.Row="1" ItemsSource="{Binding Options}" SelectedItem="{Binding SelectedOption}" Height="50"></ComboBox>
<TextBlock Grid.Row="2"> This window will then disappear behind its owner</TextBlock>
</Grid>
TestWindow ViewModel:
public class TestViewModel
{
public List<string> Options { get; set; }
public string SelectedOption { get; set; }
public TestViewModel()
{
Options = new List<string> { "String1", "String2" };
SelectedOption = Options.First();
}
}
I have an open ticket with Telerik about this, so I will update here if I find out anything.
I have been in your situation before... you have an unexplained problem... it doesn't make any sense... you've tried everything that you can think of... in a last ditch effort to fix the problem, you throw it out to all the experienced users here... then nothing... no responses... no help.
The thing is that if you can't find and fix the problem with all of your code right in front of you, then how can we fix it without any code?
All I can suggest is for you to try to locate exactly where the problem originates. You can do this by commenting out sections of code and then running your solution to see if that has removed the problem or whether it still exists. The fact that your problem only occurs infrequently will make this stage even more tricky.
However, with perseverance, you should be able to narrow down where the problem arises. Once you have managed to exclude enough of your code, the last step is to see if you re-create it in a much smaller new WPF project. If you manage to get to this stage, please come back and show your reduced code... then, we may be able to help you further.

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