I have found a new addiction: prowling StackOverflow and answering questions. It does teach a lot, because you must provide in record time a quality answer that is also appreciated by the person asking the question and by the evil reviewers who hunt you down and downvote you if you mess up. OK, they're not evil, they're necessary. Assholes! :) Anyway, in honor of my 1000th point, I want to share with you the code that I have been working on for one of the questions.

The question had a misleading title: How to inherit a textblock properties to a custom control in c# and had a 500 points reward on it (that's a lot) placed there by another person than the original requester. In fact, the question was more about how to use a normal TextBlock control, but also have it display outlined text, with a specific "stroke" and thickness. Funny thing, I had already answered this question a few days before. The bounty, though, was set on a more formal answer, one that would cover any graphical transformation on a TextBlock, considering that the control had sealed the OnRender overload and there was no way of reaching its drawing context.

We need to consider that WPF was designed to be modular, unlike ASP.Net or Windows Forms, for which inheritance was the preferred way to go. Instead WPF favors composition. That is why controls are sealing their OnRender implementation, because there is another way of getting to the drawing context and that is an Adorner. Now, it is also possible to use an Effect, but for the life of me I couldn't understand how to easily write one.

Anyway, adorners have their pros and cons. The pro is that you get to still use a TextBlock or whatever control you want to use and you just adorn it with what you need. It receives a UIElement in the constructor and in its OnRender method you get access to the drawing context of the control. Here is the code of the adorner that I presented in the StackOverflow question:
public class StrokeAdorner : Adorner
{
private TextBlock _textBlock;

private Brush _stroke;
private ushort _strokeThickness;

public Brush Stroke
{
get
{
return _stroke;
}

set
{
_stroke = value;
_textBlock.InvalidateVisual();
InvalidateVisual();
}
}

public ushort StrokeThickness
{
get
{
return _strokeThickness;
}

set
{
_strokeThickness = value;
_textBlock.InvalidateVisual();
InvalidateVisual();
}
}

public StrokeAdorner(UIElement adornedElement) : base(adornedElement)
{
_textBlock = adornedElement as TextBlock;
ensureTextBlock();
foreach (var property in TypeDescriptor.GetProperties(_textBlock).OfType<PropertyDescriptor>())
{
var dp = DependencyPropertyDescriptor.FromProperty(property);
if (dp == null) continue;
var metadata = dp.Metadata as FrameworkPropertyMetadata;
if (metadata == null) continue;
if (!metadata.AffectsRender) continue;
dp.AddValueChanged(_textBlock, (s, e) => this.InvalidateVisual());
}
}

private void ensureTextBlock()
{
if (_textBlock == null) throw new Exception("This adorner works on TextBlocks only");
}

protected override void OnRender(DrawingContext drawingContext)
{
ensureTextBlock();
base.OnRender(drawingContext);
var formattedText = new FormattedText(
_textBlock.Text,
CultureInfo.CurrentUICulture,
_textBlock.FlowDirection,
new Typeface(_textBlock.FontFamily, _textBlock.FontStyle, _textBlock.FontWeight, _textBlock.FontStretch),
_textBlock.FontSize,
Brushes.Black // This brush does not matter since we use the geometry of the text.
);

formattedText.TextAlignment = _textBlock.TextAlignment;
formattedText.Trimming = _textBlock.TextTrimming;
formattedText.LineHeight = _textBlock.LineHeight;
formattedText.MaxTextWidth = _textBlock.ActualWidth - _textBlock.Padding.Left - _textBlock.Padding.Right;
formattedText.MaxTextHeight = _textBlock.ActualHeight - _textBlock.Padding.Top;// - _textBlock.Padding.Bottom;
while (formattedText.Extent==double.NegativeInfinity)
{
formattedText.MaxTextHeight++;
}

// Build the geometry object that represents the text.
var _textGeometry = formattedText.BuildGeometry(new Point(_textBlock.Padding.Left, _textBlock.Padding.Top));
var textPen = new Pen(Stroke, StrokeThickness);
drawingContext.DrawGeometry(Brushes.Transparent, textPen, _textGeometry);
}

}

The first con is that you need to use it in code, there is no native way of using it from XAML. The second con, and the most brutal, is that when the control changes what it renders, the adorner doesn't follow suit! Someone answered it better than I can describe it here. Guess where? On StackOverflow, of course.

The first problem I have solved with another great WPF contraption: attached properties. Here is the code for the properties:
public static class Adorning
{
public static Brush GetStroke(DependencyObject obj)
{
return (Brush)obj.GetValue(StrokeProperty);
}
public static void SetStroke(DependencyObject obj, Brush value)
{
obj.SetValue(StrokeProperty, value);
}
// Using a DependencyProperty as the backing store for Stroke. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StrokeProperty =
DependencyProperty.RegisterAttached("Stroke", typeof(Brush), typeof(Adorning), new PropertyMetadata(Brushes.Transparent, strokeChanged));

private static void strokeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var stroke= e.NewValue as Brush;
ensureAdorner(d,a=>a.Stroke=stroke);
}

private static void ensureAdorner(DependencyObject d, Action<StrokeAdorner> action)
{
var tb = d as TextBlock;
if (tb == null) throw new Exception("StrokeAdorner only works on TextBlocks");
EventHandler f = null;
f = new EventHandler((o, e) =>
{
var adornerLayer = AdornerLayer.GetAdornerLayer(tb);
if (adornerLayer == null) throw new Exception("AdornerLayer should not be empty");
var adorners = adornerLayer.GetAdorners(tb);
var adorner = adorners == null ? null : adorners.OfType<StrokeAdorner>().FirstOrDefault();
if (adorner == null)
{
adorner = new StrokeAdorner(tb);
adornerLayer.Add(adorner);
}
tb.LayoutUpdated -= f;
action(adorner);
});
tb.LayoutUpdated += f;
}

public static double GetStrokeThickness(DependencyObject obj)
{
return (double)obj.GetValue(StrokeThicknessProperty);
}
public static void SetStrokeThickness(DependencyObject obj, double value)
{
obj.SetValue(StrokeThicknessProperty, value);
}
// Using a DependencyProperty as the backing store for StrokeThickness. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.RegisterAttached("StrokeThickness", typeof(double), typeof(Adorning), new PropertyMetadata(0.0, strokeThicknessChanged));

private static void strokeThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ensureAdorner(d, a =>
{
if (DependencyProperty.UnsetValue.Equals(e.NewValue)) return;
a.StrokeThickness = (ushort)(double)e.NewValue;
});
}
}
and an example of use:
<TextBlock
x:Name="t1"
HorizontalAlignment="Stretch"
FontSize="40"
FontWeight="Bold"
local:Adorning.Stroke="Red"
local:Adorning.StrokeThickness="2"
Text="Some text that needs to be outlined"
TextAlignment="Center"
TextWrapping="Wrap"

Width="600">
<TextBlock.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="Green" />
<GradientStop Offset="1" Color="Blue" />
</LinearGradientBrush>
</TextBlock.Foreground>
</TextBlock>

Now for the second problem, the StrokeAdorner already has a fix in the code, but I need to be more specific about it, because as it is written now I believe it leaks memory. Nothing terribly serious, but still. The code I am talking about is in the constructor:
foreach (var property in TypeDescriptor.GetProperties(_textBlock).OfType<PropertyDescriptor>())
{
var dp = DependencyPropertyDescriptor.FromProperty(property);
if (dp == null) continue;
var metadata = dp.Metadata as FrameworkPropertyMetadata;
if (metadata == null) continue;
if (!metadata.AffectsRender) continue;
dp.AddValueChanged(_textBlock, (s, e) => this.InvalidateVisual());
}
Here I am enumerating each property of the target (the TextBlock) and checking if they are dependency properties and if they have in their metadata the AffectsRender flag, they I add a property change handler which calls InvalidateVisual on the adorner. Notice that in no part of the code do I remove those handlers. However, at this time I don't think it is a problem. Anyway, the code itself is more about the principles of the thing, rather than the implementation.

If I were to talk about the implementation, I would say that this code doesn't always work. Even if I use the padding of the element and its actual dimensions, the FormattedText sometimes renders things differently from the TextBlock, especially if one plays with TextWrap and TextTrimming. But that is another subject altogether. Yay! 1000 points on StackOverflow! "And what do you do with the points?" [my wife :(]

This post is discussing the solution to the NotSupportedException "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread" and also the InvalidOperationException "An ItemsControl is inconsistent with its items source".

In the first case you want to bind in Windows Presentation Foundation a collection property from your viewmodel and it says no. What happens is that you are using a BindingList<T> or an ObservableCollection<T> and the binding system is using in the background a CollectionView that wraps it which does not support changes via multiple threads. The solution to this is rather simple: use this piece of code:
BindingOperations.EnableCollectionSynchronization(collection, lockObject);
This short blog post from Florent Pellet explains things a little, but that is ending on a dire note: The ViewModel becomes dependent on the view It also suggests that you need to create a lock object for each UI thread, if you have more.

This works in .NET 4.5 and that is the reason that when you are looking the exception up you get all kind of answers that either suggest you invoke any changes on the Dispatcher UI thread (which I believe is against the idea of having a viewmodel) or weird bastardizations of the collection classes used, like trying to invoke the events for list changes on the dispatcher of the invoking delegate. I've tried that and I got the second InvalidOperationException exception that I will be covering later on :)

But let's go further and examine what is going on. If you look at the method declaration, EnableCollectionSynchronization also allows specifying a synchronization callback, something that you could use to manage weird custom collection classes. The Remarks sections says When you call this overload of the EnableCollectionSynchronization(IEnumerable, Object) method, the system locks the collection when you access it, which implies you are losing some performance, but not much else. In case you have many parallel threads that are modifying your collection, you need to lock it, anyway. You may, of course, create your own high performance system of changing a collection and, maybe, run a separate method to marshal changes from your private data structure to the UI bound one.

Now, the InvalidOperationException "An ItemsControl is inconsistent with its items source" is thrown when the ItemsSource property has become out of sync with the Items property, which is usually generated by the ItemsControl. So when I tried to create my own badass collection class, I managed to avoid the first exception and I got this one. The same solution applies to both cases:
BindingOperations.EnableCollectionSynchronization(collection, lockObject);
Funny enough, you have to run this piece of code on the Dispatcher UI thread.


But where to use it? It would be rather simple to use it in the viewodel constructor, using the ((ICollection)collection)SyncRoot object, or even in the constructor of a class that inherits from either BindingList or ObservableCollection and has nothing but this type of initialization. I believe that, since this is a binding issues, something within WPF, then the binding system should handle it, like some type of synchronizing Binding. For a second I thought that the IsAsync property of the Binding class would solve this by itself, but it wouldn't work. Also, Binding doesn't have any methods to override and BindingBase is an abstract class with internal methods to implement, which of course doesn't work. Otherwise it would have been OK, I believe, to create a special SynchronizedCollectionBinding class that enables collection synchronization at bind time. BTW, if you are thinking to implement everything starting with MarkupExtension, forget it. The Binding class is a bit hardcoded in Visual Studio and it wouldn't actually work as expected.

That's it, folks!

There are a lot of people asking around what is the difference between BindingList<T> and ObservableCollection<T> and therefore, there are a lot of answers. I am writing this entry so that next time I look it up, I save StackOverflow some bandwidth. Also, because my blog is cooler :)

So, the first difference between BindingList and ObservableCollection is that BindingList implements cascading notifications of change. If any of the items in the list implements INotifyPropertyChanged, it will accept any change from those items and expose it as a list changed event, including the index of the item that initiated the change. ObservableCollection does not do that. So BindingList is better, right?

Wrong. BindingList is not "properly supported" by WPF, say some. Why is that? Well, because BindingList, as its MSDN page says, is just "an alternative to implementing the complete IBindingList interface". Yes, you've got it. BindingList is a lazy, thin, ineffective implementation of the interface. The Missing Docs blog has a very good explanation of this. Do keep in mind that BindingList was created during the time of Windows Forms and is being used by WPF only as an afterthought.

So let's use ObservableCollection then! No. The functionalities implemented by BindingList are far superior to that of ObservableCollection. Just thinking that you must somehow handle changes of every object in the list is killing the idea.

A subtle recommendation on the same MSDN page goes like this: "the typical solutions programmer will use a class that provides data binding functionality, such as BindingSource, instead of directly using BindingList". Well, what does that mean? It means using System.Windows.Forms.BindingSource, which does about everything, since it implements IBindingListView, IBindingList, IList, ICollection, IEnumerable, ITypedList, ICancelAddNew, ISupportInitializeNotification, ISupportInitialize, ICurrencyManagerProvider and is also a subclass of Component. A bit heavy, though, isn't it?

An interesting idea comes from a StackOverflow user: implement IBindingList on a subclass of ObservableCollection<T>. Should be enough to implement a scalable version of IBindingList.

There is more. The BindingListCollectionView page says "Specifically, IBindingList is required for BindingListCollectionView, and IBindingListView is an optional interface that gives additional sorting and filtering support.", which indicates that IBindingListView is also useful when getting a collection view for your object.

To recap: the best solution seems to be an ObservableCollection<T> that also implements IBindingListView (which itself implements IBindingList). The implementation must be scalable (getting the index of an object that causes a change in an efficient manner), though and I wonder, if I am implementing IBindingList, why should I even bother with inheriting from ObservableCollection? The same StackOverflow user seems interested only in the INotifyCollectionChanged interface for the ObservableCollection which is also implemented by IBindingListView!

Therefore, let's implement a class that explicitly implements IBindingListView and IList<T>, then publish the members we actually use! What could possibly go wrong? My idea is to store the index of an item next to the item, therefore removing the need to search for it. It seems that I must first implement an advanced List<T>, with a fast and efficient IndexOf method, then I can basically just copy paste the BindingList code and use this class of mine as the base. Unfortunately, BindingList uses Collection<T> as the base class, which itself implements IList<T>, IList, IReadOnlyList<T>. It seems I will have to implement all.

Immediately I have hit a snag. IBindingView is very difficult to implement, since it tries to filter using a string that is interpreted as a sort of DSL, so I would use a lot of reflection and weird conditions. Sorting is not much better. This is an interface invented when .NET did not support Predicates and lambda expressions, which would make sorting and filtering trivial and the subject of another post. So I go back to implementing a scalable BindingList, and just implement INotifyCollectionChanged over it.

For an implementation of IBindingView, check this out: BindingListView

Code time.

I've decided to implement the IndexOf caching as a dictionary with the objects as keys. The values are lists of integers representing all indexes of that value or object. Frankly I never realized that IndexOf for lists was not taking a start parameter, so it only returns the first occurrence of an item in the list.

There are three classes: AdvancedCollection is a fast IndexOf implementation of Collection. AdvancedBindingList is the copy pasted code of BindingList, with the base class changed from Collection to AdvancedCollection and with INotifyCollectionChanged implemented over it. SecurityUtils is only needed for the AddNew method of IBindingList and is again copy pasted from the Microsoft code. Enjoy!

Click to collapse/expand
internal static class SecurityUtils
{
private static volatile ReflectionPermission _memberAccessPermission;
private static volatile ReflectionPermission _restrictedMemberAccessPermission;

private static ReflectionPermission memberAccessPermission =>
_memberAccessPermission ??
(_memberAccessPermission = new ReflectionPermission(ReflectionPermissionFlag.MemberAccess));

private static ReflectionPermission restrictedMemberAccessPermission =>
_restrictedMemberAccessPermission ??
(_restrictedMemberAccessPermission =
new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));

private static void demandReflectionAccess(Type type)
{
try
{
memberAccessPermission.Demand();
}
catch (SecurityException)
{
demandGrantSet(type.Assembly);
}
}

[SecuritySafeCritical]
private static void demandGrantSet(Assembly assembly)
{
var permissionSet = assembly.PermissionSet;
var accessPermission = restrictedMemberAccessPermission;
permissionSet.AddPermission(accessPermission);
permissionSet.Demand();
}

private static bool hasReflectionPermission(Type type)
{
try
{
demandReflectionAccess(type);
return true;
}
catch (SecurityException)
{
}
return false;
}

internal static object SecureCreateInstance(Type type)
{
return SecureCreateInstance(type, null, false);
}

internal static object SecureCreateInstance(Type type, object[] args, bool allowNonPublic)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
var bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;
if (!type.IsVisible)
demandReflectionAccess(type);
else if (allowNonPublic && !hasReflectionPermission(type))
allowNonPublic = false;
if (allowNonPublic)
bindingAttr |= BindingFlags.NonPublic;
return Activator.CreateInstance(type, bindingAttr, null, args, null);
}

internal static object SecureCreateInstance(Type type, object[] args)
{
return SecureCreateInstance(type, args, false);
}

internal static object SecureConstructorInvoke(Type type, Type[] argTypes, object[] args, bool allowNonPublic)
{
return SecureConstructorInvoke(type, argTypes, args, allowNonPublic, BindingFlags.Default);
}

internal static object SecureConstructorInvoke(Type type, Type[] argTypes, object[] args, bool allowNonPublic,
BindingFlags extraFlags)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (!type.IsVisible)
demandReflectionAccess(type);
else if (allowNonPublic && !hasReflectionPermission(type))
allowNonPublic = false;
var bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | extraFlags;
if (!allowNonPublic)
bindingAttr &= ~BindingFlags.NonPublic;
var constructor = type.GetConstructor(bindingAttr, null, argTypes, null);
return constructor?.Invoke(args);
}

private static bool genericArgumentsAreVisible(MethodInfo method)
{
return !method.IsGenericMethod || method.GetGenericArguments().All(type => type.IsVisible);
}

internal static object FieldInfoGetValue(FieldInfo field, object target)
{
var declaringType = field.DeclaringType;
if (declaringType == null)
{
if (!field.IsPublic)
demandGrantSet(field.Module.Assembly);
}
else if (!declaringType.IsVisible || !field.IsPublic)
demandReflectionAccess(declaringType);
return field.GetValue(target);
}

internal static object MethodInfoInvoke(MethodInfo method, object target, object[] args)
{
var declaringType = method.DeclaringType;
if (declaringType == null)
{
if (!method.IsPublic || !genericArgumentsAreVisible(method))
demandGrantSet(method.Module.Assembly);
}
else if (!declaringType.IsVisible || !method.IsPublic || !genericArgumentsAreVisible(method))
demandReflectionAccess(declaringType);
return method.Invoke(target, args);
}

internal static object ConstructorInfoInvoke(ConstructorInfo ctor, object[] args)
{
var declaringType = ctor.DeclaringType;
if (declaringType != null && (!declaringType.IsVisible || !ctor.IsPublic))
demandReflectionAccess(declaringType);
return ctor.Invoke(args);
}

internal static object ArrayCreateInstance(Type type, int length)
{
if (!type.IsVisible)
demandReflectionAccess(type);
return Array.CreateInstance(type, length);
}
}

public class AdvancedCollection<T> : IList<T>,IList, IReadOnlyList<T>
{
private readonly List<T> _innerList;
private readonly Dictionary<T, List<int>> _reverseIndex;
private readonly object _syncRoot=new object();

public AdvancedCollection()
{
_innerList = new List<T>();
_reverseIndex = new Dictionary<T, List<int>>();
}

public AdvancedCollection(IList<T> list):this()
{
_innerList.Clear();
_innerList.AddRange(list);
refreshIndexes();
}

private void refreshIndexes()
{
lock (_syncRoot)
{
_reverseIndex.Clear();
for (var i = 0; i < _innerList.Count; i++)
{
var item = _innerList[i];
List<int> indexes;
if (!_reverseIndex.TryGetValue(item, out indexes))
{
indexes = new List<int>();
_reverseIndex[item] = indexes;
}
indexes.Add(i);
}
}
}

public int IndexOf(T item)
{
List<int> indexes;
if (!_reverseIndex.TryGetValue(item, out indexes)) return -1;
return indexes.Count == 0 ? -1 : indexes[0];
}

public void Insert(int index, T item)
{
lock (_syncRoot)
{
var indexesList = Enumerable.Range(index, _innerList.Count - index)
.Select(i => _reverseIndex[_innerList[i]])
.Distinct();
foreach (var indexes in indexesList)
{
for (var j = 0; j < indexes.Count; j++)
{
if (indexes[j] >= index)
{
indexes[j]++;
}
}
}
_innerList.Insert(index, item);
}
}

public void RemoveAt(int index)
{
lock (_syncRoot)
{
var indexesList = Enumerable.Range(index, _innerList.Count - index)
.Select(i => _reverseIndex[_innerList[i]])
.Distinct();
foreach (var indexes in indexesList)
{
for (var j = 0; j < indexes.Count; j++)
{
var i = indexes[j];
if (i == index)
{
indexes.RemoveAt(j);
j--;
continue;
}
if (indexes[j] > index)
{
indexes[j]--;
}
}
}
_innerList.RemoveAt(index);
}
}

public T this[int index]
{
get { return _innerList[index]; }
set
{
lock (_syncRoot)
{
var indexes = _reverseIndex[_innerList[index]];
indexes.Remove(index);
if (!_reverseIndex.TryGetValue(value, out indexes))
{
indexes = new List<int>();
_reverseIndex[value] = indexes;
}
indexes.Add(index);
indexes.Sort();
}
}
}


int IList.Add(object value)
{
return add((T) value);
}

bool IList.Contains(object value)
{
return ((IList<T>) this).Contains((T) value);
}

void IList.Clear()
{
lock (_syncRoot)
{
_innerList.Clear();
_reverseIndex.Clear();
}
}

int IList.IndexOf(object value)
{
return ((IList<T>) this).IndexOf((T) value);
}

void IList.Insert(int index, object value)
{
((IList<T>)this).Insert(index, (T)value);
}

void IList.Remove(object value)
{
var index = ((IList) this).IndexOf(value);
if (index < 0) return;
((IList) this).RemoveAt(index);
}

void IList.RemoveAt(int index)
{
((IList<T>) this).RemoveAt(index);
}

object IList.this[int index]
{
get { return ((IList<T>)this)[index]; }
set
{
var item = (T) value;
((IList<T>)this)[index] = item;
}
}

bool IList.IsReadOnly => false;

bool IList.IsFixedSize => false;

void ICollection.CopyTo(Array array, int index)
{
((IList)_innerList).CopyTo(array,index);
}

public int Count => _innerList.Count;

object ICollection.SyncRoot => _syncRoot;

bool ICollection.IsSynchronized => false;

IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _innerList.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>) this).GetEnumerator();
}

public void Add(T item)
{
add(item);
}

public void Clear()
{
((IList) this).Clear();
}

bool ICollection<T>.Contains(T item)
{
lock (_syncRoot)
{
return _reverseIndex.ContainsKey(item);
}
}

void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
lock (_syncRoot)
{
_innerList.CopyTo(array, arrayIndex);
}
}

bool ICollection<T>.Remove(T item)
{
var index = ((IList<T>)this).IndexOf(item);
if (index < 0) return false;
((IList<T>)this).RemoveAt(index);
return true;
}

int ICollection<T>.Count => _innerList.Count;

bool ICollection<T>.IsReadOnly => false;

int IReadOnlyCollection<T>.Count => _innerList.Count;

T IReadOnlyList<T>.this[int index] => ((IList<T>) this)[index];

private int add(T item)
{
lock (_syncRoot)
{
var index = _innerList.Count;
_innerList.Add(item);
List<int> indexes;
if (!_reverseIndex.TryGetValue(item, out indexes))
{
indexes = new List<int>();
_reverseIndex[item] = indexes;
}
indexes.Add(index);
return index;
}
}

protected virtual void ClearItems()
{
((IList<T>)this).Clear();
}

protected virtual void InsertItem(int index, T item)
{
((IList<T>)this).Insert(index,item);
}

protected virtual void RemoveItem(int index)
{
((IList<T>)this).RemoveAt(index);
}

protected virtual void SetItem(int index, T item)
{
this[index] = item;
}
}

/// <summary>
/// Provides a generic collection that supports data binding.
/// </summary>
/// <typeparam name="T">The type of elements in the list.</typeparam>
[Serializable]
[HostProtection(SecurityAction.LinkDemand, SharedState = true)]
public class AdvancedBindingList<T> : AdvancedCollection<T>, IBindingList, ICancelAddNew, IRaiseItemChangedEvents,
INotifyCollectionChanged
{
private int _addNewPos = -1;
private bool _allowEdit = true;
private bool _allowNew = true;
private bool _allowRemove = true;

[NonSerialized] private PropertyDescriptorCollection _itemTypeProperties;

[NonSerialized] private int _lastChangeIndex = -1;

[NonSerialized] private AddingNewEventHandler _onAddingNew;

[NonSerialized] private PropertyChangedEventHandler _propertyChangedEventHandler;

private bool _raiseItemChangedEvents;
private bool _raiseListChangedEvents = true;
private bool _userSetAllowNew;

/// <summary>
/// Initializes a new instance of the <see cref="T:System.ComponentModel.BindingList`1" /> class using default values.
/// </summary>
public AdvancedBindingList()
{
initialize();
}

/// <summary>
/// Initializes a new instance of the <see cref="T:System.ComponentModel.BindingList`1" /> class with the specified
/// list.
/// </summary>
/// <param name="list">
/// An <see cref="T:System.Collections.Generic.IList`1" /> of items to be contained in the
/// <see cref="T:System.ComponentModel.BindingList`1" />.
/// </param>
public AdvancedBindingList(IList<T> list)
: base(list)
{
initialize();
}

private bool itemTypeHasDefaultConstructor
{
get
{
var type = typeof (T);
return type.IsPrimitive ||
type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance,
null, new Type[0], null) != null;
}
}

/// <summary>
/// Gets or sets a value indicating whether adding or removing items within the list raises
/// <see cref="E:System.ComponentModel.BindingList`1.ListChanged" /> events.
/// </summary>
/// <returns>
/// true if adding or removing items raises <see cref="E:System.ComponentModel.BindingList`1.ListChanged" /> events;
/// otherwise, false. The default is true.
/// </returns>
public bool RaiseListChangedEvents
{
get { return _raiseListChangedEvents; }
set { _raiseListChangedEvents = value; }
}

private bool addingNewHandled
{
get
{
if (_onAddingNew != null)
return (uint) _onAddingNew.GetInvocationList().Length > 0U;
return false;
}
}

/// <summary>
/// Gets or sets a value indicating whether you can add items to the list using the
/// <see cref="M:System.ComponentModel.BindingList`1.AddNew" /> method.
/// </summary>
/// <returns>
/// true if you can add items to the list with the <see cref="M:System.ComponentModel.BindingList`1.AddNew" /> method;
/// otherwise, false. The default depends on the underlying type contained in the list.
/// </returns>
public bool AllowNew
{
get
{
if (_userSetAllowNew || _allowNew)
return _allowNew;
return addingNewHandled;
}
set
{
var num1 = AllowNew ? 1 : 0;
_userSetAllowNew = true;
_allowNew = value;
var num2 = value ? 1 : 0;
if (num1 == num2)
return;
fireListReset();
}
}

/// <summary>
/// Gets or sets a value indicating whether items in the list can be edited.
/// </summary>
/// <returns>
/// true if list items can be edited; otherwise, false. The default is true.
/// </returns>
public bool AllowEdit
{
get { return _allowEdit; }
set
{
if (_allowEdit == value)
return;
_allowEdit = value;
fireListReset();
}
}

/// <summary>
/// Gets or sets a value indicating whether you can remove items from the collection.
/// </summary>
/// <returns>
/// true if you can remove items from the list with the
/// <see cref="M:System.ComponentModel.BindingList`1.RemoveItem(System.Int32)" /> method otherwise, false. The default
/// is true.
/// </returns>
public bool AllowRemove
{
get { return _allowRemove; }
set
{
if (_allowRemove == value)
return;
_allowRemove = value;
fireListReset();
}
}

/// <summary>
/// Gets a value indicating whether <see cref="E:System.ComponentModel.BindingList`1.ListChanged" /> events are
/// enabled.
/// </summary>
/// <returns>
/// true if <see cref="E:System.ComponentModel.BindingList`1.ListChanged" /> events are supported; otherwise, false.
/// The default is true.
/// </returns>
protected virtual bool SupportsChangeNotificationCore => true;

/// <summary>
/// Gets a value indicating whether the list supports searching.
/// </summary>
/// <returns>
/// true if the list supports searching; otherwise, false. The default is false.
/// </returns>
protected virtual bool SupportsSearchingCore => false;

/// <summary>
/// Gets a value indicating whether the list supports sorting.
/// </summary>
/// <returns>
/// true if the list supports sorting; otherwise, false. The default is false.
/// </returns>
protected virtual bool SupportsSortingCore => false;

/// <summary>
/// Gets a value indicating whether the list is sorted.
/// </summary>
/// <returns>
/// true if the list is sorted; otherwise, false. The default is false.
/// </returns>
protected virtual bool IsSortedCore => false;

/// <summary>
/// Gets the property descriptor that is used for sorting the list if sorting is implemented in a derived class;
/// otherwise, returns null.
/// </summary>
/// <returns>
/// The <see cref="T:System.ComponentModel.PropertyDescriptor" /> used for sorting the list.
/// </returns>
protected virtual PropertyDescriptor SortPropertyCore => null;

/// <summary>
/// Gets the direction the list is sorted.
/// </summary>
/// <returns>
/// One of the <see cref="T:System.ComponentModel.ListSortDirection" /> values. The default is
/// <see cref="F:System.ComponentModel.ListSortDirection.Ascending" />.
/// </returns>
protected virtual ListSortDirection SortDirectionCore => ListSortDirection.Ascending;

bool IBindingList.AllowNew => AllowNew;

bool IBindingList.AllowEdit => AllowEdit;

bool IBindingList.AllowRemove => AllowRemove;

bool IBindingList.SupportsChangeNotification => SupportsChangeNotificationCore;

bool IBindingList.SupportsSearching => SupportsSearchingCore;

bool IBindingList.SupportsSorting => SupportsSortingCore;

bool IBindingList.IsSorted => IsSortedCore;

PropertyDescriptor IBindingList.SortProperty => SortPropertyCore;

ListSortDirection IBindingList.SortDirection => SortDirectionCore;

/// <summary>
/// Occurs when the list or an item in the list changes.
/// </summary>
public event ListChangedEventHandler ListChanged;

object IBindingList.AddNew()
{
var obj = AddNewCore();
_addNewPos = obj != null ? ((IList<T>) this).IndexOf((T) obj) : -1;
return obj;
}

void IBindingList.ApplySort(PropertyDescriptor prop, ListSortDirection direction)
{
ApplySortCore(prop, direction);
}

void IBindingList.RemoveSort()
{
RemoveSortCore();
}

int IBindingList.Find(PropertyDescriptor prop, object key)
{
return FindCore(prop, key);
}

void IBindingList.AddIndex(PropertyDescriptor prop)
{
}

void IBindingList.RemoveIndex(PropertyDescriptor prop)
{
}

/// <summary>
/// Discards a pending new item.
/// </summary>
/// <param name="itemIndex">The index of the of the new item to be added </param>
public virtual void CancelNew(int itemIndex)
{
if (_addNewPos < 0 || _addNewPos != itemIndex)
return;
RemoveItem(_addNewPos);
_addNewPos = -1;
}

/// <summary>
/// Commits a pending new item to the collection.
/// </summary>
/// <param name="itemIndex">The index of the new item to be added.</param>
public virtual void EndNew(int itemIndex)
{
if (_addNewPos < 0 || _addNewPos != itemIndex)
return;
_addNewPos = -1;
}

public event NotifyCollectionChangedEventHandler CollectionChanged;

bool IRaiseItemChangedEvents.RaisesItemChangedEvents => _raiseItemChangedEvents;

private void fireListReset()
{
fireListChanged(ListChangedType.Reset, -1);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

/// <summary>
/// Occurs before an item is added to the list.
/// </summary>
public event AddingNewEventHandler AddingNew
{
add
{
var num1 = AllowNew ? 1 : 0;
_onAddingNew = _onAddingNew + value;
var num2 = AllowNew ? 1 : 0;
if (num1 == num2)
return;
fireListReset();
}
remove
{
var num1 = AllowNew ? 1 : 0;
// ReSharper disable once DelegateSubtraction
_onAddingNew = _onAddingNew - value;
var num2 = AllowNew ? 1 : 0;
if (num1 == num2)
return;
fireListReset();
}
}

private void initialize()
{
_allowNew = itemTypeHasDefaultConstructor;
if (!typeof (INotifyPropertyChanged).IsAssignableFrom(typeof (T)))
return;
_raiseItemChangedEvents = true;
foreach (var obj in this)
hookPropertyChanged(obj);
}

/// <summary>
/// Raises the <see cref="E:System.ComponentModel.BindingList`1.AddingNew" /> event.
/// </summary>
/// <param name="e">An <see cref="T:System.ComponentModel.AddingNewEventArgs" /> that contains the event data. </param>
protected virtual void OnAddingNew(AddingNewEventArgs e)
{
_onAddingNew?.Invoke(this, e);
}

private object fireAddingNew()
{
var e = new AddingNewEventArgs(null);
OnAddingNew(e);
return e.NewObject;
}

/// <summary>
/// Raises the <see cref="E:System.ComponentModel.BindingList`1.ListChanged" /> event.
/// </summary>
/// <param name="e">A <see cref="T:System.ComponentModel.ListChangedEventArgs" /> that contains the event data. </param>
protected virtual void OnListChanged(ListChangedEventArgs e)
{
ListChanged?.Invoke(this, e);
}

/// <summary>
/// Raises a <see cref="E:System.ComponentModel.BindingList`1.ListChanged" /> event of type
/// <see cref="F:System.ComponentModel.ListChangedType.Reset" />.
/// </summary>
public void ResetBindings()
{
fireListReset();
}

/// <summary>
/// Raises a <see cref="E:System.ComponentModel.BindingList`1.ListChanged" /> event of type
/// <see cref="F:System.ComponentModel.ListChangedType.ItemChanged" /> for the item at the specified position.
/// </summary>
/// <param name="position">A zero-based index of the item to be reset.</param>
public void ResetItem(int position)
{
fireListChanged(ListChangedType.ItemChanged, position);
CollectionChanged?.Invoke(this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, this[position],position));
}

private void fireListChanged(ListChangedType type, int index)
{
if (!_raiseListChangedEvents)
return;
OnListChanged(new ListChangedEventArgs(type, index));
}

/// <summary>
/// Removes all elements from the collection.
/// </summary>
protected override void ClearItems()
{
EndNew(_addNewPos);
if (_raiseItemChangedEvents)
{
foreach (var obj in this)
unhookPropertyChanged(obj);
}
base.ClearItems();
fireListReset();
}

/// <summary>
/// Inserts the specified item in the list at the specified index.
/// </summary>
/// <param name="index">The zero-based index where the item is to be inserted.</param>
/// <param name="item">The item to insert in the list.</param>
protected override void InsertItem(int index, T item)
{
EndNew(_addNewPos);
base.InsertItem(index, item);
if (_raiseItemChangedEvents)
hookPropertyChanged(item);
fireListChanged(ListChangedType.ItemAdded, index);
CollectionChanged?.Invoke(this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item,index));
}

/// <summary>
/// Removes the item at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the item to remove. </param>
/// <exception cref="T:System.NotSupportedException">
/// You are removing a newly added item and
/// <see cref="P:System.ComponentModel.IBindingList.AllowRemove" /> is set to false.
/// </exception>
protected override void RemoveItem(int index)
{
if (!_allowRemove && (_addNewPos < 0 || _addNewPos != index))
throw new NotSupportedException();
EndNew(_addNewPos);
if (_raiseItemChangedEvents)
unhookPropertyChanged(this[index]);
var item = this[index];
base.RemoveItem(index);
fireListChanged(ListChangedType.ItemDeleted, index);
CollectionChanged?.Invoke(this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item,index));
}

/// <summary>
/// Replaces the item at the specified index with the specified item.
/// </summary>
/// <param name="index">The zero-based index of the item to replace.</param>
/// <param name="item">The new value for the item at the specified index. The value can be null for reference types.</param>
/// <exception cref="T:System.ArgumentOutOfRangeException">
/// <paramref name="index" /> is less than zero.-or-
/// <paramref name="index" /> is greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count" />.
/// </exception>
protected override void SetItem(int index, T item)
{
if (_raiseItemChangedEvents)
unhookPropertyChanged(this[index]);
base.SetItem(index, item);
if (_raiseItemChangedEvents)
hookPropertyChanged(item);
fireListChanged(ListChangedType.ItemChanged, index);
CollectionChanged?.Invoke(this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item,index));
}

/// <summary>
/// Adds a new item to the collection.
/// </summary>
/// <returns>
/// The item added to the list.
/// </returns>
/// <exception cref="T:System.InvalidOperationException">
/// The <see cref="P:System.Windows.Forms.BindingSource.AllowNew" />
/// property is set to false. -or-A public default constructor could not be found for the current item type.
/// </exception>
public T AddNew()
{
return (T) ((IBindingList) this).AddNew();
}

/// <summary>
/// Adds a new item to the end of the collection.
/// </summary>
/// <returns>
/// The item that was added to the collection.
/// </returns>
/// <exception cref="T:System.InvalidCastException">
/// The new item is not the same type as the objects contained in the
/// <see cref="T:System.ComponentModel.BindingList`1" />.
/// </exception>
protected virtual object AddNewCore()
{
var obj = fireAddingNew() ?? getNewInstance();
Add((T) obj);
return obj;
}

private static object getNewInstance()
{
return SecurityUtils.SecureCreateInstance(typeof (T));
}

/// <summary>
/// Sorts the items if overridden in a derived class; otherwise, throws a <see cref="T:System.NotSupportedException" />
/// .
/// </summary>
/// <param name="prop">A <see cref="T:System.ComponentModel.PropertyDescriptor" /> that specifies the property to sort on.</param>
/// <param name="direction">One of the <see cref="T:System.ComponentModel.ListSortDirection" /> values.</param>
/// <exception cref="T:System.NotSupportedException">Method is not overridden in a derived class. </exception>
protected virtual void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
throw new NotSupportedException();
}

/// <summary>
/// Removes any sort applied with
/// <see
/// cref="M:System.ComponentModel.BindingList`1.ApplySortCore(System.ComponentModel.PropertyDescriptor,System.ComponentModel.ListSortDirection)" />
/// if sorting is implemented in a derived class; otherwise, raises <see cref="T:System.NotSupportedException" />.
/// </summary>
/// <exception cref="T:System.NotSupportedException">Method is not overridden in a derived class. </exception>
protected virtual void RemoveSortCore()
{
throw new NotSupportedException();
}

/// <summary>
/// Searches for the index of the item that has the specified property descriptor with the specified value, if
/// searching is implemented in a derived class; otherwise, a <see cref="T:System.NotSupportedException" />.
/// </summary>
/// <returns>
/// The zero-based index of the item that matches the property descriptor and contains the specified value.
/// </returns>
/// <param name="prop">The <see cref="T:System.ComponentModel.PropertyDescriptor" /> to search for.</param>
/// <param name="key">
/// The value of
/// <paramref>
/// <name>property</name>
/// </paramref>
/// to match.
/// </param>
/// <exception cref="T:System.NotSupportedException">
/// <see cref="M:System.ComponentModel.BindingList`1.FindCore(System.ComponentModel.PropertyDescriptor,System.Object)" />
/// is not overridden in a derived class.
/// </exception>
protected virtual int FindCore(PropertyDescriptor prop, object key)
{
throw new NotSupportedException();
}

private void hookPropertyChanged(T item)
{
var notifyPropertyChanged = (object) item as INotifyPropertyChanged;
if (notifyPropertyChanged == null)
return;
if (_propertyChangedEventHandler == null)
_propertyChangedEventHandler = Child_PropertyChanged;
notifyPropertyChanged.PropertyChanged += _propertyChangedEventHandler;
}

private void unhookPropertyChanged(T item)
{
var notifyPropertyChanged = (object) item as INotifyPropertyChanged;
if (notifyPropertyChanged == null || _propertyChangedEventHandler == null)
return;
notifyPropertyChanged.PropertyChanged -= _propertyChangedEventHandler;
}

private void Child_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (!RaiseListChangedEvents)
return;
if (sender != null && e != null)
{
if (!string.IsNullOrEmpty(e.PropertyName))
{
T obj;
try
{
obj = (T) sender;
}
catch (InvalidCastException)
{
ResetBindings();
return;
}
var newIndex = _lastChangeIndex;
if (newIndex < 0 || newIndex >= Count || !this[newIndex].Equals(obj))
{
newIndex = IndexOf(obj);
_lastChangeIndex = newIndex;
}
if (newIndex == -1)
{
unhookPropertyChanged(obj);
ResetBindings();
return;
}
if (_itemTypeProperties == null)
_itemTypeProperties = TypeDescriptor.GetProperties(typeof (T));
var propDesc = _itemTypeProperties.Find(e.PropertyName, true);
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, newIndex, propDesc));
return;
}
}
ResetBindings();
}
}

In this post I will discuss the following:
First, let's discuss the project that I was working on which led to this work. I wanted to do a program that manages the devices on my network. There is a router and several Wi-fi extenders, all of them with an HTTP interface. I wanted to know when they are reachable through the network, connect to the HTTP interface and gather data or perform actions like resetting the device and so on. In order to see if they were reachable, I was pinging them every second, so I thought I would like to see the evolution of the ping roundtrip time in a visual way, therefore the chart.

All of the values that I was displaying and all the commands that were available on the interface were using MVVM, the pattern developed by Microsoft for a better separation of presentation and data model. MVVM presents some difficulties, though, since most of the time directly getting the data and displaying it is more efficient and easier to do. It does allow for fantastic flexibility and good maintenance of the project. So, since I am a fan, I wanted to draw this chart via MVVM as well.

The MVVM chart


In order to do that I needed a viewmodel that abstracted the chart. Since I had several devices, each of them with a collection of pings containing the time of the ping and a nullable rountrip value, it would have been way too annoying to try to chart the values directly, so on the main viewmodel I created a specific chart model. This model contained a BindingList of items of various custom types: GraphLines, GraphStarts and GraphEnds. When the ping failed I added an "end" to the model. When the ping succeeded after a fail, I would add a "start". And when the ping was continuously successful, I would add a "line" connecting the previous ping to the current one.

So, in order to draw anything, I used a Canvas. The Canvas is a very simple container that can position stuff at absolute values. The first thing you need to realize is that it is not a vectorial type of container, so when you draw something on a small canvas and you resize the window, everything remains at the same position and size. The other thing that quickly becomes apparent is that there are various ways of positioning objects on the Canvas. The attached properties Canvas.Top, Canvas.Left, Canvas.Bottom and Canvas.Right can define the position of TextBlocks or other elements, including Rectangles and Ellipses. Lines, on the other hand, whether simple Line objects or something more complex, like Paths, are positioned using Points and X,Y coordinates. This would come to bite me on the ass later on.

WPF is very flexible. In order to add things to a Canvas, all one needs to do is to declare an ItemsControl and then redefine the ItemsPanel property to be a Canvas. The way objects are represented on the Canvas can be defined via DataTemplates, in my case one for each type of item. So I created a template that contains a Line for the GraphLine type, another for GraphStart, containing a Rectangle, and one for GraphEnd, containing an Ellipse. Forget the syntax right now, first I had to solve the problem of the different ways to position something on a Canvas and the ItemsControl. You see, in order to position a Line, all you have to do is set the X1,Y1,X2,Y2 properties, but for Ellipses and Rectangles you need to set Canvas.Left and Canvas.Top. The problem with the ItemsControl is that for each of these not primitive objects it creates a ContentPresenter to encapsulate them, therefore setting Canvas properties to the inner shape did nothing. The solution is to set a style for the ContentPresenter and set the Canvas properties on it. Surprise! Then the Lines stop working! The solution was to add several Canvases, one for the lines and one for the rectangles and ellipses, as ItemsControls, and one for static text and stuff like that, all in the same Container so that they overlap. But it worked. Then I started the program and watched the chart being displayed.

<ItemsControl ItemsSource="{Binding GraphItems}" Name="GraphLines">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:GraphLine}">
...
</DataTemplate>
<DataTemplate DataType="{x:Type local:GraphSpline}">
...
</DataTemplate>
<DataTemplate DataType="{x:Type local:GraphStart}">
...
</DataTemplate>
<DataTemplate DataType="{x:Type local:GraphEnd}">
...
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

But how did I calculate the coordinates of all of these items? As I said, the Canvas is a pretty static thing. If I resized the window, the items would remain in the same position and with the same size. Also, the viewmodel didn't have (and shouldn't have had) an idea of the actual size of the drawing Canvas. My solution was to use a MultiBinding with a custom converter. It would get two values, one would be a computed double value, from 0 to 1, that represented either vertical or horizontal position, the second would be the value of the dimension, the height or the width. The result would be, of course, the product of the two values. Luckily WPF has a very flexible Binding syntax, so it was no problem two define a value from the viewmodel and a value of the ActualWidth or ActualHeight properties of the Canvas object. This resulted in a very nice graph that adapted to my resizing of the window in real time without me having to do anything.

<Line Stroke="{Binding Ip, Converter={StaticResource TextToBrushConverter}}" StrokeThickness="2" >
<Line.X1>
<MultiBinding Converter="{StaticResource ResizeConverter}">
<Binding Path="X"/>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Canvas}}"/>
</MultiBinding>
</Line.X1>
<Line.Y1>
<MultiBinding Converter="{StaticResource ResizeConverter}">
<Binding Path="Y"/>
<Binding Path="ActualHeight" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Canvas}}"/>
</MultiBinding>
</Line.Y1>
<Line.X2>
<MultiBinding Converter="{StaticResource ResizeConverter}">
<Binding Path="X2"/>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Canvas}}"/>
</MultiBinding>
</Line.X2>
<Line.Y2>
<MultiBinding Converter="{StaticResource ResizeConverter}">
<Binding Path="Y2"/>
<Binding Path="ActualHeight" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Canvas}}"/>
</MultiBinding>
</Line.Y2>
</Line>

Performance


The next issue in the pipeline was performance. Clearing the GraphItems collection and adding new items to it was very slow and presented some ugly visual artifacts. For this I used the inner mechanisms of the BindingList object. First I set the RaiseListChangedEvents property to false, so that the list would not fire any events to the WPF mechanism. Then I cleared the list,added every newly calculated GraphItem to the list, set RaiseListChangedEvents back to true and fired a ListChanged event forcefully using the (badly named) ResetBindings method.

GraphItems.RaiseListChangedEvents = false;
GraphItems.Clear();
foreach (var item in items)
{
GraphItems.Add(item);
}
GraphItems.RaiseListChangedEvents = true;
this.Dispatcher.Invoke(GraphItems.ResetBindings, DispatcherPriority.Normal);

All good, but then the overall performance of the application was abysmal. I would move to another program, then switch back to it and it wouldn't show up, or I would press a button and it wouldn't show up pressed, or the values of the data from the devices were not displayed sometimes. It wasn't that it used too much CPU or memory or anything like that, it was just a very sluggish user experience.

First idea was that the binding to the parent Canvas object to get the ActualWidth and the ActualHeight values was slow. I was right. In order to test this I removed any bindings to the Canvas and instead set the values directly to the converter, via the SizeChanged event of the Canvas object. This made things slightly faster, but also made them look weird, since I would resize the window and only see a difference after SizeChanged fired. The performance gain was significant, but not that large. The UI was still sluggish.

void Canvas_SizeChanged(object sender, SizeChangedEventArgs e)
{
var resizeConverter = (ResizeConverter)this.Resources["ResizeConverter"];
resizeConverter.Size = e.NewSize;
}

Now, you would ask yourself, what is the purpose of my using this ItemsControl and Canvas combination? It is in order to use the MVVM pattern. Just drawing directly on the Canvas would violate that, wouldn't it? Or would it? In this case the binding of the values in the viewmodel to the chart is one way. I only need to display stuff and nothing that happens on the chart UI changes the viewmodel. Also, since I chose to recreate all the chart items at every turn, it just means I am delegating clearing the Canvas and drawing everything to the WPF mechanism, nothing more. In fact, if I would just subscribe to the GraphItems ListChanged event I would be able to draw everything and not really have any strong link between data model and presentation. So I did that. The side effect of this was that I didn't need two ItemsControl/Canvas instances. I only needed one Canvas and I would add items to it as I saw fit.

Of course, the smart reader that you are, you realized that I need to know the type of the viewmodel in order to subscribe to the items list. The very correct way to do it would have been to encapsulate the Canvas into a control that would have received a list of items as a model and it would have handled all the drawing itself. It makes sense: you don't want a Canvas, what you really want is a Chart component that handles everything for you. I leave that to the enterprising reader, since it is outside the scope of this post.

Another thing that I did not do and it probably made sense in terms of performance, was to add items to the chart, somehow translate the position of the chart and remove the items that were outside the visible portion of the chart. That sounds like a good feature of the Chart control :) Again, I leave it to the reader to try to do something like that.

Bezier curves instead of lines


The last thing that I want to cover is making the chart less jagged. The roundtrip ping values were all over the place resulting in a jagged line kind of chart. I wanted something smoother, like a continuous curvy line. So I decided to replace the Line representation with a Bezier curve one. I am not a graphical person, neither a math geek. I had no idea what a Bezier curve is, only that it helps in creating these nice looking curves that blend into each other. Each Bezier curve is defined by four points so, in my ignorance, I thought that I just have to pass four points from the list instead of the two required to form a Line. The result was hilarious, but not what I wanted.

Reading the theory we learn that... what the hell is that on Wikipedia? How can anyone understand that?!... Ugh!

So let's start with some experiments. Let's use the wonderful XamlPadX application to see some examples of that using WPF. First, let's draw a jagged three line graphic and try to use the four points to define a Bezier curve and see what happens.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Canvas>
<Line X1="100" Y1="100" X2="200" Y2="300" Stroke="Gray" StrokeThickness="2"/>
<Line X1="200" Y1="300" X2="300" Y2="150" Stroke="Gray" StrokeThickness="2"/>
<Line X1="300" Y1="150" X2="400" Y2="200" Stroke="Gray" StrokeThickness="2"/>
<Path Stroke="Red" StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="100,100">
<PathFigure.Segments>
<PathSegmentCollection>
<BezierSegment Point1="200,300" Point2="300,150" Point3="400,200" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
</Page>



As we can see, the curve does touch the first and the fourth points and sort of approximates the line, but not very clearly. The problem becomes even more obvious when we add another point and we create two Bezier curves, from the first and last four points. The two curves intersect, they are not continuous. Even if you take points four by four, the resulting curves, even if they continue each other, they do it with straight corners, the opposite of what I wanted.




Let's try the opposite, let's draw one Bezier curve and then lines that connect the first and second and then the third and fourth points. We see that the lines define tangents to the two arcs comprising the Bezier curve. That intuitively tells us something: if two Bezier curves would to seamlessly blend into each other, then the straight lines that define them would also have to be continuous. We try that in XamlPadX and yes! It works.




So, from this we learn something. First of all, the first and last points of the Bezier have to be the points used in a normal Line. Then the last two points need to be part of the same line for the first two points of the next curve. So what about the second and third points? How do I choose those? Can I choose any lines to define my curves? Thinking of the chart that I am looking for, I just want that the jagged edges turn into nice little curves. I also don't want to think of other points than the points that would normally define a single line, that means I shouldn't use future data in defining the middle points of the curve that defines current data. So I just made the decision to use only horizontal lines to define curves. That means for any pair of coordinates X1,Y1, X2,Y2 I would create four pairs like this: X1,Y1 X1+something,Y1 X2-something,Y2 X2,Y2. That value could be anything, but I've decided it would be a percentage of the horizontal distance between two points.

Final result: using a percentage, let's say 20%, I would turn the pair of coordinates into X1,Y1 X1+(X2-X1)*0.2 X1+(X2-X1)*(1-0.2) X2,Y2. Let's see how that looks on the original jagged line. Let's use 50% instead. And for some fun, let's put it to 80%, 100% and even 200%.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Canvas>
<Line X1="100" Y1="100" X2="200" Y2="300" Stroke="Gray" StrokeThickness="2"/>
<Line X1="200" Y1="300" X2="300" Y2="150" Stroke="Gray" StrokeThickness="2"/>
<Line X1="300" Y1="150" X2="400" Y2="200" Stroke="Gray" StrokeThickness="2"/>
<Path Stroke="Red" StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="100,100">
<PathFigure.Segments>
<PathSegmentCollection>
<BezierSegment Point1="150,100" Point2="150,300" Point3="200,300" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<PathFigure StartPoint="200,300">
<PathFigure.Segments>
<PathSegmentCollection>
<BezierSegment Point1="250,300" Point2="250,150" Point3="300,150" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<PathFigure StartPoint="300,150">
<PathFigure.Segments>
<PathSegmentCollection>
<BezierSegment Point1="350,150" Point2="350,200" Point3="400,200" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
</Page>







That's it, folks. I hope you enjoyed this as much as I did and it helps you in future projects.

While working on a small personal project, I decided to make a graphical tool that displayed a list of items in a Canvas. After making it work (for details go here), I've decided to make the items animate when changing their position. In my mind it had to be a simple solution, akin to jQuery animate or something like that; it was not.

The final solution was to finally give up on a generic method for this and switch to the trusted attached properties. But if you are curious to see what else I tried and how ugly it got, read it here:
Click here to get ugly!

Well, long story short: attached properties. I created two attached properties CanvasLeft and CanvasTop. When they change, I animate the real properties and, at the end of the animation, I set the value. Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;

namespace Siderite.AttachedProperties
{
public static class UIElementProperties
{
public static readonly DependencyProperty CanvasLeftProperty = DependencyProperty.RegisterAttached("CanvasLeft", typeof(double), typeof(UIElementProperties), new FrameworkPropertyMetadata(
0.0,
FrameworkPropertyMetadataOptions.OverridesInheritanceBehavior,
CanvasLeftChanged));

[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static double GetCanvasLeft(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (double)element.GetValue(CanvasLeftProperty);
}

[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetCanvasLeft(DependencyObject element, double value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(CanvasLeftProperty, value);
}

private static void CanvasLeftChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sb = new Storyboard();
var oldVal = (double)e.OldValue;
if (double.IsNaN(oldVal)) oldVal = 0;
var newVal = (double)e.NewValue;
if (double.IsNaN(newVal)) newVal = oldVal;
var anim = new DoubleAnimation
{
From = oldVal,
To = newVal,
Duration = new Duration(TimeSpan.FromSeconds(1)),
FillBehavior = FillBehavior.Stop
};
Storyboard.SetTarget(anim, d);
Storyboard.SetTargetProperty(anim, new PropertyPath("(Canvas.Left)"));
sb.Children.Add(anim);
sb.Completed += (s, ev) =>
{
d.SetValue(Canvas.LeftProperty, newVal);
};
var fe = d as FrameworkElement;
if (fe != null)
{
sb.Begin(fe, HandoffBehavior.Compose);
return;
}
var fce = d as FrameworkContentElement;
if (fce != null)
{
sb.Begin(fce, HandoffBehavior.Compose);
return;
}
sb.Begin();
}


public static readonly DependencyProperty CanvasTopProperty = DependencyProperty.RegisterAttached("CanvasTop", typeof(double), typeof(UIElementProperties), new FrameworkPropertyMetadata(
0.0,
FrameworkPropertyMetadataOptions.OverridesInheritanceBehavior,
CanvasTopChanged));

[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static double GetCanvasTop(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (double)element.GetValue(CanvasTopProperty);
}

[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetCanvasTop(DependencyObject element, double value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(CanvasTopProperty, value);
}

private static void CanvasTopChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sb = new Storyboard();
var oldVal = (double)e.OldValue;
if (double.IsNaN(oldVal)) oldVal = 0;
var newVal = (double)e.NewValue;
if (double.IsNaN(newVal)) newVal = oldVal;
var anim = new DoubleAnimation
{
From = oldVal,
To = newVal,
Duration = new Duration(TimeSpan.FromSeconds(1)),
FillBehavior = FillBehavior.Stop
};
Storyboard.SetTarget(anim, d);
Storyboard.SetTargetProperty(anim, new PropertyPath("(Canvas.Top)"));
sb.Children.Add(anim);
sb.Completed += (s, ev) =>
{
d.SetValue(Canvas.TopProperty, newVal);
};
var fe = d as FrameworkElement;
if (fe != null)
{
sb.Begin(fe, HandoffBehavior.Compose);
return;
}
var fce = d as FrameworkContentElement;
if (fce != null)
{
sb.Begin(fce, HandoffBehavior.Compose);
return;
}
sb.Begin();
}
}
}

and this is how you would use them:

<ListView ItemsSource="{Binding KernelItems}" 
SelectedItem="{Binding SelectedItem,Mode=TwoWay}"
SelectionMode="Single"
>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Black" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="att:UIElementProperties.CanvasLeft" >
<Setter.Value>
<MultiBinding Converter="{StaticResource CoordinateConverter}">
<Binding Path="X"/>
<Binding Path="ActualWidth" ElementName="lvKernelItems"/>
<Binding Path="DataContext.Zoom" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="att:UIElementProperties.CanvasTop" >
<Setter.Value>
<MultiBinding Converter="{StaticResource CoordinateConverter}">
<Binding Path="Y"/>
<Binding Path="ActualHeight" ElementName="lvKernelItems"/>
<Binding Path="DataContext.Zoom" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Cyan"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect ShadowDepth="0" Color="White" Opacity="0.5" BlurRadius="10"/>
</Setter.Value>
</Setter>
<Setter Property="Canvas.ZIndex" Value="1000"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>

Hope it helps.

For a WPF project I wanted to create a graphical representation of a list of items. I computed some X,Y coordinates for each item and started changing the XAML of a Listview in order to reflect the position of each item on a Canvas. Well, it is just as easy as you imagine: change the ItemsPanel property to a Canvas and then style each item as whatever you want. The gotcha comes when trying to set the coordinates. The thing is that for each item in a listview a container is constructed and inside the item template is displayed. So here you have all you items displayed exactly as you want them, except the coordinates don't work, since what needs to be placed on the Canvas are the generated containers, not the items. Here is the solution:
<Window.Resources>
<local:CoordinateConverter x:Key="CoordinateConverter"/>
<DataTemplate DataType="{x:Type vm:KernelItem}"> <!-- the template for the data items -->
<Grid>
<Ellipse Fill="{Binding Background}" Width="100" Height="100" Stroke="DarkGray" Name="ellipse"
ToolTip="{Binding Tooltip}"/>
<TextBlock Text="{Binding Text}" MaxWidth="75" MaxHeight="75"
HorizontalAlignment="Center" VerticalAlignment="Center"
TextAlignment="Center"
TextWrapping="Wrap"
ToolTip="{Binding Tooltip}" />
</Grid>
</DataTemplate>
</Window.Resources>
<ListView ItemsSource="{Binding KernelItems}" Name="lvKernelItems"
SelectedItem="{Binding SelectedItem,Mode=TwoWay}"
SelectionMode="Single"
>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Black" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/><!-- no highlight of selected items -->
<Setter Property="Foreground" Value="White"/>
<Setter Property="(Canvas.Left)" >
<Setter.Value>
<MultiBinding Converter="{StaticResource CoordinateConverter}">
<Binding Path="X"/>
<Binding Path="ActualWidth" ElementName="lvKernelItems"/>
<Binding Path="DataContext.Zoom" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="(Canvas.Top)" >
<Setter.Value>
<MultiBinding Converter="{StaticResource CoordinateConverter}">
<Binding Path="Y"/>
<Binding Path="ActualHeight" ElementName="lvKernelItems"/>
<Binding Path="DataContext.Zoom" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Resources><!-- no highlight of selected items -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True"><!-- custom selected item template -->
<Setter Property="Foreground" Value="Cyan"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect ShadowDepth="0" Color="White" Opacity="0.5" BlurRadius="10"/>
</Setter.Value>
</Setter>
<Setter Property="Canvas.ZIndex" Value="1000"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>

As a bonus, you see the way to remove the default selection of an item: the ugly dotted line and the highlighting background.

I created a little piece of software which was supposed to get as much of the content I was interested in, then display it in a browser. It was a WPF application, but I doubt it matters that much, since the WebBrowser control there is still based on the Internet Explorer COM control that is also used in Windows Forms.

Anyway, the idea was simple: connect to the URL of the item I was selecting, display the page in the browser and, if the title of the loaded document was that of an error page (hence, the browser could not load it - I found no decent way to determine the response error code) I would display the HTML content that I gathered earlier. These two feats were, of course, realized using the Navigate and NavigateToString methods - more or less hacked to look like valid MVVM for WPF :-P. Everything worked, went to the place where the Internet is a far away myth - my Italian residence, started the application and ...

FatalExecutionEngineError was detected Message: The runtime has encountered a fatal error. The address of the error was at 0x64808539, on thread 0xf84. The error code is 0x80131623. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.. Ignore the hexadecimal numbers, I strongly doubt they were much help.

This horrible looking exception was thrown through a try/catch block and I could find no easy way to get to the source of the problem. The InnerException wasn't too helpful either: System.ExecutionEngineException was unhandled HResult=-2146233082 Message=Exception of type 'System.ExecutionEngineException' was thrown.

I did what every experienced professional does in these situations: googled for "WPF WebBrowser not working!!!". And I found this guy: Fatal Execution Error on browser ReadyState, who described a similar situation caused by interogating the document readyState property, which I was also doing! Amazingly, it worked. At first.

The second step of the operation was to go with this software to the place where the Internet exists, but it is guarded by huge trolls that live under the gateway - my Italian/European Commission workplace. Kaboom! The dreaded exception appeared again, even if I had configured my software to work with a firewall and an http proxy. Meanwhile, the harddrive of my laptop failed and I had to reinstall the software on the computer, from Windows 8 to Windows 7. Same error now consistently appeared at home.

At the end of this chain of events, the other tool of the software professional - blind trial and error - prevailed. All I had to do was to NavigateToString via the WebBrowser control Dispatcher, thus:

wbMain.Dispatcher.BeginInvoke(new Action(() =>
{
wbMain.NavigateToString(content);
}));


... and everyone lived happily ever after.

I've met a very interesting WPF bug today, something that is hard to explain or reproduce, but might give terrible headaches if you don't know its source.

I had a WPF UserControl, with its xaml and cs files. Now, I know that in MVVM I shouldn't really use those much, but it was out of my control. The control had a section of resources (UserControl.Resources) in which there was a ResourceDictionary with some stuff in it. Considering that I'd removed all the merged dictionaries from this, I thought that I had no need of the dictionary tags, after all the Resources property of an element is already a ResourceDictionary. So it was something like this:

<UserControl ... >
<UserControl.Resources>
<!-- <ResourceDictionary> with these tags commented the error occurs -->
... stuff ...
<!-- </ResourceDictionary> -->
</UserControl.Resources>
</UserControl>

The error itself is that, during compilation, the partial user control class defines in the code behind doesn't seem to find things from the xaml. Probably, the compiler fails building the xaml into a class, but fails silently, while the codebehind is completely disconnected from the xaml because it is the only partial file for that class name.

By selectively removing items in the resources I've narrowed it down to one of the converters. It was creating using the MarkupExtension trick, but it was also declared as a resource for some reason. I do not see why that should matter, but still.

Bottom line: when the partial codebehind class for a WPF user control (or maybe for windows as well) fails to connect to the xaml, it means it silently fails the compilation of the XAML and you should try checking the resources of the elements therein.

A quick post here about using a ContentPresenter (or a ContentControl which uses a ContentPresenter in its template) with its Content property. The intended usage of ContentPresenter is to set the Content to some binding to a data object, then control the element tree via the ContentTemplate property. That may lead to a counterintuitive situation when you want to specify some UI element content and then use bindings in that content. Let's take an example:

<!--
This ContentControl has a MainViewModel class as a DataContext.
The MainViewModel class exposes a MyButtonCommand property.
-->
<ContentControl>
<ContentControl.Content>
<Button Command="{Binding MyButtonCommand}">Press me!</Button>
</ContentControl.Content>
</ContentControl>
You may expect to press the button and execute the command, but it doesn't work. In fact, the binding on the Command property will fail.

Here is a working example:

<!--
This ContentControl has a MainViewModel class as a DataContext.
The MainViewModel class exposes a MyButtonCommand property.
-->
<ContentControl Content="{Binding MyButtonCommand}">
<ContentControl.ContentTemplate>
<DataTemplate>
<Button Command="{Binding}">Press me!</Button>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>


I realize this is not what most of you have in mind when using a ContentControl. Another solution is to use the Content as in the first example, but add an explicit DataContext property to it before using any binding, something like this:

<!--
This ContentControl has a MainViewModel class as a DataContext.
The MainViewModel class exposes a MyButtonCommand property.
-->
<ContentControl>
<ContentControl.Content>
<DataTemplate>
<Button
DataContext="{Binding DataContext,RelativeSource={RelativeSource AncestorType={x:Type ContentControl}}}"
Command="{Binding MyButtonCommand}">Press me!</Button>
</DataTemplate>
</ContentControl.Content>
</ContentControl>
In this case, though, you specify the DataContext as an ugly binding and, worst of all, you cannot set it via the ContentControl, but you need to access the actual content.

Perhaps another solution, one that would involve a custom DataTemplateSelector on the ContentControl would work, but right now I have no perfectly satisfactory solution.

A colleague of mine started using a control I made in which there was a Hyperlink. Well, the purpose of it was not complex, I just needed a text that can be clicked. A Hyperlink sounded like the only solution out of the box, since there is no LinkButton control in the standard WPF controls. That aside, after I finish writing this blog post, I will write myself a LinkButton control to use in these situations instead, since Hyperlink seems to have several design flaws. It's not even a control, but a flow element.

What my colleague reported is that the Hyperlink would not get enabled in certain situations and we've come to the conclusion that after the initialization of the control, the IsEnabled property on the Hyperlink does not change when an ancestor control changes its enabledness. The only way to force it is to actually bind it to an ancestor IsEnabled.

Here is the scenario: You place several items in a XAML file. They are a text in a Hyperlink, in a TextBlock (since Hyperlinks cannot be directly part of a Panel, first design flaw), in a StackPanel. The text in the text block will appear as a clickable link. Set the StackPanel to IsEnabled="False" and the text will appear as disabled. Now, add a ToggleButton and bind its IsChecked property to the StackPanel IsEnabled property. Click the button and the StackPanel will get disabled, but not the hyperlink. Start with a disabled StackPanel, the link will be disabled, click the button and the hyperlink will stay disabled. The solution: set on the Hyperlink, inline or via a style, IsEnabled="{Binding IsEnabled,RelativeSource={RelativeSource AncestorType={x:FrameworkElement}}}". Now that is ugly.

As a sideline, whenever you see a WPF element inexplicably disabled and you use Snoop on it and try to set IsEnabled to true and you can't, there is probably one of two situations:
  1. A parent of the control is disabled
  2. The control is implementing ICommandSource and its Command property is set on an ICommand that returns false on its CanExecute method

Well, I have been kind of absent from the blog lately and that is for several reasons. One is that I have been waiting for some news that would determine my direction as a professional developer. The other is that I have re-acquired a passion for chess. So, between work at the office, watching chess videos, playing chess with my PDA and watching all seven seasons of Star Trek Deep Space 9, I haven't had much time for blogging.

Also, when you think about it, the last period of my programming life has been in some sort of a limbo: switched from ASP.Net to WPF, then to ASP.Net again (while being promised it would be temporary), then back to WPF (but in a mere executive position). Meanwhile, Microsoft didn't do much to help me, and thus saw their profits plummet. Well, maybe it was a coincidence, but what if it wasn't?

I am complaining about Microsoft because I was so sold into the whole WPF/Silverlight concept, while I was totally getting fed up with web work. Yet WPF is slow, with no clear development pathway when using it, while Silverlight is essentially something else, supported by only a few platforms, and I haven't even gotten around to use it yet. And now the Internet Explorer 9/Windows 8 duo come in force placing Javascript and HTML5 in the forefront again. Check out this cool ArsTechnica blog post about Microsoft's (re)new(ed) direction.

All of this, plus the mysterious news I have been waiting for that I won't detail (don't want to jinx it :-S), but which could throw me back into the web world, plus the insanity with the mobile everything that has only one common point: web. Add to it the not too enthusiastic reaction of my blog readers when starting talking about WPF. So the world either wants web or I just have been spouting one stupid thing after another and blew my readers away.

All these shining signs pointing me towards web development also say that I should be relearning web dev with ASP.Net MVC, getting serious about Javascript, relearning HTML in its 5th incarnation and finally making some sense of CSS. Exciting and crazy at the same time. Am I getting too old for this shit or am I ready for the challenge? We'll just have to see, won't we?

As usual when I stumble into a problem that I can't solve only to see that it has a simple explanation and that I am not sufficiently informed on the matter, I had some misgivings on blogging about it. But these are the best possible blog entries, the "Oh, I am so stupid!" moments, because other people are sure to make the same mistake and you wouldn't wish for them the same humiliation, would you? Well, I wouldn't :-P

So here it is: I was having a ToggleButton and a ContextMenu in a custom control. I wanted to have the IsChecked property bound in two-way mode with the IsOpen property of the ContextMenu. So I did what most people would do, I created a Setter on the IsChecked property with a Binding on DropDown.IsOpen as a value (DropDown is the property of the control holding the ContextMenu). And it worked, of course. My custom control would inherit from ToggleButton and use the style with the Setter in it.

But now comes the tricky part: I wanted that when a certain condition was met, the button be checked and the menu open. So I added a Trigger to the Style on the condition that I wanted, with a Setter on the IsChecked property to True. And from then on, nothing made any sense. I would click the button and it would not open the menu anymore.

Well, if you think about it, you have a Setter in the Style and then another Setter on the same property in the Trigger. It makes a sort of a sense for them to interfere with each other, but I also know that setting a Binding as value to a DependencyProperty is like using SetBinding on the owner of the property. And I thought it was normal for the IsChecked property to be set to true from the trigger and, in turn, change the value of IsOpen. But it didn't happen. Let it be a lesson to other bozos like myself that this thing does make sense logically (or as wishful thinking), but not in WPF. And here is why:

Let's try to evaluate the values of IsChecked and IsOpen. First case scenario: clicking on the button. That changes the status of IsChecked from true to false and viceversa. Internally, what does happen is WPF finds any bindings associated with the value and refreshes them. In this case, it finds a binding to IsOpen and so the ContextMenu also opens up. Second case scenario: the condition in the ViewModel is met, the trigger is fired and the value of IsChecked is set. It should do the same thing, right? Find the bindings and refresh them. And it does! But in that fateful moment, it sees that the IsChecked property has a setter associated with it, from the trigger in the style, that sets it to True. It does not go further, because the trigger setter overrides the style setter. I personally think this is closer to a bug than a reasonable behavior, but I am biased here :) I mean, you set the value of the property directly in the code IsChecked=true;, and it works, but you set it in the trigger and it overrides the binding?

There are more solutions to this problem. One solution would be to replace the setter value in the trigger with another binding also to the IsOpen property of the ContextMenu, but with a nifty converter. I haven't tried it, because I think that, if it worked, it would add too much weird complexity and even if I love weird, this is a little bit too much for me. Of course, a programmatic solution is also possible, adding handlers for the Open and Close events of the ContextMenu and setting IsChecked, as well as setting IsOpen based on the value sent to the IsChecked property change callback. But I wanted to do something that is as WPFish as possible. Another solution is to set a binding to the IsOpen property, since it is two way, and this is what I did. Unfortunately, the ContextMenu is a variable of the control, so I had to manually set the binding in that property's PropertyChangedCallback. A more elegant solution, I believe, is to have another element present that would have two-way bindings for both IsChecked and IsOpen properties to two of its own properties. Internally, when one changes, the other is synchronized. This leaves both ToggleButton and ContextMenu free to have any setters on IsChecked and IsOpen without interference.

The pattern of using a separate control to link properties from other controls together is called Binding Hub. Here is an article detailing it. I disagree with the naming of properties as I believe for each connection a separate hub should be created with properties that actually make sense :), but the concept is powerful and I like it.

I was doing some tests with localization in a WPF application and I've found that the way to change dynamically the language for a control (and all of its descendants) is to set the Language property. In my application at least, the propagation of change in the entire subtree took a few seconds. As I found out, the way to refresh the language is to actually remove and readd children to control trees. This is probably why simply changing the Thread culture does not work, what the Language property is for and explains why the error was thrown.

During the Language change on the Window object a validation from one of the custom controls there threw a weird Exception: Cannot modify the logical children for this node at this time because a tree walk is in progress.. What could it mean?

This link on StackOverflow says something vague about a bug in the Silverlight charting toolkit, but I think that is wrong, or at least not the root of the problem. I looked through the Reflectored .Net sources and found that this exception is thrown in AddLogicalChild and RemoveLogicalChild methods in FrameworkElement and FrameworkContentElement when the internal property IsLogicalChildrenIterationInProgress is true. Apparently, this property is set to true whenever am internal class DescendentsWalker<T> is "walking" the visual and/or the logical trees. What is this class?

DescendentsWalker<T> seems to be a class used by the WPF framework to find resources, resolve property values, find ancestors/descendants in the control trees, propagate events, etc, so it is a very important low level class. Either because of a bug or exactly in order to prevent one, an error is thrown if someone is trying to change the structure of the tree while something is walking the tree. That is what the error represents.

Now, the only question is how to solve it. The validation code was trying to change the content property of a control, thus modifying the control tree. As such, I do believe this is a slight bug in the framework, as changing the tree could just wait until the tree walk is over, but still. A simple try/catch solve it locally, but what should I do to prevent such errors in the future for all of my code? I can't pad my code with try/catch blocks.

I've tried using Dispatcher.Invoke for the change, it didn't work. The IsLogicalChildrenIterationInProgress property itself does a this.ReadInternalFlag(System.Windows.InternalFlags.IsLogicalChildrenIterationInProgress); and _flags is obviously a private field of the FrameworkElement or FrameworkContentElement class that is never encapsulated into a public property. So I can't check for it in a simple way. Of course, one can always catch Dispatcher.UnhandledException and just set e.Handled to true if this error occurs (Oops, a minor worldwide tremor caused by developer shudder!), but I don't see another global solution.

Well, at least I've thoroughly examined the problem and its causes and possible solutions, however bad or annoying they may be. If you know of a more elegant solution for it, please share it. As this is the only time I ever got this error, I believe it is something that can be handled locally, but only if one knows how to test for it. So, change the Language of your windows or do other lengthy tree walks in order to protect your application from this bug.

The latest sources are now on Github: C# 4.0 library to generate INotifyPropertyChanged proxy from POCO type. The source from the post, designed as a proof of concept, is not the same as the one from Github.

It all started from a Sacha Barber post on CodeProject, enumerating ways in which one can use Aspect Oriented Programming to mark simple automatic properties so that they get compiled into fully fledged INotifyPropertyChanged properties, thus saving us the grief of repeating the same code over and over again in each property setter. The implementations there were good, but too complex, relying on third party libraries, some of them not even free.
He completely ignored template generators like T4, but then again, that particular approach has a lot of issues associated with it, like having to either parse source files or somehow tap into the compiled assembly... before you compile it.
However, this brought forth the idea that I could do this, maybe in some other way.

Enter Felice Pollano, with his article on CodeProject detailing a method of using CodeDom generation to create at runtime the INotifyPropertyChanged object from an already existing type. This is pretty slow, but only when first creating the type, so with a cache system it would be totally usable. I liked this approach better, but I noticed there were some errors in the generated code and when I tried changing the generating code I had to look at it for half an hour just to understand where to change it. Wouldn't it be better to use some sort of template that would be easy to edit and use it to generate the proxy type?

So this is my take on generating INotifyPropertyChanged classes dynamically, avoiding the repetitive plumbing in property setters. The library contains a template for the class and a separate template for the properties. The proxy type is being generated in memory from a string that is generated from the source type and the two templates. All in all, one class, two templates, three public methods and four static methods. As easy as 1,2,3,4 :) Here is the code:

Click to expand/collapse
public static class TypeFactory
{
private static readonly Dictionary<Type, Type> sCachedTypes = new Dictionary<Type, Type>();

public static T GetINotifyPropertyChangedInstance<T>(params object[] arguments)
{
Type type = GetINotifyPropertyChangedType<T>();
return (T) Activator.CreateInstance(type, arguments);
}

public static Type GetINotifyPropertyChangedType<T>()
{
return GetINotifyPropertyChangedType(typeof (T));
}

public static Type GetINotifyPropertyChangedType(Type type)
{
Type result;
lock (((ICollection) sCachedTypes).SyncRoot)
{
if (!sCachedTypes.TryGetValue(type, out result))
{
result = createINotifyPropertyChangedProxyType(type);
sCachedTypes[type] = result;
}
}
return result;
}

public static bool IsVirtual(this PropertyInfo info)
{
return (info.CanRead == false || info.GetGetMethod().IsVirtual)
&&
(info.CanWrite == false || info.GetSetMethod().IsVirtual);
}


private static Type createINotifyPropertyChangedProxyType(Type type)
{
var className = "@autonotify_" + type.Name;
var properties = type.GetProperties().Where(p => p.IsVirtual());
var sourceCode = getINotifyPropertyChangedSourceCode(className, type, properties);
var assembly = generateAssemblyFromCode(sourceCode);
return assembly.GetTypes().First();
}

private static string getINotifyPropertyChangedSourceCode(string className, Type baseType,
IEnumerable<PropertyInfo> properties)
{
var classTemplate = getTemplate("INotifyPropertyChangedClassTemplate.txt");
var propertyTemplate = getTemplate("INotifyPropertyChangedPropertyTemplate.txt");
var usingsBuilder = new StringBuilder();
var propertiesBuilder = new StringBuilder();
usingsBuilder.AppendLine("using System.ComponentModel;");
usingsBuilder.AppendFormat("using {0};\r\n", baseType.Namespace);
foreach (PropertyInfo propertyInfo in properties)
{
usingsBuilder.AppendFormat("using {0};\r\n", propertyInfo.PropertyType.Namespace);

string propertyString = propertyTemplate
.Replace("{propertyType}", propertyInfo.PropertyType.FullName)
.Replace("{propertyName}", propertyInfo.Name);
propertiesBuilder.AppendLine(propertyString);
}
string sourceCode = classTemplate
.Replace("{usings}", usingsBuilder.ToString())
.Replace("{className}", className)
.Replace("{baseClassName}", baseType.Name)
.Replace("{properties}", propertiesBuilder.ToString());
#if DEBUG
Debug.WriteLine(sourceCode);
#endif
return sourceCode;
}

private static string getTemplate(string resourceName)
{
var templateAssembly = Assembly.GetAssembly(typeof (TypeFactory));
resourceName = templateAssembly.GetManifestResourceNames()
.First(name => name.EndsWith(resourceName));
using (Stream stream = templateAssembly.GetManifestResourceStream(resourceName))
{
using (var streamReader = new StreamReader(stream))
{
return streamReader.ReadToEnd();
}
}
}

private static Assembly generateAssemblyFromCode(string sourceCode)
{
var codeProvider = CodeDomProvider.CreateProvider("CSharp");
var parameters = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true
};
var locations = AppDomain.CurrentDomain.GetAssemblies()
.Where(v => !v.IsDynamic).Select(a => a.Location).ToArray();
parameters.ReferencedAssemblies.AddRange(locations);
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, sourceCode);
#if DEBUG
foreach (CompilerError error in results.Errors)
{
Debug.WriteLine("Error: " + error.ErrorText);
}
#endif
return results.Errors.Count > 0
? null
: results.CompiledAssembly;
}
}


As you can see, the code needs only a type that has public virtual properties in it and it will create a proxy that will inherit that class, implement INotifyPropertyChange and override each virtual property with a notifying one. The templates are so basic that I feel slightly embarrassed; I keep thinking if I should have created template entities that would stay in the same file. :) Here are the templates:

{usings}

namespace __generatedINotifyPropertyChanged
{
  public class {className} : {baseClassName},INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    {properties}

    private void OnPropertyChanged(string propertyName)
    {
      var handler=PropertyChanged;
      if (handler != null)
      {
        handler(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}

public override {propertyType} {propertyName}
{
  get { return base.{propertyName}; }
  set {
    if (!Equals(value,base.{propertyName})) {
      base.{propertyName}=value;
      OnPropertyChanged("{propertyName}");
    }
  }
}


Don't forget to save the templates as Embedded Resource in the assembly.

Update: At Sacha Barber's advice I took a look at the DynamicObject solution for the INotifyPropertyChanged code smell. The link he provided is OlliFromTor's CodeProject article Using DynamicObject to Implement General Proxy Classes. While this works a lot easier than with compiling generated code, it also has a major drawback: the proxy class does not inherit from the original object and so it can only be used as such, but only in dynamic scenarios. Otherwise, it seems to be a perfect solution for proxy scenarios, if you are willing to discard the type safety.

When I first tried to do drag and drop in WPF I thought it would be something easy like DragAndDrop.IsDraggable="True". Boy,was I wrong! The mechanism for this has remained almost unchanged from the Windows Forms version. It is completely event driven and has nothing in the way of actual graphical feedback of what is going on except making the mouse cursor look different. If you want to do it using MVVM, you have another thing coming.

Disclaimer:Now, I have found a good solution for all the problems above, but the drag and drop behaviour is part of a larger framework that I have been working on and creating a separate project just for it might prove difficult. I mean, you want to show MVVM drag and drop, you should also have Views and ViewModels and base classes and helpers and everything. The solution, I guess, is to make separate articles for the main features in the framework, then present the project as a whole in the end. The framework itself is work in progress and untested in a real life project, so this might have to wait, as well. I will make sure, though, to put much code directly in this post.

First a bit of thanks to the people that inspired me to work on that. I have Sascha Barber to thank for his comprehensive articles on WPF, especially the ones about his Cinch framework. Then Lee Roth and Bea Stollnitz/Costa for the ideas about using adorners to show the drag and drop items. Finally Jason Young, for writing about MVVM Drag and Drop, but without the graphic part.

Ok then, let's define the requirements of this system. We need:

  • A drag item
  • A drop target
  • Showing the target is being dragged
  • Showing the target can or cannot be dropped
  • Showing the item being dragged
  • Changing the appearance of the original dragged element while dragging
  • Changing the appearance of the drop target while dragging something over
  • Allowing for drag and drop between Windows
  • Allowing for drag and drop between applications
  • Changing an application that works but has no drag and drop in an easy and maintainable way
  • Using as simple a system as possible
  • Doing everything using the Model-View-ViewModel pattern


From these requirements we can form a basic idea of the way we would like this to work. First of all, we need the ability to mark any element as a drag item. Also, we need a container that can be marked as a drop target. We can do this using boolean IsDragSource and IsDropTarget Attached Properties; once set they will force a bind of the drag and drop events to some special handlers that would then direct decisions to ICommands.

As we are doing it in MVVM, we don't use the elements directly, but the data they represent, so we work with dragging and dropping commands using data objects. The classes responsible with the decisions for the drop permissions and actions should be in the ViewModel. We could, of course, link all events to commands, but that would be very cumbersome to use. Besides, we want it simple, we don't really want the user of the system to care about the drag and drop inner workings. Therefore, the solution is to change the IsDragSource and IsDropTarget to DragSource and DropTarget properties that accept objects of type IDragSource and IDropTarget containing all the methods needed for the events in question:


/// <summary>
/// Holds the data of a dragged object in a drag-and-drop operation.
/// </summary>
public interface IDraggedData
{
/// <summary>
/// A dictionary with the format as the key and the data in that format in the value
/// </summary>
IDictionary<string, object> Values
{
get;
}

/// <summary>
/// Optional object for additional information
/// </summary>
object Tag
{
get;
}
}

/// <summary>
/// Business end of the drag source
/// </summary>
public interface IDragSource
{
/// <summary>
/// Gets the supported drop effects.
/// </summary>
/// <param name="dataContext">The data context.</param>
/// <returns></returns>
DragEffects GetDragEffects(object dataContext);

/// <summary>
/// Gets the data.
/// </summary>
/// <param name="dataContext">The data context.</param>
/// <returns></returns>
object GetData(object dataContext);
}

/// <summary>
/// Defines the handler object of a drop operation
/// </summary>
public interface IDropTarget
{
/// <summary>
/// Gets the effects.
/// </summary>
/// <param name="dataObject">The data object.</param>
/// <returns></returns>
DragEffects GetDropEffects(IDraggedData dataObject);

/// <summary>
/// Drops the specified data object
/// </summary>
/// <param name="dataObject">The data object.</param>
void Drop(IDraggedData dataObject);
}

We need the methods for the effects to instruct the system about the types of operations that are allowed during drag and drop: None, Copy, Move, Scroll, All.

If you are going for the purist approach, you should use your own DragEffects enumeration, as above, since the DragDropEffects enumeration is in the System.Windows assembly, which in theory should have nothing to do with the ViewModel part of the application (one could want to use the ViewModel in a web environment, for example, or in a console application).

You will notice that the GetDropEffects method receives an IDraggedData object. This is also because the IDataObject interface and the DataObject class used in Windows drag and drop operations are also in the System.Windows assembly.

The IDraggedData interface is basically a dictionary that uses the data format as the key and the dragged data object stored in that format as the value. An important fact is that, when trying to drag and drop between applications, you need that the dragged data object be binary serializable. If not, you will only get the expected result when dragging to the same application. Here is an implementation of the interface, complete with a totally lazy way of getting the data based on which type is more "important":


/// <summary>
/// Holds data for a drag-and-drop operation
/// </summary>
public class DraggedData : IDraggedData
{
#region Instance fields

private Dictionary<string, Exception> mExceptions;
private Dictionary<string, object> mValues;

#endregion

#region Properties

/// <summary>
/// A dictionary with the format as the key and the data in that format in the value
/// </summary>
/// <value></value>
public Dictionary<string, object> Values
{
get
{
if (mValues == null)
{
mValues = new Dictionary<string, object>();
}
return mValues;
}
}

/// <summary>
/// A dictionary with the format as the key and the data in that format in the value
/// </summary>
/// <value></value>
IDictionary<string, object> IDraggedData.Values
{
get
{
return Values;
}
}

/// <summary>
/// Optional object for additional information
/// </summary>
/// <value></value>
public object Tag
{
get;
set;
}

/// <summary>
/// A dictionary for exceptions when retrieving the data in a specified format
/// </summary>
/// <value>The exceptions.</value>
public Dictionary<string, Exception> Exceptions
{
get
{
if (mExceptions == null)
{
mExceptions = new Dictionary<string, Exception>();
}
return mExceptions;
}
}

#endregion
}

In the IDragSource interface we need the GetData method to extract the data object associated with a dragged object, since the Windows drag and drop mechanism encapsulates the objects in an application agnostic way, so one can perform drag and drop between applications or to/from the operating system. Finally, we need the Drop method in the IDropTarget interface to handle in the ViewModel what happends when an item is dropped.

Let's get to the juicy part: a DragService static class that will register the attached properties that we need. Besides the DragSource and DropTarget properties we need status properties like DragOverStatus (for the target), DraggedStatus and IsDragged (for the original dragged item) as well as two properties called BringIntoViewOnDrag and ActivateOnDrag which would bring an item completely into view or activate it (if a Window) when a valid drop target. This one is long. It also contains some extension methods that would be explained later.

Click to expand/collapse

/// <summary>
/// Holds attached properties related to drag-and-drop operations
/// </summary>
public static class DragService
{
#region Static Instance fields

/// <summary>
/// Property for the behaviour to activate a window when something is dragged over it
/// </summary>
public static readonly DependencyProperty ActivateOnDragProperty
= DependencyProperty.RegisterAttached(
"ActivateOnDrag",
typeof (bool), typeof (DragService),
new FrameworkPropertyMetadata(
false)
);

/// <summary>
/// Property for the behaviour to bring into view an element when something is dragged over it
/// </summary>
public static readonly DependencyProperty BringIntoViewOnDragProperty
= DependencyProperty.RegisterAttached(
"BringIntoViewOnDrag",
typeof (bool), typeof (DragService),
new FrameworkPropertyMetadata(
false)
);

/// <summary>
/// Property for the status of a drag-over operation
/// </summary>
public static readonly DependencyProperty DragOverStatusProperty
= DependencyProperty.RegisterAttached(
"DragOverStatus",
typeof (DragEffects), typeof (DragService),
new FrameworkPropertyMetadata(DragEffects.None)
);

/// <summary>
/// Property for the handler of drag-source operations
/// </summary>
public static readonly DependencyProperty DragSourceProperty
= DependencyProperty.RegisterAttached(
"DragSource",
typeof (IDragSource), typeof (DragService),
new FrameworkPropertyMetadata(null, new PropertyChangedCallback(dragSourceChanged))
);

/// <summary>
/// Property for the drag status of a drag source
/// </summary>
public static readonly DependencyProperty DragStatusProperty
= DependencyProperty.RegisterAttached(
"DragStatus",
typeof (DragEffects), typeof (DragService),
new FrameworkPropertyMetadata(DragEffects.None)
);

/// <summary>
/// Property for the handler of drop-target operations
/// </summary>
public static readonly DependencyProperty DropTargetProperty
= DependencyProperty.RegisterAttached(
"DropTarget",
typeof (IDropTarget), typeof (DragService),
new FrameworkPropertyMetadata(null, new PropertyChangedCallback(dropTargetChanged)));

/// <summary>
/// True if element is part of the content displayed while dragging
/// </summary>
public static readonly DependencyProperty IsDraggedProperty
= DependencyProperty.RegisterAttached(
"IsDragged",
typeof (bool), typeof (DragService),
new FrameworkPropertyMetadata(false)
);

private static DependencyObject sDraggedDependencyObject;
private static Point? sStartPoint;

#endregion

#region Static Public Methods

///<summary>
/// Attached getter method for DragOverStatus
///</summary>
///<param name="element"></param>
///<returns></returns>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[AttachedPropertyBrowsableForType(typeof (UIElement))]
public static DragEffects GetDragOverStatus(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (DragEffects) element.GetValue(DragOverStatusProperty);
}

///<summary>
/// Attached setter method for DragOverStatus
///</summary>
///<param name="element"></param>
///<param name="value"></param>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetDragOverStatus(DependencyObject element, DragEffects value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(DragOverStatusProperty, value);
}

///<summary>
/// Attached getter method for DragStatus
///</summary>
///<param name="element"></param>
///<returns></returns>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[AttachedPropertyBrowsableForType(typeof (UIElement))]
public static DragEffects GetDragStatus(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (DragEffects) element.GetValue(DragStatusProperty);
}

///<summary>
/// Attached setter method for DragStatus
///</summary>
///<param name="element"></param>
///<param name="value"></param>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetDragStatus(DependencyObject element, DragEffects value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(DragStatusProperty, value);
}

///<summary>
/// Attached getter method for IsDragged
///</summary>
///<param name="element"></param>
///<returns></returns>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[AttachedPropertyBrowsableForType(typeof (UIElement))]
public static bool GetIsDragged(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool) element.GetValue(IsDraggedProperty);
}

///<summary>
/// Attached setter method for IsDragged
///</summary>
///<param name="element"></param>
///<param name="value"></param>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetIsDragged(DependencyObject element, bool value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(IsDraggedProperty, value);
}

/// <summary>
/// Try to get the dragged data in its most qualified format:
/// something not null and not string, string, anything else, null
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
public static object GetBestDraggedDataObject(DragEventArgs e)
{
DraggedData draggedData = getData(e);
object data = null;
foreach (KeyValuePair<string, object> pair in draggedData.Values)
{
object value = pair.Value;
if (value == null)
{
continue;
}
if (data == null)
{
data = value;
continue;
}
if ((data is string) && !(value is string))
{
data = value;
break;
}
}
return data;
}

///<summary>
/// Attached getter method for DropTarget
///</summary>
///<param name="element"></param>
///<returns></returns>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[AttachedPropertyBrowsableForType(typeof (UIElement))]
public static IDropTarget GetDropTarget(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (IDropTarget) element.GetValue(DropTargetProperty);
}

///<summary>
/// Attached setter method for DropTarget
///</summary>
///<param name="element"></param>
///<param name="value"></param>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetDropTarget(DependencyObject element, IDropTarget value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(DropTargetProperty, value);
}

///<summary>
/// Attached getter method for DragSource
///</summary>
///<param name="element"></param>
///<returns></returns>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[AttachedPropertyBrowsableForType(typeof (UIElement))]
public static IDragSource GetDragSource(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (IDragSource) element.GetValue(DragSourceProperty);
}

///<summary>
/// Attached setter method for DragSource
///</summary>
///<param name="element"></param>
///<param name="value"></param>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetDragSource(DependencyObject element, IDragSource value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(DragSourceProperty, value);
}

///<summary>
/// Attached getter method for BringIntoViewOnDrag
///</summary>
///<param name="element"></param>
///<returns></returns>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[AttachedPropertyBrowsableForType(typeof (FrameworkElement))]
public static bool GetBringIntoViewOnDrag(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool) element.GetValue(BringIntoViewOnDragProperty);
}

///<summary>
/// Attached setter method for BringIntoViewOnDrag
///</summary>
///<param name="element"></param>
///<param name="value"></param>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetBringIntoViewOnDrag(DependencyObject element, bool value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(BringIntoViewOnDragProperty, value);
}

///<summary>
/// Attached getter method for ActivateOnDrag
///</summary>
///<param name="element"></param>
///<returns></returns>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[AttachedPropertyBrowsableForType(typeof (UIElement))]
public static bool GetActivateOnDrag(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool) element.GetValue(ActivateOnDragProperty);
}

///<summary>
/// Attached setter method for ActivateOnDrag
///</summary>
///<param name="element"></param>
///<param name="value"></param>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetActivateOnDrag(DependencyObject element, bool value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(ActivateOnDragProperty, value);
}

#endregion

#region Static Private Methods

private static void dropTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement element = (UIElement) d;

if (e.NewValue != null)
{
registerDropTarget(element);
}
else
{
unregisterDropTarget(element);
}
}

private static void unregisterDropTarget(UIElement element)
{
element.DragOver -= dragOver;
element.DragLeave -= elementDragLeave;
element.Drop -= drop;
element.AllowDrop = false;
}

private static void registerDropTarget(UIElement element)
{
element.DragOver += dragOver;
element.DragLeave += elementDragLeave;
element.Drop += drop;
element.AllowDrop = true;
element.ExecuteWhenUnloaded(() => unregisterDropTarget(element));
}

private static void elementDragLeave(object sender, DragEventArgs e)
{
DependencyObject dependencyObject = (DependencyObject) sender;
SetDragOverStatus(dependencyObject, DragEffects.None);
}

private static void drop(object sender, DragEventArgs e)
{
DependencyObject dependencyObject = (DependencyObject) sender;
IDropTarget dropTarget = GetDropTarget(dependencyObject);
DraggedData data = getData(e);
dropTarget.Drop(data);
SetDragOverStatus(dependencyObject, DragEffects.None);
e.Handled = true;
}

private static DraggedData getData(DragEventArgs e)
{
DraggedData data = new DraggedData();
string[] formats = e.Data.GetFormats(false);
foreach (string format in formats)
{
try
{
data.Values[format] = e.Data.GetData(format);
}
catch (Exception ex)
{
data.Values[format] = null;
data.Exceptions[format] = ex;
}
}
return data;
}

private static void dragOver(object sender, DragEventArgs e)
{
DependencyObject dependencyObject = (DependencyObject) sender;
IDropTarget dropTarget = GetDropTarget(dependencyObject);

DraggedData data = getData(e);
DragEffects dragEffects = dropTarget.GetDropEffects(data);
e.Effects = getEffects(dragEffects);
if (sDraggedDependencyObject != null)
{
SetDragStatus(sDraggedDependencyObject, dragEffects);
}
SetDragOverStatus(dependencyObject, dragEffects);

e.Handled = true;
if (GetActivateOnDrag(dependencyObject))
{
Window window = Window.GetWindow(dependencyObject);
if (window != null && !window.IsActive)
{
window.Activate();
}
}
if (GetBringIntoViewOnDrag(dependencyObject))
{
FrameworkElement element = dependencyObject as FrameworkElement;
if (element != null)
{
element.BringIntoView();
}
}
}

private static DragDropEffects getEffects(DragEffects effects)
{
DragDropEffects result;
return Enum.TryParse(effects.ToString(), out result)
? result
: (DragDropEffects) (int) effects;
}

private static void dragSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement element = (UIElement) d;
if (e.NewValue != null)
{
registerDragItem(element);
}
else
{
unregisterDragItem(element);
}
}

private static void unregisterDragItem(UIElement element)
{
element.PreviewMouseLeftButtonDown -= previewMouseLeftButtonDown;
element.PreviewMouseMove -= previewMouseMove;
element.MouseLeave -= mouseLeave;
element.QueryContinueDrag -= elementQueryContinueDrag;
element.GiveFeedback -= elementGiveFeedback;
}

private static void registerDragItem(UIElement element)
{
element.PreviewMouseLeftButtonDown += previewMouseLeftButtonDown;
element.PreviewMouseMove += previewMouseMove;
element.MouseLeave += mouseLeave;
element.QueryContinueDrag += elementQueryContinueDrag;
element.GiveFeedback += elementGiveFeedback;
element.ExecuteWhenUnloaded(() => unregisterDragItem(element));
}

private static void elementGiveFeedback(object sender, GiveFeedbackEventArgs e)
{
if (sDraggedDependencyObject != null)
{
DragEffects dragDropEffects = getDragDropEffects(e.Effects);
SetDragStatus(sDraggedDependencyObject, dragDropEffects);
}
}

private static DragEffects getDragDropEffects(DragDropEffects effects)
{
DragEffects result;
return Enum.TryParse(effects.ToString(), out result)
? result
: (DragEffects) (int) effects;
}

private static void elementQueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
if (!e.KeyStates.HasFlag(DragDropKeyStates.LeftMouseButton))
{
DependencyObject dependencyObject = sender as DependencyObject ?? sDraggedDependencyObject;
endDrag(dependencyObject);
}
}

private static void endDrag(DependencyObject dependencyObject)
{
if (dependencyObject == null)
{
return;
}
SetIsDragged(dependencyObject, false);
if (sDraggedDependencyObject != null)
{
SetDragStatus(sDraggedDependencyObject, DragEffects.None);
}
sDraggedDependencyObject = null;
}

private static void mouseLeave(object sender, MouseEventArgs e)
{
sStartPoint = null;
}

private static void previewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton != MouseButtonState.Pressed || sStartPoint == null)
{
return;
}

if (!hasMouseMovedFarEnough(e))
{
return;
}

FrameworkElement dependencyObject = (FrameworkElement) sender;
object dataContext = dependencyObject.GetValue(FrameworkElement.DataContextProperty);
IDragSource dragSource = GetDragSource(dependencyObject);

DragDropEffects dragDropEffects = getEffects(dragSource.GetDragEffects(dataContext));
if (dragDropEffects == DragDropEffects.None)
{
return;
}
startDrag(dependencyObject);
DragDrop.DoDragDrop(dependencyObject,
getDraggedData(dragSource, dataContext),
dragDropEffects);
}

private static void startDrag(DependencyObject dependencyObject)
{
SetIsDragged(dependencyObject, true);
sDraggedDependencyObject = dependencyObject;
}

private static object getDraggedData(IDragSource dragSource, object dataContext)
{
object data = dragSource.GetData(dataContext);
DataObject dataObject = new DataObject();
if (data != null)
{
if (!SerializationHelper.IsBinarySerializable(data))
{
DebugHelper.Warn(
"Trying to drag a DataItem that cannot be binary serialized. It will not work across applications");
}
dataObject.SetData(DataFormats.Text, data.ToString());
string typeName = data.GetType().FullName;
if (typeName != null)
{
DataFormat format = DataFormats.GetDataFormat(typeName);
dataObject.SetData(format.Name, data);
}
}
return dataObject;
}

private static void previewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
sStartPoint = e.GetPosition(null);
}

private static bool hasMouseMovedFarEnough(MouseEventArgs e)
{
if (sStartPoint == null)
{
return false;
}
Vector delta = sStartPoint.GetValueOrDefault() - e.GetPosition(null);

return Math.Abs(delta.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(delta.Y) > SystemParameters.MinimumVerticalDragDistance;
}

#endregion
}

Most of the code here is self explanatory: you have attached property that bind to the element drag and drop events and handle them either through direct code or by delegating to the values set. There are some extension methods like ExecuteWhenLoaded and ExecuteWhenUnloaded which execute an action when the element has finished loading or when it is unloading. An important aspect here is that a window closing does not trigger the Unloaded event for its child elements, so you need to bind to the Dispatcher.StartedShutdown event as well:


/// <summary>
/// Execute an action when an element is unloaded
/// </summary>
/// <param name="element"></param>
/// <param name="action"></param>
public static void ExecuteWhenUnloaded(this UIElement element, Action action)
{
if (element == null)
{
throw new ArgumentNullException("element",
Resources.
UIExtensions_ExecuteWhenUnloaded_Element_cannot_be_null);
}
RoutedEventHandler elementOnUnloaded = null;
EventHandler dispatcherOnShutdownStarted = null;
// ReSharper disable AccessToModifiedClosure
elementOnUnloaded = (sender, args) =>
{
performExecution(element,
dispatcherOnShutdownStarted,
elementOnUnloaded,
action);
};
dispatcherOnShutdownStarted = (sender, args) =>
{
performExecution(element,
dispatcherOnShutdownStarted,
elementOnUnloaded, action);
};
// ReSharper restore AccessToModifiedClosure
FrameworkElement frameworkElement = element as FrameworkElement;
if (frameworkElement != null)
{
frameworkElement.Unloaded += elementOnUnloaded;
}
element.Dispatcher.ShutdownStarted += dispatcherOnShutdownStarted;
}


That is pretty much it for the drag and drop itself. You can implement IDropTarget on the ViewModel directly, but IDragSource needs to be binary serializable if you intend to drag and drop across application domains, so you usually implement it into a separate class that is a property of the dragged item view model or DataContext.

Because the DragService sets the status properties for each element, you can manipulate the appearance and behaviour of both drag source and drop target based on them. However, at this point the mouse will be the only indication that you are dragging something. You might want to actually drag something, especially since in a move operation the original element would be hidden during the drag. The problem here is that the drag source element cannot control the display of the dragged item in other applications, nor should it in its application, since it is not its responsibility. The solution: decorate an element over which you would drag something (like the root element of the entire window) with something that knows how to display dragged items:

Click to expand/collapse

/// <summary>
/// Decorator for an element that would respons visually to a drag-over operation
/// </summary>
public class DragAndDropAdornerDecorator : ContentControl
{
#region Instance fields

private DragAndDropAdorner mAdorner;

#endregion

#region Properties

/// <summary>
/// Visual content for the dragged data
/// </summary>
public FrameworkElement AdornerContent
{
get
{
return (FrameworkElement) GetValue(AdornerContentProperty);
}
set
{
SetValue(AdornerContentProperty, value);
}
}

/// <summary>
/// The data being dragged
/// </summary>
public object DraggedData
{
get
{
return GetValue(DraggedDataProperty);
}
set
{
SetValue(DraggedDataProperty, value);
}
}

/// <summary>
/// The position of the drag point in the decorator content
/// </summary>
public Point Offset
{
get
{
return (Point) GetValue(OffsetProperty);
}
set
{
SetValue(OffsetProperty, value);
}
}

/// <summary>
/// Represents the point in which a dragged item has first entered the drag zone.
/// Use it to create animations when a drop operation did not succeed.
/// </summary>
public Point? EntryPoint
{
get
{
return (Point?) GetValue(EntryPointProperty);
}
private set
{
SetValue(EntryPointPropertyKey, value);
}
}

#endregion

#region Constructors

/// <summary>
/// Initializes a new instance of the <see cref="DragAndDropAdornerDecorator"/> class.
/// </summary>
public DragAndDropAdornerDecorator()
{
Focusable = false; // By default don't want 'AdornedControl' to be focusable.

DataContextChanged += dragAndDropAdornerDecoratorDataContextChanged;
updateAdornerDataContext();
}

#endregion

#region Protected Methods

/// <summary>
/// Called when the <see cref="T:System.Windows.Media.VisualCollection"/> of the visual object is modified.
/// </summary>
/// <param name="visualAdded">The <see cref="T:System.Windows.Media.Visual"/> that was added to the collection</param><param name="visualRemoved">The <see cref="T:System.Windows.Media.Visual"/> that was removed from the collection</param>
protected override void OnVisualChildrenChanged(DependencyObject visualAdded,
DependencyObject visualRemoved)
{
UIElement element = visualRemoved as UIElement;
if (element != null)
{
dettachAdorner(element);
}
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
element = visualAdded as UIElement;
if (element != null)
{
attachAdorner(element);
this.ExecuteWhenUnloaded(() => dettachAdorner(element));
}
}

#endregion

#region Private Methods

private void dragAndDropAdornerDecoratorDataContextChanged(object sender,
DependencyPropertyChangedEventArgs e)
{
updateAdornerDataContext();
}

/// <summary>
/// Update the DataContext of the adorner from the adorned control.
/// </summary>
private void updateAdornerDataContext()
{
if (AdornerContent != null)
{
AdornerContent.DataContext = DataContext;
}
}

private void attachAdorner(UIElement element)
{
mAdorner = new DragAndDropAdorner(element, AdornerContent)
{
Decorator = this
};
mAdorner.Attach();
AddLogicalChild(mAdorner.AdornerLayer);
element.AddHandler(DragEnterEvent, new DragEventHandler(elementDragEnter), true);
element.AddHandler(DragOverEvent, new DragEventHandler(elementDragOver), true);
element.AddHandler(DragLeaveEvent, new DragEventHandler(elementDragLeave), true);
element.AddHandler(QueryContinueDragEvent,
new QueryContinueDragEventHandler(elementQueryContinueDrag), true);
element.AddHandler(DropEvent,
new DragEventHandler(elementDrop), true);
hideAdorner();
}

private void elementDragEnter(object sender, DragEventArgs e)
{
EntryPoint = e.GetPosition(this);
}

private void elementDrop(object sender, DragEventArgs e)
{
hideAdorner();
}

private void elementQueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
if (!e.KeyStates.HasFlag(DragDropKeyStates.LeftMouseButton))
{
hideAdorner();
}
}

private void elementDragLeave(object sender, DragEventArgs e)
{
hideAdorner();
}

private void hideAdorner()
{
DraggedData = null;
EntryPoint = null;
if (mAdorner == null)
{
return;
}
mAdorner.Hide();
}

private void elementDragOver(object sender, DragEventArgs e)
{
DraggedData = DragService.GetBestDraggedDataObject(e);
showAdorner(e.GetPosition(this));
}

private void showAdorner(Point position)
{
if (mAdorner == null)
{
return;
}
mAdorner.Show(position);
}

private void dettachAdorner(UIElement element)
{
if (mAdorner == null)
{
return;
}
RemoveLogicalChild(mAdorner.AdornerLayer);
mAdorner.DisconnectChild();
mAdorner.Dettach();
mAdorner = null;
element.RemoveHandler(DragEnterEvent, new DragEventHandler(elementDragEnter));
element.RemoveHandler(DragOverEvent, new DragEventHandler(elementDragOver));
element.RemoveHandler(DragLeaveEvent, new DragEventHandler(elementDragLeave));
element.RemoveHandler(QueryContinueDragEvent,
new QueryContinueDragEventHandler(elementQueryContinueDrag));
element.RemoveHandler(DropEvent, new DragEventHandler(elementDrop));
}

#endregion

#region Static Instance fields

public static readonly DependencyProperty AdornerContentProperty
= DependencyProperty.Register("AdornerContent",
typeof (FrameworkElement),
typeof (DragAndDropAdornerDecorator),
new FrameworkPropertyMetadata(null));

public static readonly DependencyProperty DraggedDataProperty
= DependencyProperty.RegisterAttached(
"DraggedData",
typeof (object), typeof (DragAndDropAdornerDecorator),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.
OverridesInheritanceBehavior
| FrameworkPropertyMetadataOptions.Inherits)
);

public static readonly DependencyPropertyKey EntryPointPropertyKey
= DependencyProperty.RegisterReadOnly("EntryPoint",
typeof (Point?), typeof (DragAndDropAdornerDecorator),
new FrameworkPropertyMetadata(default(Point?)));

public static readonly DependencyProperty EntryPointProperty =
EntryPointPropertyKey.DependencyProperty;


public static readonly DependencyProperty OffsetProperty
= DependencyProperty.Register("Offset",
typeof (Point), typeof (DragAndDropAdornerDecorator),
new FrameworkPropertyMetadata(new Point()));

#endregion

#region Static Public Methods

///<summary>
/// Attached getter method for DraggedData
///</summary>
///<param name="element"></param>
///<returns></returns>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[AttachedPropertyBrowsableForType(typeof (UIElement))]
public static object GetDraggedData(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return element.GetValue(DraggedDataProperty);
}

///<summary>
/// Attached setter method for DraggedData
///</summary>
///<param name="element"></param>
///<param name="value"></param>
///<exception cref="ArgumentNullException"></exception>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public static void SetDraggedData(DependencyObject element, object value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(DraggedDataProperty, value);
}

#endregion
}

This code uses an adorner to display the dragged item over it. Nothing fancy, since the actual template for the dragged data is defined in the decorator as the content. This is not the place to discuss the adorner, though, so here is just the code:

Click to expand/collapse

/// <summary>
/// Adorner for the drag-and-drop operations: see DragHelper and DragAndDropDecorator
/// </summary>
public class DragAndDropAdorner : AdornerBase
{
#region Instance fields

private readonly FrameworkElement mChild;
private Point mPosition;

#endregion

#region Properties

/// <summary>
/// Gets the number of visual child elements within this element.
/// </summary>
/// <returns>
/// The number of visual child elements for this element.
/// </returns>
protected override int VisualChildrenCount
{
get
{
return 1;
}
}

/// <summary>
/// Gets an enumerator for logical child elements of this element.
/// </summary>
/// <returns>
/// An enumerator for logical child elements of this element.
/// </returns>
protected override IEnumerator LogicalChildren
{
get
{
yield return mChild;
}
}

/// <summary>
/// Reference to the decorator that instantiates the adorner
/// </summary>
public DragAndDropAdornerDecorator Decorator
{
get;
set;
}

#endregion

#region Constructors

/// <summary>
/// Instantiate an adorner for an element over which to show the dragged content
/// </summary>
/// <param name="adornedElement"></param>
/// <param name="adornerContent"></param>
public DragAndDropAdorner(UIElement adornedElement, FrameworkElement adornerContent)
: base(adornedElement)
{
IsHitTestVisible = false;
Focusable = false;
mChild = adornerContent;
connectChild();
}

#endregion

#region Public Methods

/// <summary>
/// Disconnect the child element from the visual tree so that it may be reused later.
/// </summary>
public void DisconnectChild()
{
RemoveLogicalChild(mChild);
RemoveVisualChild(mChild);
}

/// <summary>
/// Hide the adorner content
/// </summary>
public void Hide()
{
Opacity = 0.0;
Visibility = Visibility.Collapsed;
}

/// <summary>
/// Show the adorner content at a certain position
/// </summary>
/// <param name="point"></param>
public void Show(Point point)
{
mPosition = point;
Opacity = 1.0;
Visibility = Visibility.Visible;
InvalidateArrange();
}

#endregion

#region Protected Methods

/// <summary>
/// Implements any custom measuring behavior for the adorner.
/// </summary>
/// <returns>
/// A <see cref="T:System.Windows.Size"/> object representing the amount of layout space needed by the adorner.
/// </returns>
/// <param name="constraint">A size to constrain the adorner to.</param>
protected override Size MeasureOverride(Size constraint)
{
mChild.Measure(constraint);
return mChild.DesiredSize;
}

/// <summary>
/// When overridden in a derived class, positions child elements and determines a size for a <see cref="T:System.Windows.FrameworkElement"/> derived class.
/// </summary>
/// <returns>
/// The actual size used.
/// </returns>
/// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>
protected override Size ArrangeOverride(Size finalSize)
{
double adornerWidth = mChild.DesiredSize.Width;
double adornerHeight = mChild.DesiredSize.Height;
double offsetX=0;
double offsetY=0;
if (Decorator!=null)
{
offsetX = -Decorator.Offset.X;
offsetY = -Decorator.Offset.Y;
}
mChild.Arrange(new Rect(mPosition.X + offsetX, mPosition.Y + offsetY, adornerWidth, adornerHeight));
return finalSize;
}

/// <summary>
/// Overrides <see cref="M:System.Windows.Media.Visual.GetVisualChild(System.Int32)"/>, and returns a child at the specified index from a collection of child elements.
/// </summary>
/// <returns>
/// The requested child element. This should not return null; if the provided index is out of range, an exception is thrown.
/// </returns>
/// <param name="index">The zero-based index of the requested child element in the collection.</param>
protected override Visual GetVisualChild(int index)
{
return mChild;
}

#endregion

#region Private Methods

private void connectChild()
{
AddLogicalChild(mChild);
AddVisualChild(mChild);
}

#endregion
}

You would only need to decorate a view and then define the AdornerContent property for the decorator and, optionally, the grab point offset for the dragged element.

All that is left here is to show some usage examples. Let's assume we need a View over which we can drag and drop items:

<UserControl x:Class="BestPractices.Views.SecondaryView"
[...]
UIUtils:DragService.DropTarget="{Binding .}"
UIUtils:DragService.BringIntoViewOnDrag="True"
UIUtils:DragService.ActivateOnDrag="True"
UIUtils:DragService.DragOverStatus="{Binding DragOverStatus,Mode=OneWayToSource}">

Here you have a user control view which has the drop target set to its own view model and it is set to update the DragOverStatus property of the ViewModel when its attached DragOverStatus property is changed. The status properties are inheritable, so all the children of the view have them set. It is easy to define a Button style that has its text bolded when a copy operation is allowed for a drop item:

<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}" >  <Style.Triggers>
<DataTrigger Binding="{Binding DragOverStatus}" Value="{x:Static Utils:DragEffects.Copy}">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers
></Style>

Its content is more interesting:

<UIUtils:DragAndDropAdornerDecorator Offset="40,40">
<UIUtils:DragAndDropAdornerDecorator.AdornerContent>
<Controls:ContentItem
DataContext="{Binding Path=(UIUtils:DragAndDropAdornerDecorator.DraggedData),
RelativeSource={RelativeSource Self}}"

Opacity="0.7"/>
</UIUtils:DragAndDropAdornerDecorator.AdornerContent>
<DockPanel Background="{Binding Background,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
>
<Button Command="{m:CommandBinding AddItemCommand}"
DockPanel.Dock="Top"
>Add item</Button>
<Button Command="{m:CommandBinding RemoveItemCommand}"
DockPanel.Dock="Top"
>Remove item</Button>
<WrapPanel x:Name="ContainerPanel" >
</WrapPanel>
</DockPanel>
</UIUtils:DragAndDropAdornerDecorator>

The container for the items is a simple WrapPanel and it is placed in a dock panel together with add and remove item buttons. This dock panel is decorated as a drag visual container, and the content that is dragged is set to a custom control called ContentItem, with a drag point set to 40,40. The DataContext property of the item is set to the DraggedData property so that it expresses the actual dragged object.

Now we have set up a container to be a drop target for items. It displays the items as they are dragged over it. All we have left is to set up the items, the ContentItem control, to be a DragSource:


<Style TargetType="{x:Type Controls:ContentItem}">
<Setter Property="UIUtils:DragService.DragSource" Value="{Binding DragSource}"/>
<Setter Property="UIUtils:DragService.IsDragged" Value="{Binding IsDragged,Mode=OneWayToSource}"/>
<Setter Property="UIUtils:DragService.DragStatus" Value="{Binding DragStatus,Mode=OneWayToSource}"/>
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Controls:ContentItem}">
<Border BorderThickness="1" BorderBrush="Blue" CornerRadius="2" Background="{TemplateBinding Background}" Width="75" Height="60">
<TextBlock Text="{Binding Id}" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontSize="22"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsDragged}" Value="True">
<Setter Property="Background" Value="LightPink"/>
</DataTrigger>
<DataTrigger Binding="{Binding DragStatus}" Value="{x:Static Utils:DragEffects.Copy}">
<Setter Property="Background" Value="Lime"/>
</DataTrigger>
</Style.Triggers>
</Style>

The control style defines as a drag source the DragSource property of the data context of the item and synchronizes with the data context the properties of IsDragged and DragStatus. Triggers then make is pinkish when dragged and greenish when it can be dropped. Notice that this applies to the original item, while its representation is dragged, so you have a feedback of what is going on with the item right at the source.

I won't put here the ViewModels or the data items, since they are pretty much part of the business context, not the drag and drop. Just return DragEffects. All on the effects methods and you can drag anything anywhere, for example.

That's it, folks: drag and drop completely MVVM, without as much as writing an event handler or caring about the actual elements in the viewmodel. It would be even easier if you would allow references to WPF assemblies in the ViewModels, since you could also get the source elements and do stuff with them, but that wouldn't be much of an MVVM pattern, would it?

And here is the AdornerBase class, just a simple helper class:


/// <summary>
/// Basic adorner class that exposes simple Attach and Dettach methods
/// </summary>
public abstract class AdornerBase : Adorner
{
#region Instance fields

private bool mIsDettached;

#endregion

#region Properties

public bool IsDettached
{
get
{
return mIsDettached;
}
}

public AdornerLayer AdornerLayer
{
get;
private set;
}

#endregion

#region Constructors

protected AdornerBase(UIElement adornedElement)
: base(adornedElement)
{
mIsDettached = true;
}

#endregion

#region Public Methods

/// <summary>
/// Attach the adorner to the element's adorner layer
/// </summary>
public void Attach()
{
AdornerLayer = AdornerLayer.GetAdornerLayer(AdornedElement);
if (AdornerLayer != null)
{
AdornerLayer.Add(this);
mIsDettached = false;
}
}

/// <summary>
/// Dettach the adorner from the element's adorner layer
/// </summary>
public void Dettach()
{
AdornerLayer = AdornerLayer ?? AdornerLayer.GetAdornerLayer(AdornedElement);
if (AdornerLayer != null)
{
AdornerLayer.Remove(this);
mIsDettached = true;
}
}

#endregion
}