and has 0 comments
The fifth book in the Dexter Morgan series by Jeff Lindsay, Dexter is Delicious is slightly better written than the first four, but also less credible. The main character is torn between his Dark Passanger and the desire to love and protect his newly born child. He thus decides to "become human" in the worst possible moment. His brother Brian, who attempted to kill Dexter's adoption sister Deborah, also makes an appearance. The bad guys in the story are a cannibal ring and they are quite the gourmet, requiring Dexter as a main course.

The problem with this book, apart from the general Dexter Morgan hard to swallow leaps of faith, is that the Dark Passenger is pushed back, as Dexter gets in tough with his parental instincts. For me, at least, Dark-Dexter was the main character and the mischievous whispers of his inner demon were the delight of the series. If I would want to know people having kids and loving their pinkness I would read something else entirely.

I will continue to follow the series, but I can't help feeling a little dissappointed every time I read one of the books in the series. With such a wonderful subject, the possibilities are limitless and a great deal of potential wasted.

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.

I restarted my computer and afterwards I could not access any of the local sites via IIS. The error message in the Application logs of the EventViewer was
Event Type: Error
Event Source: ASP.NET 4.0.30319.0
Description:
aspnet_wp.exe could not be started. The error code for the failure is C0000142. This error can be caused when the worker process account has insufficient rights to read the .NET Framework files. Please ensure that the .NET Framework is correctly installed and that the ACLs on the installation directory allow access to the configured account.
I did the classic
iisreset /stop
%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -i
iisreset /start
to no avail. I was about to curse and restart the computer again when I found this pretty little link: IIS doesn't start. Error code: C0000142. A solution is at the bottom, as the least voted answer: Go to Task Manager, kill explorer.exe, Run another explorer.exe. This starts IIS (aspnet_wp.exe under inetinfo.exe) correctly.

Update: It bugged me that I had to kill explorer.exe. First of all it is a manual solution, then it always messed with my system tray icons. So I searched a little more. Short story shorter, you need to edit machine.conf and replace <processModel autoConfig="true" /> with <processModel userName="system" password="AutoGenerate" />. That effectively makes ASP.Net work under the System account, not the default machine. It does indicate the issue is permission related, but I don't get exactly where and why it should work if I restart explorer.exe. As long as you don't mind running ASP.Net under the System account, this solution seems to solve it. Here is the long version.

Note: you can find the machine.config file in %windir%\Microsoft.NET\Framework\[framework version]\Config\machine.config.

I personally think that the IE8 developer tools are better than Firebug, but let's face it: Firebug was first. Besides, Firebug has also a completely javascript version called Firebug lite that you can inject into any page. Well, you might say, as a developer it is a nice tool, but how can I, the Internet surfer, use this in any page? And the answer is: the favorites links!

It all started from this brilliant post: Bookmark to inject FireBug Light into Internet Explorer. that showed how you can create a specific URL file, add it to the Favorites folder of your Windows user and then use it on any page. Elegant it may be, but it's lazy. It only works on pages that have loaded jQuery. So I did the version that works with simple javascript.

Then I realized that, since I like the Internet Explorer tools better, this is useless for me. How cool would it be to have Firebug lite on Chrome, which has yet to provide a decent developer tool. And it's even easier! Here is how you do it.

For Internet Explorer, follow the steps described in the ElegantCode post but use generic javascript: create a file called Firebug.url containing
[DOC_FirebugUI] 
ORIGURL=about:blank
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=javascript:var script=document.createElement('script'); script.type='text/javascript'; script.src='https://getfirebug.com/firebug-lite.js';document.getElementsByTagName('body')[0].appendChild(script); void(0);
IDList=
IconFile=http://getfirebug.com/img/favicon.ico
IconIndex=1
then save it in the user's c:\Documents and Settings\{UserName}\Favorites folder.

For Chrome, you only right click on the bookmarks bar, choose Add Page, then enter the url in the file above:
javascript:var script=document.createElement('script'); script.type='text/javascript'; script.src='https://getfirebug.com/firebug-lite.js';document.getElementsByTagName('body')[0].appendChild(script); void(0);

And that is it. Click on the link in any of the said browsers and a small icon will appear in the bottom-right corner. Click on it and voila: Firebug! Of course, one can install the Firebug extension, which is actually also a javascript link, albeit really weird, but I think this is more clear and user friendly.

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
}



Pete Postlethwaite is dead. This has hit me hard and it is difficult to describe why. He has played in so many movies that I loved, but I also loved his acting and manner. Now, at only 64, he died peacefully after a lengthy illness. How can anyone die peacefully of cancer is beyond me. This disease is just ridiculous, somebody get rid of it already!

Anyway, Mr. Postlethwaite was a great actor and I will personally miss him.

I've remembered this song when reading a review of the third movie in the Lost Boys franchise and watching its trailer. Really, you should watch the first one. The others two are a probably a completely different thing. I haven't watched them, yet. The remade version of the song in the trailer immediately rekindled some of the feelings I had when watching as a kid the atmospheric original film; this is proof of its value, I believe. Also, many artists have covered the song in different and interesting ways, listed below.

I will not get into the whole "Poor Corey Haim" thing, I didn't really have much love for the guy, but in Lost Boys he was cool. Here is the song, with a fan made video:


Some nice covers from the tube:
by Ashford Twins
by Blutengel
by Nikki McKibbin
by Carfax Abbey
by Ventana

Enjoy.

and has 0 comments

I've just seen the last episode of the first season of Caprica, the series offshooting from Battlestar Galactica. There will be no second season, as the show has been cancelled. Why is that?

Let's start with something other than pure financial interests (oh, you TV network Guatrau!) and discuss the effort that was put in the series. You have a very successful and innovative series like Battlestar Galactica, creating an entire universe with its technology and religions and cultures, and then you go further and create a new series that actually reproduces the lives of people on those worlds. You get cultural criminal organisations, religious fanatics, technologists, robots, AI, virtual worlds, space travel, fashion, music, everything! This is the hardest part of any story: the setup. So you get the setup done and then you... stop writing the story because of low viewer turnout? Are you stupid?! Just tell it in a way that will please your stupid audience and also continue the effort, or can't your little brain get around that?

Then it is about the actor effort. God(s), I hated Clarice Willow and you know why? Because Polly Walker did a great job playing that character, down to the microexpressions and little scheming eye movements. Eric Stoltz, Esai Morales, even the teenagers and kids played well, creating really complex likeable or hateable characters. The creator, Ronald D. Moore, which I totally hate for ruining the end seasons of Battlestar Galactica, also did his best and I can see that it is a great show. And you are going to piss on that? The success of any project lies in the motivation to do it. All these people were motivated and you, money grabbing assholes, pissed in their faces. Shame doesn't begin to cover it. I don't want to shame you, I want you to die a horrible death, you soulless vampires!

And then there is the audience, your precious little numbers. Do you guys know why your network is called SyFy for? I will tell you, so you can say "oh!" with your carefully arranged heads; I guess this is coming as a surprise: it comes from the old name of SciFi, which in turn comes from science fiction. Now you fuckers get what your audience is? Or did you rename the channel only because you have no idea what it was about anyway? Kudos for HBO for raising the standards cause you are just letting them drop in the gutter.

So, in conclusion: Fuck you, SyFy Channel and all your executives, and as you are doing everything possible to stiffle creativity, I wish you a very creative and painful death!

and has 2 comments
It is time for another exhaustive list of TV series I have been watching. Some are great, some are horrible, but the moral of the story is I just can't stop :) Here it goes:
  • Caprica - A spin-off from Battlestar Galactica, it showed a lot of promise, tackling the culture of the twelve colonies, issues like emergent AI and virtual life. However, it did not appeal to the public so it was cancelled. I am yet to see the last episodes from the series, but I expect the quality of the show to have plummeted long before the official news of the cancellation. When a network exec puts limits like "get me audience or die" people just lose interest in doing something and it quickly becomes a self-fulfilling prophecy.
  • Doctor Who - one wacky adventure after another, I still watch this British series. What it lacks in budget it compensates with weird plot lines and original writing. Quite refreshing.
  • Eureka - a silly sci-fi comedy, I would have expected it to die after a few seasons. Alas, people like easy, silly, pointless shows and only resent the ones that makes them think. Season 4 is expected to resume in July 2011.
  • House MD - I am kind of stuck watching this less and less medical series, because my wife likes it. I am bored by the plot, characters and almost everything in it except the occasional interesting medical fact. I hear season 8 might be the last.
  • Criminal Minds - some episodes are pretty stupid, others are brilliant. The exposure of the minds of serial killers through behavioural analysis is a great subject. Alas, they put too much focus on the procedure and too little on the actual principles behind the work of the FBI unit. Don't fret, though, a spin-off with Forest Whitaker as the lead of another crime fighting group. Unfortunately, the joint episode from Criminal Minds that shouls have presented the new characters was weak and the new team pathetic.
  • Southpark - this animation comedy series has its bad moments, but usually it is exceptionally funny and making fun of recent events.
  • Dexter - the show keeps holding strong, even if they kind of drifted from the perfect quality of the first seasons. I hear season 6 might be last, even if the fourth book in the Dexter series, Dexter is Delicious, is now available. Lucky for the TV series, they only got inspiration from the books which were not of such good quality as the show.
  • Big Love - interesting story about a mormon family trying to maintain their plurimarital beliefs in the face of adversity from goverment and other mormons alike. The 5th season is to start soon, but it is also the last. It kind of went bad from the third one, anyway.
  • Fringe - I am yet to watch the episodes from season 3. It is a pretty dumb show, so people like it. I am waiting for a period in which I have nothing to do in order to watch it.
  • True Blood - I like True Blood! It's not the vampires, but the feel of the backwater town that is plagued by all kinds of supernatural creatures. I think the show did great, but lately it kind of stuttered. Season 4 is to start somewhere in June
  • Californication - luckily, father Christmas brought us two preair episodes from season 4 which should have started next year. I still like the show, but it is a far cry from the greatness of the first season, during which I wanted to make a son and name him David Duchovny.
  • Breaking Bad - is it good anymore? The show started great and I did watch it religiously, but it does seem to get less and less interesting. It's a crystal meth male version of Weeds.
  • Secret Diary of a Call Girl - Billie Piper could not have been more perfect for this series. She was delicious from the first time I saw her in that silly video clip of hers. The show was sexy, interesting, and will continue with a fourth season, which is said to be last. Why, God, why?!
  • Entourage - this series is another television gem. It features the Hollywood adventures of a talented actor and his close childhood friends. The show managed to maintain a consistent positive feel for five or six seasons, which made it both great and original in this world of TV drama. The last seasons, though, went for a dark weird vibe and the eigth season will be both short and the last. A feature film is in the works, maybe, but it doesn't matter, since the original feel is pretty much destroyed.
  • Stargate Universe - Yeah, finally a Stargate show that takes itself seriously! Or so I thought. When the audience didn't like the dark and gritty atmosphere, the black wind of show cancellation made everybody not give a damn. The result is a half baked show, troubled by financing and screenwriting issues. Poor Robert Carlyle did a marvelous job, but a single good Scottish actor can't save a show from its evil masters. The second season of Stargate Universe will also be the last.
  • Torchwood - A Doctor Who spin-off, it took a big break after an attempted publicity stunt. Season 4 is to start next year. Fun series, but when you take Doctor Who, you Americanize it and then you make it even sillier, you are bound to miss somewhere.
  • The Sarah Jane Adventures - another Doctor Who spin-off, directed almost exclusively towards young kids. Of course, I watch it and enjoy it very much.
  • V - the original miniseries was not great, but that is no reason to make a stupid show like this. It is about aliens invading Earth via subterfuge and manipulation and the human resistance. It quickly turned into a involuntary parody of World War II movies with dumb Germans and smart Allies.
  • Men Of A Certain Age - suprisingly good and serious, it is about three middle aged guys and childhood friends living their lives. It is funny, but deep, with characters that feel real and jokes that really make you think and smile. Way to go, Ray Romano! Season 2 just started.
  • Weeds - the show just ended its sisth season. The seventh should be its last. Not even the babeliciousness of Mary-Louise Parker could save the last season, which was boring and kind of pointless. Started so well, though.
  • The Good Wife - it is a lawyer show, mostly directed towards women, but I like it. Characters are complex enough, the law cases feel real and the plot is interesting.
  • The Walking Dead - woohoo! Zombie series! Also made after comic books, so they can't fail too much. I like it, but since it focuses on the personal drama of the survivors and not the survival itself, and since the zombies are slow and ridiculous... meh! :)
  • Shattered - Canadian show starring Callum Keith Rennie, which you may know from Battlestar Galactica, it is about a cop with split personality disorder. Not very realistic, with a 70's feel to it, even if it is supposed to take place in the present, but I watch it nonetheless. I wonder if there will be a second season to it.
  • Haven - supposedly based on a Stephen King short story, it is basically a mashup between Fringe and Twin Peaks. It's worse than both, but it is easy to watch when you shut your brain down.
  • Rubicon - The wife watches this, I can't. It is like somebody accidentally dropped a bit of Lost in Nikita, but also removed the hot chicks.
  • Royal Pains - an easy medical slightly-comedy show. Started funny, now it's just boring. I will tell you when it's over.
  • Identity - British police drama that had some potential. The Brits cancelled it after it's first season, but the ABC network is said to want to make their own series.
  • Lost Girl - Canadian show again, this time a sort of supernatural thing with a hot bisexual chick that is also a succubus as the lead. Buffy like, nothing serious, but at least it's sexy.
  • Nikita - Nikita is now an American-Asian, still bad-ass and with Michael wrapped around her little finger. Pointless show, really.
  • No Ordinary Family - a family of super heroes! What could be cooler? I stopped watching it after the pilot episode.
  • Better with You - my attempt to watch something really easy with the girls, a show with background laughter and stuff, it's about three couples of different ages and their developped manierisms. Instead of actually analysing the causes and finding solutions, though, they just focus on the inevitability that all comedy American couples look and sound the same in their age group. Yuck!
  • Pioneer One - this is a show that is created by an independent studio (read: two guys in a garrage), freely distributed via Bittorrent (legally) and financed through donations. For 20000$ an episode, it is pretty cool. I donated some money since I really want this to work. Don't expect a master-piece, but I personally enjoy it and await the release of the third episode.


Phew, that's about all. But there are also the shows that I intend to watch! :) Here is the list:
  • Terra Nova - a show that is supposed to start in the fall of 2011. The synposis sounds kind of ridiculous, but hey, it's sci-fi!
  • Tilda - an HBO comedy about two blogger women journalists: Diane Keaton and Ellen Page. Both are annoying, but good actresses, and HBO does good shows. Let's see how it goes.
  • Criminal Minds: Suspect Behavior - I mentioned this show as the spin-off from Criminal Minds. I don't hold high hopes for it, though, based on the episode that presented the new team.
  • A Game of Thrones - I've read the books and they were great! I predict the show will be epic, since the books themselves were detailed, complex, with great story and a bit of fantasy as well. I can't wait for the show to start.
  • Falling Skies - aliens are attacking, again. I wonder if they started this show to finally bury V, which sucks. However, how much better can another show be when the plot is that an advanced technological race comes to Earth to occupy it. I mean, this dump?!


Ok, now it's over... or should I mention the anime series I am watching as well... how about the web series? Hmm... :)

and has 0 comments
I've noticed a nice feature on news sites: they take important quotes from their articles and highlight them in special boxes in their articles. Helps with the skimming of an article when you don't have the time to read it. I've added the same feature to my blog and I would like to know if you, my readers, find it useful as well.

and has 0 comments
There are visionaries today that are capable of describing the future, as they see it. If it is close to the actual future, they get to be called futurologists. Of course, one will jump up and say that futurology has a definition and it is an art or a science that has nothing to do with vision, but I say that this is exactly what it is: guesswork. Guessing can be facilitated, however, by studying trends, staying current with new technology and thinking ahead on the needs that people have and will have in the future.

So how come no one is really good at it? How come people said in the past that by now we would get to Mars and have free energy and the likes? The reason is simple: because we can, but we won't! Just like people walking on the street and witnessing a robbery or a beating just stay and watch, but don't act, we are a world of diffuse responsibility. Nobody is responsible, everybody is to blame. But it's not true. I am responsibile, and you are; we make the future, we are the people, we are the ones that DO anything and everything.

So what is the error of futurology: they assume we would do what we can, when in truth we only do what we care. My New Year's resolution is to care, see where it takes me.

and has 0 comments
I will start with the errors. I was trying to access a site using a simple WebRequest.Create(url) method and a System.Configuration.ConfigurationErrorsException was thrown, with the message Error creating the Web Proxy specified in the 'system.net/defaultProxy' configuration section. That was weird, since I was doing it all from a WPF application and I had never had to modify the configuration for it to work. The exception had an even crazier inner exception: System.Runtime.InteropServices.SEHException External component has thrown an exception. Google failed to provide a satisfactory answer to any of the errors, although there were quite a few people having the same problem.

I proceeded in creating a system.net/defaultProxy section in the app.config. I changed the True values of the proxy element to False:

<system.net>
<defaultProxy>
<proxy
usesystemdefault = "False"
bypassonlocal = "False"
/>
</defaultProxy>
</system.net>


Voila! No more errors in Create... exceptions would be thrownm however, by the GetResponse() method later on. This time no configuration exception, only the weird SEHException with the oh so helpful ErrorCode -2147467259 (0x80004005) which means "Unspecified Error".

I tried different stuff like resetting IIS, trying to decompile .Net assemblies and see where the error comes from (all to no avail since the error comes from a native Windows component. In my desperation I issued a "netsh winsock reset" in the command line and then restarted the computer. Frankly, I don't know if the command did it or just the restart. The fact is, it just worked afterwards.

So, here is the first exception:
System.Configuration.ConfigurationErrorsException occurred
Message=Error creating the Web Proxy specified in the 'system.net/defaultProxy' configuration section.
Source=System
BareMessage=Error creating the Web Proxy specified in the 'system.net/defaultProxy' configuration section.
Line=0
StackTrace:
at System.Net.Configuration.DefaultProxySectionInternal.GetSection()
at System.Net.WebRequest.get_InternalDefaultWebProxy()
at System.Net.HttpWebRequest..ctor(Uri uri, ServicePoint servicePoint)
at System.Net.HttpRequestCreator.Create(Uri Uri)
at System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase)
at System.Net.WebRequest.Create(String requestUriString)
InnerException: System.Runtime.InteropServices.SEHException
Message=External component has thrown an exception.
Source=System
ErrorCode=-2147467259 (0x80004005)
StackTrace:
at System.Net.UnsafeNclNativeMethods.OSSOCK.WSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, IntPtr protocolInfo, UInt32 group, SocketConstructorFlags flags)
at System.Net.Sockets.Socket.InitializeSockets()
at System.Net.NetworkAddressChangePolled..ctor()
at System.Net.AutoWebProxyScriptEngine.AutoDetector.Initialize()
at System.Net.AutoWebProxyScriptEngine.AutoDetector.get_CurrentAutoDetector()
at System.Net.AutoWebProxyScriptEngine..ctor(WebProxy proxy, Boolean useRegistry)
at System.Net.WebProxy.UnsafeUpdateFromRegistry()
at System.Net.WebProxy..ctor(Boolean enableAutoproxy)
and here is the second:
System.Runtime.InteropServices.SEHException occurred
Message=External component has thrown an exception.
Source=System
ErrorCode=-2147467259
StackTrace:
at System.Net.UnsafeNclNativeMethods.OSSOCK.WSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, IntPtr protocolInfo, UInt32 group, SocketConstructorFlags flags)
at System.Net.Sockets.Socket.InitializeSockets()
at System.Net.IPAddress.InternalParse(String ipString, Boolean tryParse)
at System.Net.NetworkInformation.IpAddrString.ToIPAddressCollection()
at System.Net.NetworkInformation.SystemIPGlobalProperties.GetFixedInfo()
at System.Net.NetworkInformation.SystemIPGlobalProperties.get_FixedInfo()
at System.Net.NetworkInformation.SystemIPGlobalProperties.get_HostName()
at System.Net.NclUtilities.GuessWhetherHostIsLoopback(String host)
at System.Net.ServicePoint.get_ConnectionLimit()
at System.Net.ConnectionGroup..ctor(ServicePoint servicePoint, String connName)
at System.Net.ServicePoint.FindConnectionGroup(String connName, Boolean dontCreate)
at System.Net.ServicePoint.SubmitRequest(HttpWebRequest request, String connName)
at System.Net.HttpWebRequest.SubmitRequest(ServicePoint servicePoint)
at System.Net.HttpWebRequest.GetResponse()
.

The solution? Restart the computer. I wish I had a better, more informed answer, on why this happened, but I do not. I welcome any further explanation on the issue and I hope this helps people not waste a few hours like I did.

I've just finished watching episode two from the first season of Pioneer One, a sci-fi show made by amateurs, financed by donations and freely downloadable via Bittorrent. That is just fabulous! An episode is done with 20000$ and they need about 40000$ more to finish the last two episodes of the series.

I thought of this kind of system myself a year or so ago as I was observing that almost all movies and shows I watch are made by Americans, through gigantic media outlets that are only interested in profits and cancel any good show on the basis of money alone. I was wondering: where are the people that would be to TV what bloggers are to printed press? Of course, writing an article in a free public place like Blogger is a lot simpler than making a movie, but the idea is there. Mangakus do it all the time, in the US the comic book is back, why not TV shows?

The series is really good for the money that went into it. Except for some clueless actors that play very small parts, the people involved act decently and the atmosphere of the show is powerful and enticing. The dialogue is also strangely good, as I am used to clichees being sprouted in scenes of a certain type and when that doesn't happen, I have an eery feeling of unreality!

Pioneer One is not the only show like this. There is a network, called Vodo, with the motto: We love free! that helps distribute a lot of these Creative Commons licenced films and shows. I really want this to work. This gets the money from people interested to watch and gives it to the creators, rather than some vampire distribution network.

On that note, I would like to also talk about another TV show that is about to appear, called S.T.A.L.K.E.R. Yes, indeed, it is a TV series inspired by the game with the same name, which in turn was inspired by Roadside Picnic, by the Strugatsky brothers. The show is made by the Ukranian company that made the game and you can follow the progress of the series by going to its official site. The S.T.A.L.K.E.R. show would not be freely released, but at least it is not part of the official channels for TV distribution. The story itself sounds cool and the S.T.A.L.K.E.R. universe counts about 40 books already (in Russian, unfortunately, but give it time).

It moves slowly, but surely. I am convinced that in a few years people will make and distribute work via the Internet, directly sponsored by the people interested in their creation. All the salesmen in the middle will just be bypassed and creators will be controlling the cultural market rather than distributors. It only feels natural: if you distribute something under a Creative Commons licence, there can be no piracy :) So there, what I've always said comes true: the death of piracy is synonimous with the death of mammoth distribution companies and all their bullshit.

and has 2 comments
Here is the link for the article, written by Brian Hayes, who argues that programmers should rather communicate peacefully, rather than fight each other over the language they are using. In the end it didn't really reveal anything grandieuse, but his post was detailed and funny and nice to read.

Update: I've thought about the article and I feel I have to add to this post.

First of all, I have to admit, as the author of the initial article admited that he is a Lisp fan, that I like the C-like structure of programs (minus the pointers :D). Actually, I would go so far as to occasionally dream of building an application which would convert Python and F# and Lisp and all those wacky languages into a semicolon/curly bracket version that I could use, then convert it back to their normal format before compilation or use. I agree with the author that the syntax itself is not very relevant to the language, but it is relevant to the users. I can "read" C#-like code much easier because by now I am fluent in C#. I believe that a nice option is to have the kind of functionality I am describing: something that would not change the language, but would slightly change the syntax so that someone can read it more easily.

Second of all, I am amazed that something that started as a nice introduction to an idea would continue with an admission (of guilt >:) ) that the author likes Lisp and then abruptly end. He didn't mention anything about the .Net idea which tries to unify a lot of programmaing languages under an intermediate compiler language. This brings the great opportunity to use a library written in a language with an application written in another. If that is not a good idea, I don't know what is!

Programming Collective Intelligence is easy to read, small but concise, and its only major flaw is the title; and that is because it is misleading. The book touches quite heavily on using collective information and social site APIs, but what it is really about is data mining. It may not be a flaw with the majority of readers, but personally I wouldn't care about the collective, the Facebook API or anything like that, but I was really interested in the different ways to analyse data. In that sense, this book can be taken as a reference guide on data mining.

Each algorithm and idea is accompanied by Python sources. I personally dislike Python as a language, but the author afirms he chose it intentionally because the algorithms look clear and the source is small, with its purpose unhindred by many language artefacts. The book was so interesting, though, that I plan (if I ever find the time :( ) to take all the examples and do them in C#, then place them on Github.

The book covers classification and feature extraction, supervised and unsupervised algorithms, filtering and discovery and it also has exercises at the end of each chapter. Here is a short list:
  • Making Recommendations - about the way one can use data from user preferences in order to create recommendations. Distance metrics and finding similar items to the ones we like or people with similar tastes.
  • Discovering Groups - about classifying data into different groups. Supervised and unsupervised methods are described, hierarchical clustering, dendograms, column clustering, K-Means clustering and diferent methods of visualisation.
  • Searching and Ranking - it basically explains step by step how to make a search engine. Word frequency, word distance, location of a document, counting methods, artifical neural networks, the Google PageRank algorithm, extraction of information from link text, and learning from user clicks can be found in this chapter.
  • Optimization - simulated annealing, hill climbing, genetic algorithms are described and exampled here. The chapter talks about optimizing problems like travel schedules and the example uses data from Kayak.
  • Document Filtering - a chapter about filtering documents based on preferences or getting rid of spam. You can find here Bayesian filtering and the Fisher method.
  • Decision Trees - a very interesting method of splitting information items into groups that have a hierarchical connection between them. The examples use the Zillow API
  • Bulding Price Models - k-Nearest neighbours, weighted neighbours, scaling.
  • Advanced Classification - Kernel Methods and Support Vector Machines. This is a great chapter and it show some pretty cool uses of data mining using the Facebook API
  • Finding Independent Features - reviews Bayesian classification and clustering, then proposes Non-Negative Matrix Factorisation, a method invented circa the late 90s, a powerful algorithm which uses matrix algebra to find features in a data set
  • Evolving Intelligence - bingo! Genetic Programming made easy. Really cool.
  • Algorithm Summary, Third Party Libraries and Mathematical Formulas - if you had any doubts you can use this book as a data mining reference book, the last three chapters eliminate them. An even more concise summary of the methods explained in the book, listing every math formula and obscure library used in the book


Conclusion: I really loved the book and I can hardly wait to take it apart with a computer in hand.