The Children
property is not exposed as a dependency property, which means you cannot bind it. Furthermore, it is initialized once in the constructor of the MdiContainer
type and then a handler is added to the CollectionChanged
event of the underlying ObservableCollection<MdiChild>
. It is never updated or removed.
Therefore, although the Children
property has a setter, it will break the control if you use it to set a different collection. This also implies that you cannot simply create attached properties to expose a bindable Children
dependency property.
Apart from that, MdiChild
is a Control
, so it actually contradicts the purpose of your view model. If you expose a collection of user interface controls from your view model this conflicts with the MVVM pattern. View models should not have any knowledge about the view. However, the MDI controls do not seem to follow the usual WPF practices for custom controls, so there is not much room for improvement here, data templating is not supported, the MdiContainer
is a UserControl
and there are very limited dependency properties.
If you really want to continue working with this control with your current approach, you could:
Create a custom attached behavior to synchronize your view model collection with the Children
collection of the MdiContainer
and vice-versa, see XAML behaviors in WPF.
Use the Loaded
event to assign the Children
collection to your view model property.
<mdi:MdiContainer Name="Container" Grid.Row="1" Background="GhostWhite" Loaded="MdiContainer_OnLoaded">
private void MdiContainer_OnLoaded(object sender, RoutedEventArgs e)
{
var mdiContainer = (MdiContainer)sender;
var dataContext = (Main)mdiContainer.DataContext;
if (dataContext == null)
return;
dataContext.Children = mdiContainer.Children;
}
Use an EventTrigger
on the Loaded
event with a custom trigger action that sets the Children
collection. This is just a different variant of the previous approach that does not require code-behind.
The new XAML behaviors for WPF package, which replaces the legacy Blend behaviors from the System.Windows.Interactivity
namespace already includes such a trigger action. Install the Microsoft.Xaml.Behaviors.Wpf NuGet package and use this:
<mdi:MdiContainer Name="Container" Grid.Row="1" Background="GhostWhite">
<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="Loaded">
<behaviors:ChangePropertyAction TargetObject="{Binding DataContext, ElementName=Container}"
PropertyName="Children"
Value="{Binding Children, ElementName=Container}"/>
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
</mdi:MdiContainer>
Note that with these approaches, you either synchronize to your own collection or you work directly with the collection of the MdiContainer
that you passed to your view model. These are only workarounds. If you would want to implement this in a clean and MVVM compliant way, I think you would need to extend or fix the control itself, which is rather costly and not recommendable, since it seems to be dead anyway.