Archive for category How To

Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding.

BasicBindingUpdate 11.07.2013 : Added ICommanding example.
Update 10.25.2013 : Added how to use the CallerMemberName attribute with INotifyPropertyChanged in .Net 4.

While answering a question on StackOverflow I ran across a situation where the user was having troubles due to binding to a view model which was statically initiated in Xaml. While there is nothing wrong with creating the VM in Xaml, it can miss some benefits for most control and page situations where the all controls want to access one source of data. This article describes and provides example code to creating the view model in the code behind which I tend to prefer over the others methods.

Create a .Net 4 and Above VM

The view model adheres to the standard where it implements INotifyPropertyChange. The following ViewModel implements it using the .Net 4.5 way with the CallerMemberName attribute which saves us from having to explicitly define it on every member call. (If you are using .Net 4, add the Nuget Package: Microsoft BCL into you project to use CallerMemberName attribute).

Note for reference there is a situation below where we actually do specify the property name but it is to create in a change notification on another property.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace SO_WPF.ViewModels {

public class MainVM : INotifyPropertyChanged 
{

    private List<string> _Members;
    private int _MemberCount;
    private bool _IsMembershipAtMax;
    public bool IsMembershipAtMax 
    {
        get { return MemberCount > 3; }
    }
    public int MemberCount 
    { 
        get { return _MemberCount; }
        set
        {
            _MemberCount = value; 
            OnPropertyChanged();
            OnPropertyChanged("IsMembershipAtMax");
        } 
    }

    public List<string> Members 
    { 
        get { return _Members; }
        set { _Members = value; OnPropertyChanged(); } 
    }
    public MainVM()
    {
        // Simulate Asychronous access, such as to a db.

        Task.Run(() =>
                    {
                        Members = new List<string>() {"Alpha", "Beta", "Gamma", "Omega"};
                        MemberCount = Members.Count;
                    });
    }
    /// <summary>Event raised when a property changes.</summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>Raises the PropertyChanged event.</summary>
    /// <param name="propertyName">The name of the property that has changed.</param>
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}
}

Main Page Code Behind

We now need to hook up the main page view model to the main page. To do that we will do two things, one, make a non INotifyPropertyChanged property on the class which will hold our view model. Two we will instantiate it, hook it up to the page’s data along with our property. Doing that ensures that everything on our page will get access to our view model, thanks to the data context and how controls inherit their parents data context.

using SO_WPF.ViewModels;

namespace SO_WPF
{
    public partial class MainWindow : Window
    {

        public MainVM ViewModel { get; set; }

        public MainWindow()
        {
            InitializeComponent();

            // Set the windows data context so all controls can have it.
            DataContext = ViewModel = new MainVM();

        }

    }
}

Xaml

Now in the xaml we can simply bind to the View Models properties directly without any fuss.

<Window x:Class="SO_WPF.MainWindow"
        xmlns:viewModels="clr-namespace:SO_WPF.ViewModels"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        d:DataContext="{d:DesignInstance {x:Type viewModels:MainVM}}"
        Title="MainWindow"
        Height="300"
        Width="400">

<StackPanel Orientation="Vertical">
    <ListBox Name="lbData"
                ItemsSource="{Binding Members}"
                SelectionMode="Multiple"
                Margin="10" />

    <Button Height="30"
            Width="80"
            Margin="10"
            Content="Click Me" />
</StackPanel>

</Window>

In the above code we bind the Members to the listbox just by specifying the Members property name. As to the highlighted lines, I have added them as a debug design option. That lets Visual Studio and Blend know that our data context is our MainVM. That allows for the editor to present us with the options of data binding to the appropriate items, and not having it blank.

This has been a simple example, but a powerful one which can be used as a binding strategy for any WPF, Silverlight or Windows Phone Xaml based applications in C#.

Note though it is not shown, sometimes in styles one needs the element name to bind to, where the data context will fail due to the nature of the style binding, the above page we would bind to the page name as provided (“MainWindow”) and then the property name as usual!

Extra Credit ICommanding

I won’t go into much detail about commanding, but the gist is that the ViewModel is not directly responsible for actions which can happen due to the ICommanding process, but allow for binding operations to occur against those actions and those actions are performed elsewhere usually on a view.

Below is our view model with the commanding public variables which can be consumed by controls (or other classes which have access to the VM).

public class MainVM : INotifyPropertyChanged
{
    #region Variables
       #region Commanding Operations

    public ICommand ToggleEditing { get; set; }
    public ICommand ReportError   { get; set; }
    public ICommand CheckSequence { get; set; }

       #endregion
       #region Properties
    public string ErrorMessage { // the usual INotifyProperty as shown before }
       #endregion
    #endregion
}

Then on our main page which consumes the view model we then process those requests by creating methods to fulfill those operations. Note that the example below references properties on the VM which were not shown in the example,
but that is not important in this article. But one variable is shown and that is the error message. This allow anyone to push an error using the commanding to the viewmodel which is subsequently shown. That is a peek at the power of commanding right there to allow a dependency injection of setting an error variable to be done outside the VM but used by those which consume the VM!

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();

        // Set the windows data context so all controls can have it.
        DataContext = ViewModel = new MainVM();

        SetupCommanding();
    }

    private void SetupCommanding()
    {
        // Commanding using OperationCommand class
        ViewModel.ToggleEditing         = new OperationCommand((o) => ViewModel.IsEditing = !ViewModel.IsEditing);
        ViewModel.ReportError           = new OperationCommand((o) => ViewModel.ErrorMessage = (string)o);
        ViewModel.CheckSequence         = new OperationCommand(CheckSequences, CanExecute);

    }

     private void CheckSequences(object obj)
     {
        ...
     }

    private bool CanExecute(object obj)
    {
        return !ViewModel.UnsavedsExist;
    }
}

Finally the ICommanding class used.

public class OperationCommand : ICommand
{

    #region Variables

    Func<object, bool> canExecute;
    Action<object> executeAction;

    public event EventHandler CanExecuteChanged;

    #endregion

    #region Properties

    #endregion

    #region Construction/Initialization

    public OperationCommand(Action<object> executeAction)
        : this(executeAction, null)
    {
    }

    public OperationCommand(Action<object> executeAction, Func<object, bool> canExecute)
    {
        if (executeAction == null)
        {
            throw new ArgumentNullException("Execute Action was null for ICommanding Operation.");
        }
        this.executeAction = executeAction;
        this.canExecute = canExecute;
    }

    #endregion

    #region Methods

    public bool CanExecute(object parameter)
    {
        bool result = true;
        Func<object, bool> canExecuteHandler = this.canExecute;
        if (canExecuteHandler != null)
        {
            result = canExecuteHandler(parameter);
        }

        return result;
    }

    public void RaiseCanExecuteChanged()
    {
        EventHandler handler = this.CanExecuteChanged;
        if (handler != null)
        {
            handler(this, new EventArgs());
        }
    }

    public void Execute(object parameter)
    {
        this.executeAction(parameter);
    }

    #endregion
Share

Tags: , , , , , ,

C#: Multiple Dynamic Properties on a Class Either Defined or with Generics

Using the class indexer of C# (abc[ xxx ] = yyy) we can create a class which has multiple dynamic properties associated by a string or whatever we want as the key for access. In the example below we use a string as our access key and holds a string as a value. The storage is accomplished by using a dictionary. See the Usage method below on how to access it.

public class MultipleDynamicProperties
{

    private Dictionary<string, string> _dynamicProperties = new Dictionary<string, string>();    
    
    // Index the data here  
    public string this[string key]
    {
        get
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, string.Empty );

            return _dynamicProperties[key];
        }
        set
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, value );
            else
            {
                _dynamicProperties[key] = value;
            }
        }
    }

    /// <summary>
    /// Example don't use in your code.
    /// </summary>
    public static void Usage()
    {
        MultipleDynamicProperties mdc = new MultipleDynamicProperties();

        mdc["Jabber"] = "1st Attempt";
        mdc["Jabber"] = "Wocky";
        mdc["Omega"] = "Man";

        Console.WriteLine("Jabber: " + mdc["Jabber"]); // Printers Jabber: wocky

    }

}

Using other index types say integer or enum, we can accomplish the same goal by changing or adding to our index’able properties of the class. We could have multiple accessors as long as the key is not the same. Below is an example using an enum as the key and a List<string> as the value returned:

public class MultipleDynamicPropertiesWithEnum
{
    public enum Operation
    {
        TargetA,
        TargetB,
    }

    private Dictionary<Operation, List<string>> _dynamicProperties = new Dictionary<Operation, List<string>>();


         // Index the data here  
    public List<string> this[Operation key]
    {
        get
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, new List<string>() );

            return _dynamicProperties[key];
        }
        set
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, value );
            else
            {
                _dynamicProperties[key] = value;
            }
        }
    }

    public static void Usage()
    {
        MultipleDynamicPropertiesWithEnum show = new MultipleDynamicPropertiesWithEnum();

        show[Operation.TargetA] = new List<string>() { "Jabber" };
        show[Operation.TargetB] = new List<string>() { "Wocky" };

        // Prints Jabberwocky 
        Console.WriteLine( show[Operation.TargetA][0] + show[Operation.TargetB][0] );
    }
}

 

Generic Option

But why limit ourselves, why not make the accessor generic, so the user/consumer can dictate what the keys and what data is returned. Here is the generic version where we mimic the hard coded version of string and string.

/// <summary>
/// This class has a generic indexor defined by the generic parameters specified
/// by the consumer.
/// </summary>
/// <typeparam name="KY">Key type to use to acces the value type to store.</typeparam>
/// <typeparam name="T">The value type to store.</typeparam>
/// <remarks>See Usage on how to use.</remarks>
public class MultipleDynamicPropertiesAsGeneric<KY, T>
{

    private Dictionary<KY, T> _dynamicProperties = new Dictionary<KY, T>();

    // Index the data here  
    public T this[KY key]
    {
        get
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
            {
                _dynamicProperties.Add( key, Activator.CreateInstance<T>() );
            }

            return _dynamicProperties[key];
        }
        set
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, value );
            else
            {
                _dynamicProperties[key] = value;
            }
        }
    }

    public static void Usage()
    {
        MultipleDynamicPropertiesAsGeneric<string, string> show = new MultipleDynamicPropertiesAsGeneric<string, string>();

        show["Jabber"] = "Wocky";

        // Prints wocky 
        Console.WriteLine( show["Jabber"] );

    }

}
Share

Tags: ,

C#: Handling Title Case in Strings with Articles and Prepositions

iStock_000002240961XSmall

This was an issue I answered in the forums which a user presented and felt that the response was intricate enough to share with the world as a whole. The user wanted to have a string converted to title case but also wanted to have the first letter of any article or preposition to not be be upper case along with the rest of the sentence. This article discusses how to do that in C#.

For example the user was interested in changing

“ALL QUIET ON THE WESTERN FRONT”

   to

“All Quiet on the Western Front.”

.Net Framework Almost Does It

Thanks to the TextInfo class and a helping hint from a current CultureInfo object we can use the method ToTitleCase to work with our current language. The problem is that when ToTitleCase is called with the original sentence we get this:

“All Quiet On The Western Front”

Give it some Help

The .Net code is not robust enough to ignore the articles and prepositions so we will augment it. The following code using Linq-to-Object and Regex and processes majority of the target articles and prepositions . I have placed it into an extension method below:

/*
using System.Globalization;
using System.Threading;
using System.Text.RegularExpressions;
*/

/// <summary>
/// An Extension Method to allow us t odo "The Title Of It".asTitleCase()
/// which would return a TitleCased string.
/// </summary>
/// <param name="title">Title to work with.</param>
/// <returns>Output title as TitleCase</returns>
public static string asTitleCase ( this string title)
{
    string WorkingTitle = title;

    if ( string.IsNullOrEmpty( WorkingTitle ) == false )
    {
        char[] space = new char[] { ' ' };

        List<string> artsAndPreps = new List<string>()
            { "a", "an", "and", "any", "at", "from", "into", "of", "on", "or", "some", "the", "to", };

        //Get the culture property of the thread.
        CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
        //Create TextInfo object.
        TextInfo textInfo = cultureInfo.TextInfo;

        //Convert to title case.
        WorkingTitle = textInfo.ToTitleCase( title.ToLower() );

        List<string> tokens = WorkingTitle.Split( space, StringSplitOptions.RemoveEmptyEntries ).ToList();

        WorkingTitle = tokens[0];

        tokens.RemoveAt(0);

        WorkingTitle += tokens.Aggregate<String, String>( String.Empty, ( String prev, String input )
                                => prev +
                                    ( artsAndPreps.Contains( input.ToLower() ) // If True
                                        ? " " + input.ToLower()              // Return the prep/art lowercase
                                        : " " + input ) );                   // Otherwise return the valid word.

        // Handle an "Out Of" but not in the start of the sentance
        WorkingTitle = Regex.Replace( WorkingTitle, @"(?!^Out)(Out\s+Of)", "out of" );
    }

    return WorkingTitle;

}
Explanation
  • Line 21: Here is our English list of words not to capitalize. We would have to change this for other languages.
  • Line 25: We get the current culture from the running thread so that ToTitleCase can do its job.
  • Line 30: ToTitleCase does the first run and upper cases all the first letters and drops any following upper case letters if they exist.
  • Line 32: We split the line on space between the words into word tokens and put them in a list.
  • Line 34: We save off the first word because regardless of what it is, it is correct.
  • Line 36: We remove the first word so not to process it.
  • Line 40: Using the Aggregate extension to accumulate each word token we will add a space. We are using the aggregate method in-lieu of string.Join to add spaces to our words (the accumulation), but also to check each word as it goes by which string.Join can’t help us with.
  • Line 42: As the tokens (words) are handed to us, check to see if they are in the list we setup in line 21. If it exists, add a space in front and make the whole word lower case (Line 43) other wise ad a space and just return the word.
  • Line 46: Handle any two word Out Of issues, but ignore if it is the first word as found in “Out of Africa”.
Tests and Results

 

Console.WriteLine( "ALL QUIET ON THE WESTERN FRONT".asTitleCase() );
Console.WriteLine( "Bonfire OF THE Vanities".asTitleCase() );
Console.WriteLine( "The Out-of-Sync Child: Recognizing and Coping with Sensory Processing Disorder".asTitleCase() );
Console.WriteLine( "Out OF AFRICA".asTitleCase() );

/* Results
All Quiet on the Western Front
Bonfire of the Vanities
The Out-Of-Sync Child: Recognizing and Coping With Sensory Processing Disorder
Out of Africa
*/
Share

Tags: , , ,