|
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
namespace CodeProject.Windows.Markup
{
public class ViewModel : MarkupExtension
{
private class BindingsWatcher
{
private UIElement element;
private object viewModel;
public BindingsWatcher(UIElement element, object viewModel)
{
this.element = element;
this.viewModel = viewModel;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
public void SinkCommands(string oldValue, string newValue)
{
Dictionary<string, IList> sinks = GetCommandSinks();
if (oldValue != null)
{
IList bindings;
if (sinks.TryGetValue(newValue, out bindings))
{
foreach (CommandBinding binding in bindings)
{
element.CommandBindings.Remove(binding);
}
INotifyCollectionChanged notify = bindings as INotifyCollectionChanged;
if (notify != null)
notify.CollectionChanged -= OnCollectionChanged;
}
}
if (newValue != null)
{
IList bindings;
if (sinks.TryGetValue(newValue, out bindings))
{
foreach (CommandBinding binding in bindings)
{
element.CommandBindings.Add(binding);
}
INotifyCollectionChanged notify = bindings as INotifyCollectionChanged;
if (notify != null)
notify.CollectionChanged += OnCollectionChanged;
}
}
}
private Dictionary<string, IList> GetCommandSinks()
{
Dictionary<string, IList> sinks = new Dictionary<string, IList>();
Type modelType = viewModel.GetType();
foreach (PropertyInfo propertyInfo in modelType.GetProperties())
{
foreach (Attribute attrib in propertyInfo.GetCustomAttributes(typeof(CommandSinkAttribute), true))
{
CommandSinkAttribute commandSinkAttrib = attrib as CommandSinkAttribute;
if (commandSinkAttrib != null)
{
if (sinks.ContainsKey(commandSinkAttrib.KeyName))
{
Trace.WriteLine(string.Format(CultureInfo.CurrentUICulture,
"Duplicate CommandSink: {0}",
commandSinkAttrib.KeyName));
}
else
{
IList list = propertyInfo.GetValue(viewModel, null) as IList;
sinks.Add(commandSinkAttrib.KeyName, list);
}
}
}
}
return sinks;
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
foreach (CommandBinding binding in e.OldItems)
{
element.CommandBindings.Remove(binding);
}
foreach (CommandBinding binding in e.NewItems)
{
element.CommandBindings.Add(binding);
}
}
}
private static readonly DependencyProperty BindingsWatcherProperty = DependencyProperty.RegisterAttached(
"BindingsWatcherProperty", typeof(BindingsWatcher), typeof(ViewModel));
public static readonly DependencyProperty InstanceProperty = DependencyProperty.RegisterAttached(
"InstanceProperty", typeof(object), typeof(ViewModel),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, OnInstanceChanged));
public static readonly DependencyProperty CommandsProperty = DependencyProperty.RegisterAttached(
"CommandsProperty", typeof(string), typeof(ViewModel),
new FrameworkPropertyMetadata(null, OnCommandsChanged));
public static object GetInstance(DependencyObject obj)
{
return obj.GetValue(InstanceProperty);
}
public static void SetInstance(DependencyObject obj, object value)
{
obj.SetValue(InstanceProperty, value);
}
public static string GetCommands(DependencyObject obj)
{
return (string)obj.GetValue(CommandsProperty);
}
public static void SetCommands(DependencyObject obj, string value)
{
obj.SetValue(CommandsProperty, value);
}
private static void OnInstanceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
ValueSource source = DependencyPropertyHelper.GetValueSource(obj, InstanceProperty);
if (source.BaseValueSource != BaseValueSource.Local)
return;
FrameworkElement element = obj as FrameworkElement;
if (element == null)
return;
element.DataContext = e.NewValue;
obj.ClearValue(CommandsProperty);
SetCommands(obj, string.Empty);
}
private static void OnCommandsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
object model = GetInstance(obj);
if (model == null)
return;
BindingsWatcher watcher = obj.GetValue(BindingsWatcherProperty) as BindingsWatcher;
if (watcher == null)
{
if (e.NewValue == null)
return;
UIElement element = obj as UIElement;
if (element == null)
return;
watcher = new BindingsWatcher(element, model);
obj.SetValue(BindingsWatcherProperty, watcher);
}
watcher.SinkCommands(e.OldValue as string, e.NewValue as string);
if (e.NewValue == null)
obj.ClearValue(BindingsWatcherProperty);
}
private Type modelType;
public ViewModel()
{
}
public ViewModel(Type modelType)
{
this.modelType = modelType;
}
public Type ModelType
{
get { return modelType; }
set { modelType = value; }
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
IProvideValueTarget provideValue = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
object target = provideValue.TargetObject;
ConstructorInfo cons = ModelType.GetConstructor(new Type[] { target.GetType() });
if (cons != null)
return cons.Invoke(new object[] { target });
cons = ModelType.GetConstructor(Type.EmptyTypes);
if (cons != null)
return cons.Invoke(null);
return null;
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Windows developer with 10+ years experience working in the banking industry.