My application is a WPF project implemented in C# .NET (4.5) using an MVVM architecture with no code-behind in the View. In order to eliminate the coupling between the View and the ViewModel I’m implementing some of the WPF-specific behaviours as custom DependencyProperties that can be bound to ‘simple’ properties exposed by the ViewModel.
The View assembly now has several of these DependencyProperties that are bound by the top-level ‘Windows’ in the View. I can’t see any obvious reason to collect them together into a single ‘Controller’ class, other than that when I do so the code suddenly looks prettier, but doing so introduces unnecessary coupling between these properties simply because they may be bound by a top-level View because not all ViewModel objects require all of the behaviours.
Should I sacrifice some reduction in coupling by requiring that the top-level ViewModel objects expose a cohesive ‘Controller’ property for the View to bind to with a single, custom DependencyProperty? Would it be better to implement multiple, single-purpose custom DependencyProperties for each of the behaviours? Is there a completely different appropach I could use, such as providing some kind of ‘behaviour container’?
Single Controller approach:
using System;
using System.Threading;
using System.Windows;
using FrameworkMVVM.BindingControllers; // For TopLevelViewController
namespace FrameworkMVVM.ViewBehaviours
{
public static class WindowBindableProperties
{
// One property that encapsulates the behaviours in a controller class
#region WindowControllerProperty
private static DependencyProperty _windowControllerProperty =
DependencyProperty.RegisterAttached
(
"WindowController",
typeof(TopLevelViewController),
typeof(WindowBindableProperties),
new PropertyMetadata(null, WindowControllerPropertyChanged)
);
public static DependencyProperty WindowControllerProperty
{ get { return _windowControllerProperty; } }
private static void WindowControllerPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
// Hook the events, EventHandlers, SynchronizationContext,
// DialogResult, etc. here.
}
#endregion
}
}
Multiple Properties approach:
using System;
using System.Threading;
using System.Windows;
namespace FrameworkMVVM.ViewBehaviours
{
public static class WindowBindableProperties
{
// Multiple properties, one for each behaviour.
#region CloseViewEventProperty
private static DependencyProperty _closeViewEventProperty =
DependencyProperty.RegisterAttached
(
"CloseViewEvent",
typeof(EventHandler),
typeof(WindowBindableProperties),
new PropertyMetadata(null, CloseViewEventPropertyChanged)
);
// The rest of the CloseViewEvent implementation goes here.
#endregion
#region DialogResultProperty
private static DependencyProperty _dialogResultProperty =
DependencyProperty.RegisterAttached
(
"DialogResultProperty",
typeof(Boolean?),
typeof(WindowBindableProperties),
new PropertyMetadata(null, DialogResultPropertyChanged)
);
// The rest of the DialogResultProperty implementation goes here.
#endregion
#region ViewContextProperty
private static DependencyProperty _viewContextProperty =
DependencyProperty.RegisterAttached
(
"ViewContextProperty",
typeof(SynchronizationContext),
typeof(WindowBindableProperties),
new PropertyMetadata(null, ViewContextPropertyChanged)
);
// The rest of the ViewContextProperty implementation goes here.
#endregion
// Etc., etc., etc..
}
}
2