AutoCompleteBox to auto complete data entry.

I ran into a situation where, I need a way to provide a user with auto complete text box with predefined list of data. If the data already exists in the list, then user select it and continue, if the data does not contain in the list, the user data will be added to the list thus it is available for the future auto completion. It is pretty simple, if you know there is a control called ‘AutoCompleteBox’ available in the toolkit.

In my case the auto completion is part of the grid, so I will stay on the same sample to illustrate how easy to implement this. This is a very rudimentary implementation and can be improved a lot to meet your needs.

First thing we start by adding a cell edit template to the the column in question where we need to provide the auto completion. A simple XAML definition would look like the following

 1: <c1:Column.CellEditingTemplate>
 2:     <DataTemplate>
 3:          <sdk:AutoCompleteBox Text="{Binding ReferencePath,Mode=TwoWay}"
 4:                Populating="tester_Populating" MinimumPrefixLength="0" IsDropDownOpen="True" LostFocus="tester_LostFocus"/>
 5:     </DataTemplate>
 6: </c1:Column.CellEditingTemplate>

There are few important pieces in line 4. The first one is the event called ‘tester_Populating’ event. This event, will filter the data collection and return only matching values as the user types to show in the drop down.

MinimumPrefixLength to 0 will show the drop down even when there is no data entered in the text box.

IsDropDownOpen set to true will open the drop down on double click on the cell.

LostFocus event will trigger a method to check and see if the data user enter already in the list and if it is not available then add it to the collection to show in the future.

Lets look at the events implementation

tester_Populating:

 1: private void tester_Populating(object sender, PopulatingEventArgs e)
 2: {
 3:      if (_names == null)
 4:      {
 5:           _names = new List<string>();
 6:           _names.Add("Unni");
 7:           _names.Add("Rani");
 8:           _names.Add("Unnikrishnan");
 9:           _names.Add("Jitin");
 10:       }
 11:       List<string> data = new List<string>();
 12:       AutoCompleteBox box = sender as AutoCompleteBox;
 13:       foreach (string name in _names)
 14:       {
 15:            if (name.ToUpper().StartsWith(box.Text.ToUpper()))
 16:                data.Add(name);
 17:       }
 18:       box.ItemsSource = data;
 19:       box.PopulateComplete();
 20: }

Line 3-10 to create first time collection. Line 13-17 is where you check and see if the user input data matches any in our collection and if so, then add it to temperory collection and binding it to auto complete box. As done in line 18.

 1: private void tester_LostFocus(object sender, RoutedEventArgs e)
 2: {
 3:      AutoCompleteBox box = sender as AutoCompleteBox;
 4:      if (box.Text.Length > 0)
 5:      {
 6:          bool found = false;
 7:          foreach (string name in _names)
 8:          {
 9:              if (name.ToUpper().Equals(box.Text.ToUpper()))
 10:             {
 11:                 found = true;
 12:                  break;
 13:              }
 14:           }
 15:           if (!found)
 16:             _names.Add(box.Text);
 17:    }
 18: }

Hope this helps someone.

Converter Parameter with bound variable

You will run into a situation where you need to convert a value based on another value in the object. As you would know by now, you can not use {Binding variable} in convert parameter. If you do, even though you will not any compilation error, you will get run time error. So how do we do that. You can pass static variable in the convert parameter.

So a simple work around for this problem would be to bind as following in your XAML.

 <c1:Column Header="Amount" Binding="{Binding Converter={StaticResource myConverter}, ConverterParameter=Amount}" GroupAggregate="Sum" Width="100"/>

 

In the above XAML instead of binding it to a object variable, I bound it to the row and then call my converter passing the string name of the column I am interested in.

   1:   public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   2:   {
   3:          Person p = value as Person;
   4:          if (p.Amount < 0 && p.Name.Equals("Unni"))
   5:             return p.Amount + p.Amount * p.Bonus;
   6:          else
   7:             return p.Amount;
   8:          return value;
   9:   }

In the above code as you can see, first thing I do, is to unbox the object to the class and in here it is ‘Person’ class. Once you do that, from there you have access to all the properties in the class for you in the Convert method.  In the above code, as you can see, if the name is “Unni’ then my salary would salary + bonus other wise just salary.

Digg This