Freitag, 11. Mai 2012

Seting Visibility on a GridViewColum of a ListView in WPF

There are two different ways how the Visibility of a GridViewColumn can be set.

1. With attached properties
2. Extending the GridViewColumn

In the attached property version, we save the original width of the column in another attached property, whenever the visibility is set to something else than Visible. After that we set the Width to 0.
This way the column disappears.

When resetting the Visibility to visible, we retrieve the original saved width and restore it to the Width property again.

public class GridViewColumnVisibilityManager
{
    public static Visibility GetVisibility(DependencyObject o)
    {
        return (Visibility)o.GetValue(VisibilityProperty);
    }

    public static void SetVisibility(DependencyObject obj, Visibility value)
    {
        obj.SetValue(VisibilityProperty, value);
    }

    public static readonly DependencyProperty VisibilityProperty =
        DependencyProperty.RegisterAttached("Visibility", typeof(Visibility),
        typeof(GridViewColumnVisibilityManager),
        new FrameworkPropertyMetadata(Visibility.Visible, 
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        new PropertyChangedCallback(OnVisibilityPropertyChanged)));

    private static void OnVisibilityPropertyChanged(DependencyObject d, 
                                     DependencyPropertyChangedEventArgs e)
    {
        var column = d as GridViewColumn;
        if (column != null)
        {
            var visibility = GetVisibility(column);
            if (visibility == Visibility.Visible)
            {
                // set the with back to the original
                column.Width = GetVisibleWidth(column);
            }
            else
            {
                // store the original width
                SetVisibleWidth(column, column.Width);
                // set the column width to 0 to hide it
                column.Width = 0.0;
            }
        }
    }

    public static double GetVisibleWidth(DependencyObject obj)
    {
        return (double)obj.GetValue(VisibleWidthProperty);
    }

    public static void SetVisibleWidth(DependencyObject obj, double value)
    {
        obj.SetValue(VisibleWidthProperty, value);
    }

    /// <summary>
    /// dpenendency property that stores the last visible width
    /// whenever the visibility changes this propert is used to set or get the width
    /// </summary>
    public static readonly DependencyProperty VisibleWidthProperty =
        DependencyProperty.RegisterAttached("VisibleWidth", 
                typeof(double), 
                typeof(GridViewColumnVisibilityManager), 
                new UIPropertyMetadata(double.NaN));

}

<ListView ItemsSource="{Binding DataObjects}" Grid.Column="1" >
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" 
                     foo:GridViewColumnVisibilityManager.Visibility="{Binding IsVisible, Converter={StaticResource boolToVis}}"/>
                <GridViewColumn Header="Vorname" DisplayMemberBinding="{Binding Vorname}"/>
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>


The extension works the same way except that we can use a variable to store the original width instead of an attached property.

public class GridViewColumnExt : GridViewColumn
{
    public Visibility Visibility
    {
        get
        {
            return (Visibility)GetValue(VisibilityProperty);
        }
        set
        {
            SetValue(VisibilityProperty, value);
        }
    }

    public static readonly DependencyProperty VisibilityProperty =
        DependencyProperty.Register("Visibility", typeof(Visibility), 
        typeof(GridViewColumnExt),
        new FrameworkPropertyMetadata(Visibility.Visible, 
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        new PropertyChangedCallback(OnVisibilityPropertyChanged)));

    private static void OnVisibilityPropertyChanged(DependencyObject d, 
                                  DependencyPropertyChangedEventArgs e)
    {
        var column = d as GridViewColumnExt;
        if (column != null)
        {
            column.OnVisibilityChanged((Visibility)e.NewValue);
        }
    }

    private void OnVisibilityChanged(Visibility visibility)
    {
        if (visibility == Visibility.Visible)
        {
            Width = _visibleWidth;
        }
        else
        {
            _visibleWidth = Width;
            Width = 0.0;
        }
    }

    double _visibleWidth;
}

<ListView ItemsSource="{Binding DataObjects}" Grid.Column="1" >
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <c:GridViewColumnExt Header="Name" DisplayMemberBinding="{Binding Name}" 
                     Visibility="{Binding IsVisible, Converter={StaticResource boolToVis}}"/>
                <GridViewColumn Header="Vorname" DisplayMemberBinding="{Binding Vorname}"/>
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>

Donnerstag, 12. April 2012

Binding multiple ComboBoxes to the same collection and using Filters

When multiple ComboBoxes bind to the same collection and the collection uses a Filtering, the items of all ComboBoxes get filtered. Not as expected only the one using the filter. If a ComboBox already has a value selected and another ComboBox uses a filter on the collection, the first ComboBox could lose its value because the SelectedItem is no longer contained in the displayed list.

This hapens because in WPF all Collections contain a default ICollectionView. This view can be retrieved with:

var view = CollectionViewSource.GetDefaultView(collection);


This can easily be handled if each ComboBox binds to a unique ICollectionView. It doesn't matter if the underlying Collection is the same as long as the ICollectionViews differ.


IList<ComboBoxExtDataObject> _dataObjects;
public IList<ComboBoxExtDataObject> DataObjects
{
    get
    {
        if (_dataObjects == null)
        {
            _dataObjects = new ObservableCollection<ComboBoxExtDataObject>();

            for (int i = 1; i <= 50; i++)
                _dataObjects.Add(new ComboBoxExtDataObject { Id = i, Name = "Name" + i });
        }
        return _dataObjects;
    }
}

ICollectionView _sources1;
public ICollectionView Sources1
{
    get
    {
        if (_sources1 == null)
        {
            var lst = new CollectionViewSource();
            lst.Source = _dataObjects;
            _sources1 = lst.View;
        }
        return _sources1;
    }
}

ICollectionView _sources2;
public ICollectionView Sources2
{
    get
    {
        if (_sources2 == null)
        {
            var lst = new CollectionViewSource();
            lst.Source = _dataObjects;
            _sources2 = lst.View;
        }
        return _sources2;
    }
}

In this case I bind the ComboBox1 to Sources1 and the ComboBox2 to Sources2. Now I can easily use the Filtering that I added to my ComboBox without changing the CollectionView of the other ComboBox.

Filering in ComboBoxes

To achieve filtering in a ComboBox I simply extended the ComboBox.

If I want to Filter the items in the DropDown list I simply bind to the FilterString property.
This example can even handle wildcards.

public class ComboBoxExt : ComboBox
{

#region Filter

#region Implementation

IList<object> _displayedItems;

/// <summary>
/// refreshes the filtering of the combobox according to the string in
/// <see cref="FilterString"/>
/// </summary>
private void RefreshFilter()
{
    var source = ItemsSource as ICollectionView;
    if (source == null)
        source = Items as ICollectionView;
            
    if (source != null)
    {
        if (_displayedItems == null)
            _displayedItems = new ObservableCollection<object>();
        _displayedItems.Clear();

        source.Filter = new Predicate<object>(Filter);

        if (_displayedItems.Count > 0)
        {
            var focusedElement = Keyboard.FocusedElement;

            SelectedItem = _displayedItems[0];

            if (focusedElement != null)
                focusedElement.Focus();
        }
    }
}

/// <summary>
/// method that gets called by the predicate in the ICollectionView.Filter that
/// filters the entries in the dropdown
/// according to the string in <see cref="FilterString"/>
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
private bool Filter(object obj)
{
    // no filter is set
    if (string.IsNullOrEmpty(FilterString))
        return true;

    // no filterpath is set
    if (string.IsNullOrEmpty(FilterMemberPath))
        return true;

    // get the value from the property out of the bound object
    var value = GetValueFromBindingPath(obj, FilterMemberPath);
    if (value == null)
        return false;

    //
    // matching filterstring and value using regex found on:
    // http://www.codeproject.com/Articles/11556/Converting-Wildcards-to-Regexes
    //

    // accept sql and dos Wildcards
    // convert all sql wildcards to dos wildcards
    var filter = FilterString.Replace("%", "*").Replace("_", "?");

    // convert all wildcards to regex wildcards and add a * to search all prepending chars
    filter = "^" + Regex.Escape(filter).Replace("\\*", ".*").Replace("\\?", ".") + ".*$";
            
    // match the value with the regex filter
    bool isFiltered = Regex.IsMatch(value.ToString(), filter, RegexOptions.IgnoreCase);
            
    if (isFiltered)
        _displayedItems.Add(obj);

    return isFiltered;
}

#endregion

#region DependcyProperties

#region FilterMemberPath

//
// the filtermemeberpath is used to get the property that the filter should be used on
// 

/// <summary>
/// gets or set the object path to the property that is filtered on the bound object
/// </summary>
public string FilterMemberPath
{
    get
    {
        return (string)GetValue(FilterMemberPathProperty);
    }
    set
    {
        SetValue(FilterMemberPathProperty, value);
    }
}

/// <summary>
/// the dependencyproperty for the <see cref="FilterMemberPath"/> property
/// </summary>
public static readonly DependencyProperty FilterMemberPathProperty =
    DependencyProperty.Register("FilterMemberPath", typeof(string), typeof(ComboBoxExt), 
      new FrameworkPropertyMetadata(null, 
           new PropertyChangedCallback(OnFilterMemberPathPropertyChanged)));

private static void OnFilterMemberPathPropertyChanged(DependencyObject sender, 
                                        DependencyPropertyChangedEventArgs args)
{
}

#endregion

#region FilterString

/// <summary>
/// gets or sets the string that is used for filtering the combobox
/// </summary>
public string FilterString
{
    get
    {
        return (string)GetValue(FilterStringProperty);
    }
    set
    {
        SetValue(FilterStringProperty, value);
    }
}
        
/// <summary>
/// dependencyproperty for the <see cref="FilterString"/> property
/// </summary>
public static readonly DependencyProperty FilterStringProperty =
    DependencyProperty.Register(
    "FilterString", 
    typeof(string), 
    typeof(ComboBoxExt), 
    new FrameworkPropertyMetadata(
        null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | 
              FrameworkPropertyMetadataOptions.AffectsRender | 
              FrameworkPropertyMetadataOptions.AffectsParentMeasure,
        new PropertyChangedCallback(OnFilterStringPropertyChanged)));


private static void OnFilterStringPropertyChanged(DependencyObject sender, 
                                    DependencyPropertyChangedEventArgs args)
{
    var dt = sender as ComboBoxExt;
    if (dt == null)
        return;
            
    dt.RefreshFilter();
}

#endregion
        
#endregion

#endregion

#region Value from Binding / Path

// 
// we create a virtual binding and bind to the property from the
// path that was set in the FiltermemberPath property
// with the binding we can easily retreave the object that is
// contained behind the property
//
// tests with over 5000 items have shown 
// that this has no impact on performance
//

/// <summary>
/// gets the object/value from a property from the object according to the path
/// </summary>
/// <param name="obj"></param>
/// <param name="propertyPath"></param>
/// <returns></returns>
public static object GetValueFromBindingPath(object obj, string propertyPath)
{
    Binding binding = new Binding(propertyPath);
    binding.Mode = BindingMode.OneTime;
    binding.Source = obj;
    BindingOperations.SetBinding(_dummy, Dummy.ValueProperty, binding);
    return _dummy.GetValue(Dummy.ValueProperty);
}

// dummy object for getting the value from a path on a object
private static readonly Dummy _dummy = new Dummy();

private class Dummy : DependencyObject
{
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(object), typeof(Dummy), 
                                             new UIPropertyMetadata(null));
}

#endregion
}

Retrieving the value of a property from a DataBound object

In WPF it's easy to bind a object to a DependencyProperty and can be accessed just like any normal Property. You can even access the Properties of that object and get the values of these if you know what type they are.
But what is if the Binding is of a random type and you would like to access the value of a property on that unknown?

Let's say for example you want to add a Filtering to the ComboBox.
ComboBoxes can bind to any type as long as it implements IEnumerable. But for Filtering you need to know the value of a Property inside the objects in the IEnumerable.

To access the value of a Property on the Bound objects, you need to create a new Binding on the desired Property for each of the objects in the IEnumerable. The thing you need to tell the ComboBox is the name of the Property of which you would like to get the value of. In the example I simply created a DependencyProperty containing the name(path). You could also use the DisplayMemberPath or analyse the Template of the Bound objects.

public bool Filter(object obj)
{
    // get the value from the property out of the bound object
    var value = GetValueFromBindingPath(obj, FilterMemberPath);
    if(value != null)
    {
        if(value.ToString().Contains(FilterString))
           return true;
    }
    return false;
}

/// <summary>
/// the name of the property that the filtering should be made on in the bound objects
/// </summary>
public string FilterMemberPath
{
    get { return (string)GetValue(FilterMemberPathProperty); }
    set { SetValue(FilterMemberPathProperty, value); }
}

public static readonly DependencyProperty FilterMemberPathProperty =
    DependencyProperty.Register("FilterMemberPath", typeof(string), typeof(ComboBoxExt), 
                                new UIPropertyMetadata(null));

#region Value from Binding / Path

// 
// we create a virtual binding and bind to the property from the
// path that was set in the FiltermemberPath property
// with the binding we can easily retreave the object that is
// contained behind the property
//
// tests with over 5000 items have shown 
// that this has no impact on performance
//

/// <summary>
/// gets the object/value from a property from the object according to the path
/// </summary>
/// <param name="obj"></param>
/// <param name="propertyPath"></param>
/// <returns></returns>
public static object GetValueFromBindingPath(object obj, string propertyPath)
{
    Binding binding = new Binding(propertyPath);
    binding.Mode = BindingMode.OneTime;
    binding.Source = obj;
    BindingOperations.SetBinding(_dummy, Dummy.ValueProperty, binding);
    return _dummy.GetValue(Dummy.ValueProperty);
}

// dummy object for getting the value from a path on a object
private static readonly Dummy _dummy = new Dummy();

private class Dummy : DependencyObject
{
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(object), typeof(Dummy), 
                                    new UIPropertyMetadata(null));
}

#endregion


This looks like a hack and maybe (most probably) it is a big one.
But it works quite well and its quite fast.

Mittwoch, 11. Januar 2012

Simple Drag and Drop Handler using MVVM and Attached Properties

I wanted to implement some Drag & Drop behaviour to my ListBoxes. Because the Drag & Drop is handled through Events I created some Attached Properties that would handle these events and pass the needed information to my ViewModel through binding.

First I created an Interface that I could pass to the Attached Property that contained two Method definitions that would get executed when the DropEvent gets fired.
One method returnes a bool defining if the Drop can be executed.
The second method handles the DropEvent.
    public interface IDragDropHandler
    {
        bool CanDrop(IDataObject dropObject, IEnumerable dropTarget);

        void OnDrop(IDataObject dropObject, IEnumerable dropTarget);
    }

Then I created the DependencyProperty that gets attached. In the PropertyMetadata I created a new object containing the PropertyChangedHandler that gets executed when the dragDropHandlerProperty is changed. Inside the instance I hooked to the DragEvent of the DependencyObject and added a handler that gets executed when the DragEvent gets fired.
    public static class DragDropBehaviour
    {
        #region DragDropHandler

        #region DragDropHandler DependencyProperty

        /// 
        /// attached property that handles drag and drop
        /// 
        public static readonly DependencyProperty DragDropHandlerProperty =
           DependencyProperty.RegisterAttached("DragDropHandler", 
           typeof(IDragDropHandler), 
           typeof(DragDropBehaviour),
           new PropertyMetadata(null, new ExecuteDragDropBehaviour().PropertyChangedHandler));

        public static void SetDragDropHandler(DependencyObject o, object propertyValue)
        {
            o.SetValue(DragDropHandlerProperty, propertyValue);
        }
        public static object GetDragDropHandler(DependencyObject o)
        {
            return o.GetValue(DragDropHandlerProperty);
        }

        #endregion

        internal abstract class DragDropBehaviourBase
        {
            protected DependencyProperty _property;

            /// <summary>
            /// attach the events
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="oldValue"></param>
            /// <param name="newValue"></param>
            protected abstract void AdjustEventHandlers(DependencyObject sender, 
                                                        object oldValue, object newValue);

            /// <summary>
            /// Listens for a change in the DependencyProperty
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            public void PropertyChangedHandler(DependencyObject sender, 
                                               DependencyPropertyChangedEventArgs e)
            {
                if (_property == null)
                {
                    _property = e.Property;
                }

                object oldValue = e.OldValue;
                object newValue = e.NewValue;

                AdjustEventHandlers(sender, oldValue, newValue);
            }
        }

        /// <summary>
        /// an internal class to handle listening for the drop event and executing the dropaction
        /// </summary>
        private class ExecuteDragDropBehaviour : DragDropBehaviourBase
        {
            /// <summary>
            /// attach the events
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="oldValue"></param>
            /// <param name="newValue"></param>
            protected override void AdjustEventHandlers(DependencyObject sender, 
                                                   object oldValue, object newValue)
            {
                var element = sender as UIElement;
                if (element == null) { return; }

                if (oldValue != null)
                {
                    element.RemoveHandler(UIElement.DropEvent, 
                                          new DragEventHandler(ReceiveDrop));
                }

                if (newValue != null)
                {
                    element.AddHandler(UIElement.DropEvent, 
                                       new DragEventHandler(ReceiveDrop));
                }
            }

            /// <summary>
            /// eventhandler that gets executed when the DropEvent fires
            /// </summary>
            private void ReceiveDrop(object sender, DragEventArgs e)
            {
                var dp = sender as DependencyObject;
                if (dp == null)
                    return;

                var action = dp.GetValue(_property) as IDragDropHandler;
                if (action == null)
                    return;

                IEnumerable dropTarget = null;
                if (sender is ItemsControl)
                    dropTarget = (sender as ItemsControl).ItemsSource;

                if (action.CanDrop(e.Data, dropTarget))
                    action.OnDrop(e.Data, dropTarget);
                else
                    e.Handled = true;
            }
        }

        #endregion
    } 

Next I created an Attached DependencyProperty that starts the Draging when the MouseDownEvent gets fired. The Draging only gets initialized when the value that gets passed to the Property is "True".
    public static class DragDropBehaviour
    {
        #region DragDropHandler
        ... 
        #endregion

        #region IsDragSource DependencyProperty

        /// 
        /// attached property that defines if the source is a drag source
        /// 
        public static readonly DependencyProperty IsDragSourceProperty =
           DependencyProperty.RegisterAttached("IsDragSource", 
           typeof(bool?), 
           typeof(DragDropBehaviour),
           new PropertyMetadata(null, new IsDragSourceBehaviour().PropertyChangedHandler));

        public static void SetIsDragSource(DependencyObject o, object propertyValue)
        {
            o.SetValue(IsDragSourceProperty, propertyValue);
        }
        public static object GetIsDragSource(DependencyObject o)
        {
            return o.GetValue(IsDragSourceProperty);
        }

        #endregion

        /// <summary>
        /// Internal class that starts the draging
        /// </summary>
        private class IsDragSourceBehaviour : DragDropBehaviourBase
        {
            /// <summary>
            /// Hattach the events
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="oldValue"></param>
            /// <param name="newValue"></param>
            protected override void AdjustEventHandlers(DependencyObject sender, 
                                                        object oldValue, object newValue)
            {
                var element = sender as UIElement;
                if (element == null) 
                    return;

                if (oldValue != null)
                {
                    element.RemoveHandler(UIElement.MouseMoveEvent, 
                                          new MouseEventHandler(OnMouseMove));
                }

                if (newValue != null && newValue is bool && (bool)newValue)
                {
                    element.AddHandler(UIElement.MouseMoveEvent, 
                                       new MouseEventHandler(OnMouseMove));
                }
            }

            /// <summary>
            /// eventhandler for the MouseMoveEvent
            /// </summary>
            private void OnMouseMove(object sender, MouseEventArgs e)
            {
                if (sender is Selector && e.LeftButton == MouseButtonState.Pressed)
                {
                    var lst = (Selector)sender;
                    var selectedItem = lst.SelectedItem;

                    var dragDropEffect = DragDropEffects.Move;

                    if (dragDropEffect != DragDropEffects.None)
                    {
                        DragDropEffects enmEffect = 
                                   DragDrop.DoDragDrop(sender as DependencyObject, 
                                                       selectedItem, dragDropEffect);
                    }
                }
            }
        }
   }


The implementation of the DragDropHandler can be used in different ways.

Firs I tried an approach similar to the way the RelayCommand is implemented with an Object that implements the IDragDropHandler interface and can be used as a Property that gets attached to the DragDropHandlerPeoperty through data binding.
This object accepts a Action and a Func as parameters whereas the Func is optional.
    public class DragDropHandler : IDragDropHandler
    {
        readonly Action<IDataObject, IEnumerable> _drop;
        readonly Func<IDataObject, IEnumerable, bool> _canDrop;

        public DragDropHandler(Action<IDataObject, IEnumerable> drop)
            : this(drop, null)
        {
        }

        public DragDropHandler(Action<IDataObject, IEnumerable> drop, 
                               Func<IDataObject, IEnumerable, bool> canDrop)
        {
            if (drop == null)
                throw new ArgumentNullException("drop");

            _drop = drop;
            _canDrop = canDrop;
        }

        [DebuggerStepThrough]
        public bool CanDrop(IDataObject dropObject, IEnumerable dropTarget)
        {
            if (_canDrop != null)
                return _canDrop(dropObject, dropTarget);

            return true;
        }

        [DebuggerStepThrough]
        public void OnDrop(IDataObject dropObject, IEnumerable dropTarget)
        {
            _drop(dropObject, dropTarget);
        }
    }

In the ViewModel I created a Property of type DragDropHandler. Here I passed a method that accepts a IDataObject and IEnumerable as parameter for the Action<IDataObject, IEnumerable> and a method that accepts a IDataObject and IEnumerable as parameter for the Func<IDataObject, IEnumerable> (alternatively ony if needed) through the constructor. These methods will handle the DropActions similar to the RelayCommand.
The nice thing about this approach is that the DragDopHandler accepts Lambda Expressions as parameters instead of the methods.
        IDragDropHandler _dragDropAction;
        public IDragDropHandler DragDropAction
        {
            get
            {
                if (_dragDropAction == null)
                    _dragDropAction = new DragDropHandler(OnDrop, CanDrop);
                return _dragDropAction;
            }
        }

        public bool CanDrop(IDataObject dropObject, IEnumerable dropTarget)
        {
            if (!(dropTarget is IList))
                return false;
            return !(dropTarget as IList).Contains(dropObject.GetData(typeof(BaseGroup)));
        }

        public void OnDrop(IDataObject dropObject, IEnumerable dropTarget)
        {
            if (dropTarget is IList)
            {
                if (dropObject.GetDataPresent(typeof(BaseGroup)))
                {
                    (dropTarget as IList).Add(dropObject.GetData(typeof(BaseGroup)));
                }
            }
        }

In the XAML I added the AttachedProperties and made a DataBinding to the DragDropAction Property.
            <ListBox IsSynchronizedWithCurrentItem="True"
                     AllowDrop="True"
                     ItemsSource="{Binding Objects}" 
                     i:DragDropBehaviour.DragDropHandler="{Binding DragDropAction}"
                     i:DragDropBehaviour.IsDragSource="True"/>

            <ListBox Grid.Column="1"
                     IsSynchronizedWithCurrentItem="True"
                     AllowDrop="True"
                     ItemsSource="{Binding Objects2}" 
                     i:DragDropBehaviour.DragDropHandler="{Binding DragDropAction}"
                     i:DragDropBehaviour.IsDragSource="True"/>


Alternatively the ViewModel itself could implement the IDragDropHandler interface. This way the Binding can be made directly in the ViewModel instead of creating a roundtrip over the DragDropHandler object.
    internal class DragDropListBoxViewModel : IDragDropHandler
    {
        #region DragDropAction

        public bool CanDrop(IDataObject dropObject, IEnumerable dropTarget)
        {
            if (!(dropTarget is IList))
                return false;
            return !(dropTarget as IList).Contains(dropObject.GetData(typeof(BaseGroup)));
        }

        public void OnDrop(IDataObject dropObject, IEnumerable dropTarget)
        {
            if (dropTarget is IList)
            {
                if (dropObject.GetDataPresent(typeof(BaseGroup)))
                {
                    (dropTarget as IList).Add(dropObject.GetData(typeof(BaseGroup)));
                }
            }
        }

        #endregion
    }

The DataBinding can be made by directly binding to the ViewModel.
            <ListBox IsSynchronizedWithCurrentItem="True"
                     AllowDrop="True"
                     ItemsSource="{Binding Objects}" 
                     i:DragDropBehaviour.DragDropHandler="{Binding}"
                     i:DragDropBehaviour.IsDragSource="True"/>

            <ListBox Grid.Column="3" 
                     IsSynchronizedWithCurrentItem="True"
                     AllowDrop="True"
                     ItemsSource="{Binding Objects2}" 
                     i:DragDropBehaviour.DragDropHandler="{Binding}"
                     i:DragDropBehaviour.IsDragSource="True"/>

Dienstag, 10. Januar 2012

Syntax Highlighting

I just edited the layout of the Blog and added Syntax Highlighting for the code examples.

I found a description here http://heisencoder.net/2009/01/adding-syntax-highlighting-to-blogger.html which uses the Syntax Highlighter from http://alexgorbatchev.com/SyntaxHighlighter/

Possible suported languages are cpp, c, c++, c#, c-sharp, csharp, css, delphi, pascal, java, js, jscript, javascript, php, py, python, rb, ruby, rails, ror, sql, vb, vb.net, xml, html, xhtml, xslt. Full list

I'm realy surprised at how easy it was to implement this...

Set Properties to ReadOnly at runtime

Lately I needed to set the ReadOnly Attribute of a Property in C# at runtime. I wanted to change the IsReadOnly Property dynamically. The problem was that the IsReadOnly Property of the ReadOnlyAttribute does not contain a setter meaning that it is ReadOnly...

After doing a lot of searching I stumbled on this Post by David Morton. Here he describes how to use Reflection to edit internal fields.

I created a Method that uses Reflection to change the IsReadOnly Property of the ReadOnlyAttribute.
     /// <summary>  
     /// Uses reflection to set the readonly attribute on a property.  
     /// This value is set to the class definition and not to the instance.   
     /// If it is set once than it has to be reset again to get the default.  
     /// </summary>  
     /// <param name="instance">instance containing the property</param>  
     /// <param name="property">the property to set the readonly value</param>  
     /// <param name="value">value to set to the property</param>  
     private static void SetReadOnly(object instance, string property, bool value)  
     {  
       // Create a PropertyDescriptor for the Property by calling the static 
       // GetProperties on TypeDescriptor.  
       PropertyDescriptor descriptor = 
                        TypeDescriptor.GetProperties(instance.GetType())[property];  
       // Fetch the ReadOnlyAttribute from the descriptor.   
       ReadOnlyAttribute attrib = 
                       (ReadOnlyAttribute)descriptor.Attributes[typeof(ReadOnlyAttribute)];  
       // Get the internal isReadOnly field from the ReadOnlyAttribute using reflection.   
       System.Reflection.FieldInfo isReadOnly = 
                       attrib.GetType().GetField("isReadOnly", 
                              System.Reflection.BindingFlags.NonPublic | 
                              System.Reflection.BindingFlags.Instance);  
       // Using Reflection, set the internal isReadOnly field.   
       isReadOnly.SetValue(attrib, value);   
     }  

In this excample I want to change the value of the ReadOnlyAttribute of the TestProperty.
   class PropertyTest  
   {  
     string _testProperty;  
     [ReadOnly(false)]  
     public string TestProperty  
     {  
       get  
       {  
         return _testProperty;  
       }  
       set  
       {  
         _testProperty = value;  
       }  
     }  
   }  
Now I can pass a instance and make any Property I want ReadOnly or Readable again.
     public void Edit()  
     {  
       var instance = new PropertyTest();  
       SetReadOnly(instance, "TestProperty", true);  
     }  
A big drawback about this is that it breaks encapsulation.
Another problem with this approach ist that it changes the Attribute in the Class definition and not only in the instance. If a new object is created the ReadOnlyAttribute of Property has the value that was set previously. In that case the Attribute has to be set every time a new Instance is created.