Posts Tagged ‘ CSharp ’

ObservableCollection – Extension Methods

When you ever used the CollectionView of the ObservableCollection and wanted to get or set the CurrentItem you might have noticed that it requires much more typing than expected.

For that purpose I created the following extension methods for the ObservableCollection.

 

  public static class CollectionExtensions
  {
    /// <summary>
    /// This method returns the current item of the given collection.
    /// </summary>
    /// <typeparam name="T">The type of the elements in the collection.</typeparam>
    /// <param name="source">The collection.</param>
    public static T GetCurrentItem<T>(this IEnumerable<T> source)
    {
      if (source == null)
        return default(T);
      var collectionView = CollectionViewSource.GetDefaultView(source);
      return (T)collectionView.CurrentItem;
    }

    /// <summary>
    /// This method returns the current position within the given collection.
    /// </summary>
    /// <typeparam name="T">The type of the elements in the collection.</typeparam>
    /// <param name="source">The collection.</param>
    public static int GetCurrentPosition<T>(this IEnumerable<T> source)
    {
      if (source == null)
        return -1;
      var collectionView = CollectionViewSource.GetDefaultView(source);
      return collectionView.CurrentPosition;
    }

    /// <summary>
    /// This method sets the current item of the given collection.
    /// </summary>
    /// <typeparam name="T">The type of the elements in the collection.</typeparam>
    /// <param name="source">The collection.</param>
    /// <param name="item">The item which should be set as the current one.</param>
    public static void SetCurrentItem<T>(this IEnumerable<T> source, T item)
    {
      if (source == null) return;
      var collectionView = CollectionViewSource.GetDefaultView(source);
      collectionView.MoveCurrentTo(item);
    }

    /// <summary>
    /// This method moves the current item to the first.
    /// </summary>
    /// <typeparam name="T">The type of the elements in the collection.</typeparam>
    /// <param name="source">The collection.</param>
    public static void MoveCurrentToFirst<T>(this IEnumerable<T> source)
    {
      if (source == null) return;
      var collectionView = CollectionViewSource.GetDefaultView(source);
      collectionView.MoveCurrentToFirst();
    }

    /// <summary>
    /// This method moves the current item to the previous.
    /// </summary>
    /// <typeparam name="T">The type of the elements in the collection.</typeparam>
    /// <param name="source">The collection.</param>
    public static void MoveCurrentToPrevious<T>(this IEnumerable<T> source)
    {
      if (source == null) return;
      var collectionView = CollectionViewSource.GetDefaultView(source);
      collectionView.MoveCurrentToPrevious();
    }

    /// <summary>
    /// This method moves the current item to the next.
    /// </summary>
    /// <typeparam name="T">The type of the elements in the collection.</typeparam>
    /// <param name="source">The collection.</param>
    public static void MoveCurrentToNext<T>(this IEnumerable<T> source)
    {
      if (source == null) return;
      var collectionView = CollectionViewSource.GetDefaultView(source);
      collectionView.MoveCurrentToNext();
    }

    /// <summary>
    /// This method moves the current item to the last.
    /// </summary>
    /// <typeparam name="T">The type of the elements in the collection.</typeparam>
    /// <param name="source">The collection.</param>
    public static void MoveCurrentToLast<T>(this IEnumerable<T> source)
    {
      if (source == null) return;
      var collectionView = CollectionViewSource.GetDefaultView(source);
      collectionView.MoveCurrentToLast();
    }

    /// <summary>
    /// This method sets the current position withing the given collection
    /// </summary>
    /// <typeparam name="T">The type of the elements in the collection</typeparam>
    /// <param name="source">The collection</param>
    /// <param name="index">The new position</param>
    public static void SetCurrentPosition<T>(this IEnumerable<T> source, int index)
    {
      if (source == null) return;
      var collectionView = CollectionViewSource.GetDefaultView(source);
      collectionView.MoveCurrentToPosition(index);
    }

    /// <summary>
    /// Removes the items from the collection according to the predicate.
    /// </summary>
    /// <param name="source">The source.</param>
    /// <param name="predicate">The predicate.</param>
    public static void Remove<T>(this ICollection<T> source, Func<T, bool> predicate)
    {
      if (source == null) return;
      var itemsToRemove = source.Where(predicate).ToList();
      foreach (var item in itemsToRemove)
        source.Remove(item);
    }
}
Advertisements

WPF – Send keys

Hi guys,

if you come from the WinForms age you might know the SendKeys class and the SendKeys.Send method, which allows you to send keys to the keyboard.
Meaning that you can simulate the pressing of a key.

But in WPF this class is no longer present. Instead of this class you can use the InputManager and feed it with the KeyEventArgs which will then be processed.
I created a small class which simplyfies this process.

public static class SendKeys
  {
    /// <summary>
    ///   Sends the specified key.
    /// </summary>
    /// <param name="key">The key.</param>
    public static void Send(Key key)
    {
      if (Keyboard.PrimaryDevice != null)
      {
        if (Keyboard.PrimaryDevice.ActiveSource != null)
        {
          var e1 = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Down) {RoutedEvent = Keyboard.KeyDownEvent};
          InputManager.Current.ProcessInput(e1);
        }
      }
    }
  }

You can simply call the SendKeys.Send method like you did it in WinForms.

Have fun!

WPF – Custom IsSynchronizedWithCurrentItem implementation

Hi guys,

if you ever missed the IsSynchronizedWithCurrentItem property in one of your controls you might need this.
Well basically you can enable a feature using this property which is synchronizing the selected item of your Control (ListBox, ComboBox, etc.) with the current item of the collection to which you bind to.

In my case I needed this feature in the Telerik RadListBox. Therefore I created an attached property which simulates this feature.
Basically what I’m doing is the following:

  • When the SelectedItem in the ListBox was changed => update the CurrentItem in the Collection
  • When the CurrentItem in the Collection was changed => update the SelectedItem of the ListBox

The tricky part here is that the user might bind a new collection to the control. Such that you have to notice that the collection was changed and register the events for the new collection.
Therefore I used this ListBoxSources-Dictionary which contains the key value pairs of the listboxes and their corresponding collections.
If the collection is different from the one it has before we know that it was changed and have to unregister the events in the old collection and register then in the new collection.

Here is the code I was talking about:

 /// <summary>
  ///   This class contains a few useful extenders for the ListBox.
  /// </summary>
  public class RadListBoxExtensions : DependencyObject
  {
    private static readonly Dictionary<RadListBox, object> ListBoxSources = new Dictionary<RadListBox, object>();

    public static readonly DependencyProperty IsSynchronizedWithCurrentItemProperty = DependencyProperty.RegisterAttached("IsSynchronizedWithCurrentItem", typeof (bool), typeof (RadListBoxExtensions), new UIPropertyMetadata(default(bool), OnIsSynchronizedWithCurrentItemChanged));

    /// <summary>
    ///   Returns the value of the IsSynchronizedWithCurrentItemProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be returned</param>
    /// <returns>The value of the given property</returns>
    public static bool GetIsSynchronizedWithCurrentItem(DependencyObject obj)
    {
      return (bool) obj.GetValue(IsSynchronizedWithCurrentItemProperty);
    }

    /// <summary>
    ///   Sets the value of the IsSynchronizedWithCurrentItemProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be set</param>
    /// <param name="value">The value which should be assigned to the AutoScrollToCurrentItemProperty</param>
    public static void SetIsSynchronizedWithCurrentItem(DependencyObject obj, bool value)
    {
      obj.SetValue(IsSynchronizedWithCurrentItemProperty, value);
    }

    /// <summary>
    ///   This method will be called when the IsSynchronizedWithCurrentItem property was changed
    /// </summary>
    /// <param name="s">The sender (the RadListBox)</param>
    /// <param name="e">Some additional information</param>
    public static void OnIsSynchronizedWithCurrentItemChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
    {
      var listBox = s as RadListBox;
      if (listBox != null)
      {
        var newValue = (bool) e.NewValue;
        var selectionChangedWorker = new SelectionChangedEventHandler((s1, e2) => OnSelectionChanged(listBox, listBox.SelectedItem));
        if (newValue)
        {
          listBox.Loaded += OnLoaded;
          listBox.SelectionChanged += selectionChangedWorker;
        }
        else
        {
          listBox.Loaded -= OnLoaded;
          listBox.SelectionChanged -= selectionChangedWorker;
        }
      }
    }

    /// <summary>
    ///   Called when when the listbox was loaded.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">
    ///   The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.
    /// </param>
    private static void OnLoaded(object sender, RoutedEventArgs e)
    {
      var listBox = sender as RadListBox;
      if (listBox == null)
        return;
      var collection = listBox.ItemsSource;
      ActivateCollectionIfNecessary(listBox, collection);
    }

    /// <summary>
    ///   Called when the selection was changed.
    /// </summary>
    /// <param name="listBox">The list box.</param>
    /// <param name="selectedItem">The selected item.</param>
    private static void OnSelectionChanged(RadListBox listBox, object selectedItem)
    {
      var collection = listBox.ItemsSource;
      ActivateCollectionIfNecessary(listBox, collection);
      var defaultView = CollectionViewSource.GetDefaultView(collection);
      if (defaultView != null)
        defaultView.MoveCurrentTo(selectedItem);
    }

    /// <summary>
    ///   Activates the collection if necessary.
    /// </summary>
    /// <param name="listBox">The listbox.</param>
    /// <param name="collection">The collection.</param>
    private static void ActivateCollectionIfNecessary(RadListBox listBox, object collection)
    {
      if (!ListBoxSources.ContainsKey(listBox))
        ListBoxSources.Add(listBox, collection);
      else if (ListBoxSources[listBox] == collection)
        return;
      var oldCollection = ListBoxSources[listBox];
      var newView = CollectionViewSource.GetDefaultView(collection);
      var currentChangedWorker = new EventHandler((s1, e2) => listBox.SelectedItem = newView.CurrentItem);

      if (oldCollection != null)
      {
        var oldView = CollectionViewSource.GetDefaultView(oldCollection);
        if (oldView != null)
          oldView.CurrentChanged -= currentChangedWorker;
      }
      ListBoxSources[listBox] = collection;

      if (newView != null)
      {
        newView.CurrentChanged += currentChangedWorker;
        listBox.SelectedItem = newView.CurrentItem;
      }
    }
}

Have fun!

The type reference cannot find a public type named ‘MyType’

Today I had a strange problem when I wanted to define a DataTemplate of a specific type which is located in the same assembly as I wanted to use it.
The problem was that if I wrote the assembly-name in the import of the Namespace then I got the following Exception:

The type reference cannot find a public type named ‘MyType’

So after a few hours of testing and searching I finally found the solution. I just had to remove the assembly from the import of the namespace.

Now lets have a look at a simple demonstration of the problem

This is the type I want to assign to the DataTemplate

namespace MyWpfApp
{
    public class MyType
    {
        private string _description;

        public MyType(string description)
        {
            _description= description;
        }

        public string Description
        {
            get { return _description; }
        }
    }
}

In the UI I defined a DataTemplate for this type

<Window x:Class="MyWpfApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:me="clr-namespace:MyWpfApp;assembly=MyWpfApp"
    Title="MainWindow">    
    <Window.Resources>
        <DataTemplate DataType="{x:Type me:MyType}"> <!-- Here it displays the error message -->
            <StackPanel Orientation="Vertical">
                <TextBlock Text="Description" FontWeight="Bold" Margin="5"/>
                <TextBlock Text="{Binding Description}" Margin="5"/>
            </StackPanel>
        </DataTemplate>
......

This code results in the error message I talked about before.

But if you change the import of the MyWpfApp namespace then it works without problems.

<Window x:Class="MyWpfApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:me="clr-namespace:MyWpfApp" <!-- REMOVED the assembly in the namespace import to fix the problem -->
    Title="MainWindow">    
    <Window.Resources>
        <DataTemplate DataType="{x:Type me:MyType}">
            <StackPanel Orientation="Vertical">
                <TextBlock Text="Description" FontWeight="Bold" Margin="5"/>
                <TextBlock Text="{Binding Description}" Margin="5"/>
            </StackPanel>
        </DataTemplate>
......

Have fun

[WPF] Custom ValidationRule with an additional parameter

Hello,

maybe you ever had the problem that you wanted to create a custom validationrule but you need some kind of an extra parameter.
But it seems that there is no straightforward way to do that.

So I used this workaround in order to achieve that.
In this example I will validate a string. The parameter gives the length if the string is shorter then it is valid else not.

First of all we have to create our custom ValidationRule

public class MyStringLengthValidationRule : ValidationRule
  {
    /// <summary>
    /// Gets or sets the maximal length of the string
    /// </summary>
    public int Length { get; set; }

    /// <summary>
    /// Checks if the string is valied
    /// </summary>
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
      if (value.ToString().Length <= Length)
         return new ValidationResult(true, null);
      return new ValidationResult(false, "The string is to long");
    }
  }

All right. Here you see this simple ValidationRule with our additional property (Length).
We can not use DependencyProperties because ValidationRule does not extend DependencyObject therefore we have to use this property.

The second step is to assign our ValidationRule to a control

        <TextBox>
            <TextBox.Text>
                <Binding Path="MyText">
                    <Binding.ValidationRules>
                        <utils:MyStringLengthValidationRule Length="{Binding MyLength}" />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

You may think that it works like this but it does not. Since the Length property is not a DependencyProperty we can not directly bind to it.
But there exists a nice workaround. We can just use a so-called proxy which allows us to bind values to normal properties.
I used the proxy from this blog: http://www.11011.net/wpf-binding-properties

The version using the proxy looks like this

<utils:Proxy In="{Binding MyLength, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" Out="{Binding ElementName=strLengthValidationRule, Path=Length}" /> 
<TextBox>
  <TextBox.Text>
     <Binding Path="MyText">
         <Binding.ValidationRules>
            <utils:MyStringLengthValidationRule x:Name="strLengthValidationRule" />
          </Binding.ValidationRules>
       </Binding>
  </TextBox.Text>
</TextBox>

All right now it should work.

I attached the demo project. Where you can specify the maximal length (upper TextBox) of the string in the TextBox at the bottom.
Note that the Validation will only be updated when the value of the TextBox was changed!

The attached file is a rar file. I just have to add the doc extension because else I can not upload it.
Change the extension in .rar then you can extract it. (It contains the demo project as a VS 2010 Beta solution)
ValidatorWithParameter.rar (doc)

[WPF] Set Attached Properties (Grid.Column, Grid.Row, Canvas.Top, Canvas.Left, etc.) in C# Code

Hello everybody,

if you tried to create a Grid, Canvas or a DockPanel in C# problem than you probably had the problem that you do not know how to add the children to a specific column, row or whatever.

These properties are so called Attached Properties. And you can not see them if you call textBox.Grid.Row in the C# code.

Here an example

<Grid>
   <TextBox Grid.Row="0" Grid.Column="0" />
</Grid>

But you can not do the following in your C# Code

<pre>Grid grid = new Grid();
TextBox txt = new TextBox();
txt.Grid.Column = 1; //Not possible!

But you can do the following

//Set the Grid.Row Attached Property of the TextBox txt to 0
Grid.SetRow(txt, 0);
//Set the Grid.Column Attached Property of the TextBox txt to 0
Grid.SetColumn(txt,0);

It works in the same way for all other Attached Properties

ListBox – Automatically scroll to bottom

In WinForms it was so simple to tell the ListBox to scroll to the buttom.
But in WPF it seems to be rather difficult but it is not.
You can simply create an attached property and once done it will do it for you.

Simply add the attached property to your ListBox

<ListBox ItemsSource="{....}" Extenders:ListBoxExtenders.AutoScrollToEnd="True" />

And here is the source code of the attached property

/// <summary>
  /// This class contains a few useful extenders for the ListBox
  /// </summary>
  public class ListBoxExtenders : DependencyObject
  {
    public static readonly DependencyProperty AutoScrollToEndProperty = DependencyProperty.RegisterAttached("AutoScrollToEnd", typeof(bool), typeof(ListBoxExtenders), new UIPropertyMetadata(default(bool), OnAutoScrollToEndChanged));

    /// <summary>
    /// Returns the value of the AutoScrollToEndProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be returned</param>
    /// <returns>The value of the given property</returns>
    public static bool GetAutoScrollToEnd(DependencyObject obj)
    {
      return (bool)obj.GetValue(AutoScrollToEndProperty);
    }

    /// <summary>
    /// Sets the value of the AutoScrollToEndProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be set</param>
    /// <param name="value">The value which should be assigned to the AutoScrollToEndProperty</param>
    public static void SetAutoScrollToEnd(DependencyObject obj, bool value)
    {
      obj.SetValue(AutoScrollToEndProperty, value);
    }

    /// <summary>
    /// This method will be called when the AutoScrollToEnd
    /// property was changed
    /// </summary>
    /// <param name="s">The sender (the ListBox)</param>
    /// <param name="e">Some additional information</param>
    public static void OnAutoScrollToEndChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
    {
      var listBox = s as ListBox;
      var listBoxItems = listBox.Items;
      var data = listBoxItems.SourceCollection as INotifyCollectionChanged;

      var scrollToEndHandler = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
          (s1, e1) =>
          {
            if (listBox.Items.Count > 0)
          {
            object lastItem = listBox.Items[listBox.Items.Count - 1];
            listBoxItems.MoveCurrentTo(lastItem);
            listBox.ScrollIntoView(lastItem);
          }
          });

      if ((bool)e.NewValue)
        data.CollectionChanged += scrollToEndHandler;
      else
        data.CollectionChanged -= scrollToEndHandler;
    }
  }

Note that it is similar to the scroll current element into view
So check this out: scroll current item into view