Bassem Mohsen's Programming Blog

"High thoughts must have high language." —Aristophanes

  • The Author

    Bassem Mohsen - Freelance Windows and
    Web application developer. Technical writer. 24 yo. Based in Cairo, Egypt.

  • MCTS certification logo

Posts Tagged ‘WPF’

Culture Info

Posted by Bassem Mohsen on July 15, 2011

Download the source code and binaries of the Culture Info project.
Run Culture Info (Works only for Internet Explorer with XBAPs enabled).

Introduction

The MSDN documentation says: "Windows ships with a set of locales, equivalent to .NET Framework cultures, that specify culture-specific information such as how text is sorted, how a date is formatted, and the display format of numbers and currency."
This culture information is intended for use by the code that performs culture-sensitive sorting and formatting. But I think that this information can be interesting in itself. For example it can be interesting to know the currency symbol for a certain country and whether a certain language is written from right to left.

Culture Info is an XBAP that presents you with a list of cultures installed on your computer. You can select a culture from the list to view information about this culture.

This application was developed to explore and practice with WPF binding, specifically binding to collections (where the binding source is a collection), and master-detail binding (where selecting an item from a list shows you details about this item).

Binding Item Controls to Collections

The collection acting as the binding source can be specified either in the binding expression or by setting the DataContext property of the bound element or one of its ancestors to the collection object. Because in the CulturesWindow many controls are bound to the same collection (the CultureInfo array), my choice was to set the DataContext of the Window to the collection object. This saves me from specifying the binding source in every binding expression.

CultureInfo[] specificCultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);

this.DataContext = specificCultures;

<ComboBox

          ItemsSource="{Binding}" DisplayMemberPath="Name" IsSynchronizedWithCurrentItem="True"

          SelectedItem="{Binding Source={x:Static glob:CultureInfo.CurrentCulture}, Mode=OneWay}">

    …

</ComboBox>

The above piece of XAML defines a ComboBox that is bound to the CultureInfo array, specifies that the items of the ComboBox should display the value of the ‘Name’ property of the array items, sets the SelectedItem to the static object returned by CultureInfo.CurrentCulture, and sets the Binding Mode of the second binding expression to OneWay because we do not want the selection change to update the binding source.

But what about the IsSynchronizedWithCurrentItem="True"?
When a collection is bound to by a WPF binding, an ICollectionView is created for that collection. Item controls display all the items of the collection, but content controls only display the CurrentItem of the CollectionView. Setting IsSynchronizedWithCurrentItem to true on the ComboBox ensures that the SelectedItem property of the ComboBox will always be equal to the CurrentItem property of the ICollectionView. Consequently, the content controls will display the properties of the item that is selected in the ComboBox. This is how master-detail binding is achieved.

Binding Content Controls to the CurrentItem in the CollectionView

Here is how a TextBlock was bound to the AlgorithType of the Calendar of the currently selected CultureInfo.

<TextBlock Text="{Binding Path=/Calendar.AlgorithmType}" />

The ‘/’ in the binding path means that Calendar is a property of the type of the CurrentItem in the CollectionView. The ‘.’ in the path means that AlgorithmType is a property of the type of Calendar. I admit that this is a bit confusing, but the documentation of the Binding.Path property explains very well the binding path syntax.

Grouping and Sorting

ICollectionView supports grouping collection items.

ICollectionView culturesCollectionView = CollectionViewSource.GetDefaultView(specificCultures);

culturesCollectionView.GroupDescriptions.Add(new PropertyGroupDescription("Parent"));

The first statement in the above code snippet uses the static method CollectionViewSource.GetDefaultView to get the ICollectionView created for the specificCultures array. The second statement adds a PropertyGroupDescription based on the ‘Parent’ property to the GroupDescriptions collection of ICollectionView. This has the effect of putting items having the same value for the CultureInfo.Parent property next to each other. But there is more, we can define a header for the groups.

<ComboBox …>

    <ComboBox.GroupStyle>

        <GroupStyle>

            <GroupStyle.HeaderTemplate>

                <DataTemplate>

                    <Border>

                        <!– Styling code omitted for brevity –>

                        <TextBlock Text="{Binding Name}" HorizontalAlignment="Center" />

                    </Border>

                </DataTemplate>

            </GroupStyle.HeaderTemplate>

        </GroupStyle>

    </ComboBox.GroupStyle>

</ComboBox>

We define the header by setting the GroupStyle property of the item control to a GroupStyle object, and setting the HeaderTemplate of this GroupStyle to a DataTemplate object. The ‘Name’ property to which the Text property of the TextBlock is bound is actually a property of PropertyGroupDescription.

The following screenshot shows how grouped items are displayed in the ComboBox.

ComboBox With Grouping

ICollectionView also supports sorting. Sorting is achieved by adding a SortDescription to the SortDescriptions property of ICollectionView.

culturesCollectionView.SortDescriptions.Add(

    new SortDescription("Name", ListSortDirection.Ascending));

Here the sort is ascending and is based on the value of the ‘Name’ property (CultureInfo.Name).

Download the source code and binaries of the Culture Info project.
Run Culture Info (Works only for Internet Explorer with XBAPs enabled).

Posted in Small Software Projects | Tagged: , , , | Leave a Comment »

ConvertSourceToHtml

Posted by Bassem Mohsen on May 23, 2011

Download ConvertSourceToHtml from CodePlex.
This project is based on CopySourceAsHtml 3.0.
This project uses the NumericUpDown control form the MSDN samples.

Motivation

I spent some time searching for a way to display code with nice formatting and syntax highlighting in my website. I found many server-side and client-side scripts that performed the formatting and highlighting dynamically, but did not like them. I thought this is too much unnecessary complexity. Styling should be done by static HTML and CSS. Plus the tools could not recognize type names to apply a special formatting to them. I also found ‘online syntax highlighters’ where you paste your source code and the tool generates HTML that you can place in your website or blog. These tools were still unable to recognize class names.

Finally I found CopySourceAsHtml. A Visual Studio plugin that takes formatted and highlighted code from Visual Studio in RTF format and converts this RTF to HTML then places the HTML in the clipboard. This plugin gives perfect results. Only one problem, I am using the Express editions of Visual Studio which do not support plugins. Fortunately CopySourceAsHtml is an open source project, so I was able to modify the source code to make it work as a standalone program. I called the standalone version ConvertSourceToHtml.

Using the Program

The program replaces RTF code in your clipboard by HTML code when you click on the ‘Convert’ button. So you will keep ConvertSourceToHtml open, copy from Visual Studio, click ‘Convert’, then paste in your HTML editor.

convert-source-to-html-main-window

The program has settings that enable you to control some aspects of the HTML output. Some settings can be changed from the program GUI, for example the settings that determine whether line numbers should be included, the number of the first line, the background color and whether to alternate the background color.

ConvertSourceToHtml settings window

Other more advanced settings like the CSS rules for the container HTML element can only be changed by editing the Settings.settings file in Visual Studio and recompiling the program. I know this is not very convenient and I am sorry about that.

The Program Architecture

The Most important namespaces in the ConvertSourceToHtml project are ClipboardUtilities, Conversion, and Conversion.HtmlCodeElements.
The ClipboardUtilities namespace contains the classes responsible for reading RTF data from the clipboard and writing HTML data to the clipboard.
The Conversion namespace contains the classes responsible for parsing RTF code and generating HTML code.
The Conversion.HtmlCodeElements namespace contains the classes that represent HTML code elements like HtmlStyle and HtmlLine.
ConvertSourceToHtmlCustomControls is a separate assembly for the custom controls used in the program. The assembly contains only the NumericUpDown control.

Binding WPF Controls to Application Settings

The technique I used to bind the controls in the SettingsWindow to the application settings deserves a section to document it because there is a very good chance I will use this technique again.

The Settings class is contained in the namespace ConvertSourceToHtml.Properties, so to use this class in XAML, an XML namespace prefix must be created for the CLR namespace.

<Window

        xmlns:props="clr-namespace:ConvertSourceToHtml.Properties"

        … >

Next we bind the appropriate property of the control to the property representing the setting.

<TextBox Name="fontSizeTextBox" Width="30"

         Text="{Binding Source={x:Static props:Settings.Default}, Path=FontSize,

                        Mode=TwoWay, UpdateSourceTrigger=Explicit}" />

The control will display the value of the setting and update the value of the setting, this is why the Binding Mode was set to TwoWay. But we want to update the data source only after the ‘Save Settings’ button is clicked and after the form data is validated, so we set the Binding.UpdateSourceTrigger property to Explicit (it is LostFocus by default for the TextBox control).

To update the binding source we must extract the binding from the control property and call BindingExpression.UpdateSource(). The following method does exactly that.

private void UpdateBindingSource(FrameworkElement element, DependencyProperty property)

{

    BindingExpression bindingExpression = element.GetBindingExpression(property);

    bindingExpression.UpdateSource();

}

Now updating the binding source (after performing the necessary validation) is as simple as making the following method call.

UpdateBindingSource(fontSizeTextBox, TextBox.TextProperty);

Thanks to ValueConverters, it is possible to present the setting value to the user in a way that is different from how it is stored. All you need is to implement an IValueConverter.

[ValueConversion(typeof(double), typeof(double))]

public class FractionToPercentageConverter : IValueConverter

{

    #region IValueConverter Members

 

    public object Convert(object value, Type targetType, object parameter,

        System.Globalization.CultureInfo culture)

    {

        return ((double)value) * 100;

    }

 

    public object ConvertBack(object value, Type targetType, object parameter,

        System.Globalization.CultureInfo culture)

    {

        return (double.Parse(value.ToString())) / 100;

    }

 

    #endregion

}

And specify that IValueConverter in the binding expression.

<Window.Resources>

    …

    <local:FractionToPercentageConverter x:Key="fractionToPercentageConverter" />

</Window.Resources>

<uc:NumericUpDown

                  Value="{Binding Source={x:Static props:Settings.Default},

                                  Path=AlternateBackgroundColorAdjustment,

                                  Mode=TwoWay, UpdateSourceTrigger=Explicit,

                                  Converter={StaticResource fractionToPercentageConverter}}"

                  … />

This allows the user to see and edit the setting value as a percentage while it is stored as a fraction between 0 and 1.

Update: CopySourceAsHtml was not updated for Visual Studio 2010. The solution for making it work with VS 2010 increases the Visual Studio startup time considerably. I think ConvertSourceToHtml is a good alternative to CopySourceAsHtml for VS 2010 users.

Download ConvertSourceToHtml from CodePlex.
This project is based on CopySourceAsHtml 3.0.
This project uses the NumericUpDown control form the MSDN samples.

Posted in Small Software Projects | Tagged: , , | 2 Comments »

Fast Paste

Posted by Bassem Mohsen on May 10, 2011

Click here to download the source code and binaries of the Fast Paste project.
This project uses icons from the FamFamFam free icon library.

Introduction

People responsible for email response handling often have a set of commonly used sentences that they paste into their response messages. The WPF commanding system gave me an idea of a simple text editor that can help these people do their job faster. This application was built primarily to explore the commanding feature of WPF.

Using the Program

Fast Paste window

Most of the program commands can be invoked either from the top menu or from the toolbar buttons or using key gestures. For example to invoke the ‘open document’ command you select File > Open… or you use the toolbar button with the folder icon or you use the key gesture Ctrl+O. To paste the predefined string number 5 you select Edit > Paste Predefined > string 5 or you use the ‘5’ toolbar button or you use the key gesture Ctrl+5. Predefined strings come from a file ‘Strings.txt’ in the program’s working directory.

Program Architecture

The DocumentManager class contains methods for opening and saving documents, and methods for editing the document text.
The EditorWindow class handles the user input and forwards most of the user commands to the DocumentManager class.
The CustomCommands static class contains the definitions of the commands that are needed by the program and not predefined in the .NET Framework.
The StringManager class wraps the array of predefined strings loaded from ‘Strings.txt’.

Cut, Copy and, Paste Commands – The Framework Does It All!

WPF provides static objects to represent the cut, copy, and paste commands. These objects are available through the static properties of the ApplicationCommands class: ApplicationCommands.Cut, ApplicationCommands.Copy, ApplicationCommands.Paste. WPF also associated the key gestures Ctrl+X, Ctrl+C, and Ctrl+V to the cut, copy, and paste commands respectively.

The functionality to handle these commands is built into the TextBox control. So you do not have to do anything for TextBoxes in your application to support cutting, copying, and pasting using key gestures.

In my application, I wanted to give the user more options to invoke the cut, copy, and paste commands. So I provided menu items and toolbar buttons for invoking these commands. This was as simple as adding the Command="ApplicationCommands.*" attribute to the Button and MenuItem controls.

<Button Command="ApplicationCommands.Cut" …

<Button Command="ApplicationCommands.Copy" …

<Button Command="ApplicationCommands.Paste" …

<MenuItem Command="ApplicationCommands.Cut" />

<MenuItem Command="ApplicationCommands.Copy" />

<MenuItem Command="ApplicationCommands.Paste" />

CommandBinding and Implementing the Command Handlers Yourself

Usually, you have to write the logic that handles the command yourself. You associate the command to the method that handles the command using a CommandBinding object. This CommandBinding object should be added to the CommandBindings collection of the command source or one of its ancestors.

To handle the ApplicationCommands.New command, I added the following method to the code behind (note the method signature)

private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)

{

    _documentManager.CreateNew();

}

And in the XAML file, I added a CommandBinding to the CommandBindings collection of the Window class

<Window.CommandBindings>

    <CommandBinding Command="ApplicationCommands.New" Executed="NewCommand_Executed" />

    …

</Window.CommandBindings>

Associating Input Gestures With Commands

MouseBinding and KeyBinding objects (both inherited from InputBinding) can be used to associate input gestures with commands. InputBinding objects are added to the InputBindings collection of a UIElement.

For example to associate the CopyAll command with the key gesture Ctrl+Shift+C I added a KeyBinding objects to the KeyBindings collection of the Window class.

<Window.InputBindings>

    <KeyBinding Command="local:CustomCommands.CopyAll" Key="C"Modifiers="Control+Shift" />

    …

</Window.InputBindings>

Custom Commands

If the .NET Framework does not have a command the suits your need, you can define your own command. You do that by instantiating the class RoutedUICommand. It is a good idea to expose your command object through a static property to make sure that only one instance of your command exists.

Here is how I defined the CopyAll command

private static RoutedUICommand _copyAll = new RoutedUICommand(
    "Copy All", "Copy All", typeof(CustomCommands));

public static RoutedUICommand CopyAll

{

    get

    {

        return _copyAll;

    }

}

Using Command Parameters

You can pass data from the command source to the command handler. The common command sources: Button, MenuItem, and InputBinding support the CommandParameter property. The value of CommandParameter is passed to the command handler and can be retrieved using the ExecutedRoutedEventArgs.Parameter property.

Here is how I passed the index of the predefined string to be pasted from the command source

<KeyBinding Command="local:CustomCommands.PastePredefined" CommandParameter="6" Key="D6"
            Modifiers="Control" />

<Button Command="local:CustomCommands.PastePredefined" CommandParameter="6">6</Button>

And here is how I retrieved and used it in the command handler

private void PastePredefinedCommand_Executed(object sender, ExecutedRoutedEventArgs e)

{

    int stringIndex = int.Parse(e.Parameter.ToString());

    _documentManager.PastePredefinedString(stringIndex);

 

    e.Handled = true;

}

Enabling and Disabling Commands

The CommandBinding.CanExecute event is raised to check whether the command associated with the CommandBinding can be executed. You can handle this event to provide the logic that determines whether the command can be executed. In your event handler you set CanExecuteRoutedEventArgs.CanExecute to true to enable the command and you set it to false to disable the command.

In my application, I wanted the CopyAll command to be enabled only when theTextBox is not empty. So I registered an event handler for the CommandBinding.CanExecute event.

<CommandBinding Command="local:CustomCommands.CopyAll" Executed="CopyAllCommand_Executed"

                CanExecute="CopyAllCommand_CanExecute" />

And in the event handler, I set CanExecuteRoutedEventArgs.CanExecute to enable or disable the command based on my condition.

private void CopyAllCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)

{

    if (theTextBox != null// The CanExecute event is raised before the TextBox object is created.

        e.CanExecute = !string.IsNullOrEmpty(theTextBox.Text);

}

Click here to download the source code and binaries of the Fast Paste project.
This project uses icons from the FamFamFam free icon library.

Posted in Small Software Projects | Tagged: , | Leave a Comment »