Use the numeric keypad decimal key as the numeric separator for all locales as in Excel

by Sébastien Van Bruaene 29. April 2009 04:15

If the locale specifies that the numeric separator is something else then '.' (e.g. ',' in Belgium) then the numeric keypad decimal key can not be used to enter a numeric separator in a WPF input control. However in applications like Excel this works. How can we do this in a WPF input control ? Very simple: we handle the PreviewKeyDown event and emulate the input of a numeric separator for that locale.

private static void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)

{

    if(e.Key == Key.Decimal &&

        NumberFormatInfo.CurrentInfo.NumberDecimalSeparator != ".")

    {

        var _this = (sender as TextBox);

        if(_this != null)

        {

            e.Handled = true;

 

            var eventArgs = new TextCompositionEventArgs(

                Keyboard.PrimaryDevice,

                new TextComposition(

                    InputManager.Current,

                    Keyboard.FocusedElement,

                    NumberFormatInfo.CurrentInfo.NumberDecimalSeparator))

                    {

                        RoutedEvent = ContentElement.TextInputEvent

                    };

 

            InputManager.Current.ProcessInput(eventArgs);

        }

    }

}

 

Currently rated 4.5 by 2 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

Bug in WPF combobox databinding

by Sébastien Van Bruaene 4. March 2009 06:22

Last week I exprienced an annoying bug in the WPF combobox databinding. One of the forms that I am developing consists of a master-detail view. The master is selected in a listview which is data bound to a list of contact person viewmodels. When selecting an item in the listview the databinding of the detail view changes to the viewmodel of the selected contact person. On the detail view there is a combobox of which the items are data bound to a list of countries and the selecteditem is data bound to the country of the contact person.

<ComboBox ItemsSource="{Binding Countries, Mode=OneWay}"
          SelectedItem="{Binding SelectedCountry}"        
          DisplayMemberPath="Name" >
</ComboBox>


The bug I experienced was that when switching to another contact person in the master listview and then switching back to the original contact person the selected country in my viewmodel was always set to null so the contact person's country was lost. I did not know were to start so I made a little test project to properly debug this. Debugging learnt me that after setting the data binding of the detail view the combobox SelectedItem data binding still held a reference to the previous viewmodel and set the Country property on my viewmodel to null.

I could not think of an easy fix but all of the sudden I had a lucky hunch. I switched the ItemSource and SelectedItem in the combobox XAML like this:

<ComboBox SelectedItem="{Binding SelectedCountry}"
          ItemsSource="{Binding Countries, Mode=OneWay}"
          DisplayMemberPath="Name" >
</ComboBox>

And tada everything worked as it should ...

I do not have a clue why it is like that, it is a WPF bug I guess. I will try to report it somewhere. Attached is my test project that reproduces and fixes the problem.

TestBindingError.zip (19.44 kb)

Currently rated 5.0 by 6 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

Viewing the default WPF styles and templates

by Sébastien Van Bruaene 19. February 2009 03:29

Sometimes it is very useful to view the default styles and templates in a WPF control, to get some inspiration for your own controls or just to understand something better. I used to use style snooper for this, a tool by Walt Ritscher. This worked out ok for me but I discovered there is an BAML viewer add-in available for .NET Reflector which makes the style snooper tool obsolete (.NET Reflector is an essential tool for any .NET developer, with it you can easily decompile .NET assemblies and view it's resources).

The BAML viewer plugin can be downloaded here. Just add to the add-ins in Reflector. Then open an assembly containing BAM, I use PresentationFramework.Aero.dll as an example. Make sure you open the BAML viewer.

 

 

The BAML viewer will show a list of all loaded assemblies that contain BAML. Just expand the resources and click on the BAML file and voila everything is there.

 

 

 

Isn't that great ? :) 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

Some experiences with Validation.ErrorTemplate

by Sébastien Van Bruaene 16. February 2009 23:20

Currently I am working on a WPF application. One of my targets for this sprint was to add Input validation for my input forms. I was already using data binding and the model-view-viewmodel (MVVM) pattern for my client. So I opted to use the data validation that is in WPF data binding. As data validation seemed something the model (and viewmodel) should do instead of the view I opted for the IDataErrorInfo interface. I decided to use this on two levels, the first being the viewmodel the second the model.

The viewmodel is responsible for validating the "input". An example of this would be a text box that is used to input dates. These can be different kinds of strings ("12/12/2008" , "12-12-08", ... ). I bind this text box to a string property in my viewmodel. The viewmodel validates this string and tries to convert it to a date in the model. The model is responsible for validating the "business" rules. An example for this is that a date should be greater then a certain minimum value. All of this is based on some great blog posts of Josh Smith, you can read about it there so I won't go into further detail.

In the GUI I wanted to show a red asterix next to a control that was in invalid state. Together with a red border around it and tooltips with some help on the asterix and the control.

 

 

This I could do easily using the Validation.ErrorTemplate attached property. This property gives you the possibility to link a WPF control template to your control. It will only be shown when the validation fails. Mine is actually quite similar to the default template I only added the red asterix. In the template you should add the AdornedElementPlaceholder element, this makes sure your original control will be shown.

 

    <ControlTemplate x:Key="ValidationTemplate">
        <DockPanel>
            <TextBlock Foreground="Red"
                       Margin="0,0,2,0"
                       Text="*"
                       VerticalAlignment="Center"
                       ToolTip="{Binding ElementName=MyAdorner, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"/>
            <Border BorderBrush="Red"
                    BorderThickness="1" >
                <AdornedElementPlaceholder Name="MyAdorner"/>
            </Border>
        </DockPanel>
    </ControlTemplate>

    <Style TargetType="{x:Type TextBox}" x:Key="ValidationTextBoxStyle" BasedOn="{StaticResource TextBoxBaseStyle}" >
        <Setter Property="Margin" Value="10,0,0,0" />
        <Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationTemplate}"  />
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}" />
            </Trigger>
        </Style.Triggers>
    </Style>

 

This system works exceptionally well but I encountered a problem that took some time to find a solution for so I wanted to share to solution with you ! :) The problem was that my error template did show up nicely but the next time that I entered the same form (I have some navigation framework that re-uses a form) the error template did not show up anymore. MDSN documentation did not give any clues so I was quite puzzled by this one.

The error template is drawn in the WPF "adorner" layer. That is some kind of special layer in WPF that is drawn over the normal GUI layer. In this layer you can draw extensions on top of your controls. If you want to make custom adorners these need to be in the adorner layer. You need to add this layer yourself by using the AdornerDecorator WPF tag (If you want more information on this here is a nice article). This was the key in solving my problem. I needed to add this tag somewhere in the root of my form and everything was working as it should.

 

<BusinessForm:ScrollableBusinessForm x:Class="Metanous.EurowasteClient.Controls.BusinessForm.CustomerDetailForm"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:BusinessForm="clr-namespace:Metanous.EurowasteClient.Controls.BusinessForm"
    Grid.IsSharedSizeScope="True">
    <AdornerDecorator>
        <Grid>


Some stuff here
 
        </Grid>
    </AdornerDecorator>
</BusinessForm:ScrollableBusinessForm>

 

If you think about it it makes sense but this is nowhere to be found in the MSDN docs about Validation.ErrorTemplate. It seems that without the keyword the adorner layer is added the first time you show a control/form but is discarded when you hide/minimize it.

Anyway this gave me some headache but in the end I have a nice validation framework.

P.S. My next post will probably be about our company's new toy, a MS surface computer ...

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

About the author

I am a software engineer / architect who spends most of his time working with Microsoft technologies (.NET / WPF / EF / SQL Server). I have worked in the healthcare sector for some time but nowadays I work for a great company called Metanous. 

I am very happily married but I have no children yet. For now I only have 4 rabbits and 4 chickens. My rabbits are of the "Vlaamse reus" breed, the biggest kind of rabbit in the world :)

In my spare time I play a little basketball and mini soccer (yes that is an actual sport).