Copied from my WordPress blog. As with everything, this may not be the best way to do things.
people kept asking for. They're a little more updated than when this tutorial was written. Read the "tutorial" if you dare.
Hmm…here’s another basic “tutorial” using WPF. As I’ve said before…WPF is a really cool technology that gives you endless possibilities when it comes to customization. Recently…I was charged with completing a project which dealt with some basic data processing (healthcare referrals). One of the fields that needed to be input was the referring provider’s (that’s a doctor/physician) name. Well, some might say - “Why not just make that a drop downlist/combo box?” — but that’s not feasible in this case. People move into and out of our business/hospital everyday — not to mention a large number of the providers are contractors (meaning they could just work a day…or a year…or a day…and then come back a year later). Hopefully, you get my drift. Personnel fluctuations and changes make it nigh on impossible to have an updated list of currently working providers — even HR has a hard time keeping up with “who’s here”.
But anyways…none of that is important. So let’s make a basic AutoComplete Textbox using WPF. The coolest thing about WPF is that you can inherit your custom controls from ANY (I think) pre-existing control. So you could, in theory, add any kind of missing functionality/feature to anything Microsoft has been so eager to provide for you. Now, the first thing you’ll want to do is fire up you copy of Visual Studio and use the Custom Control Library Template. You don’t _have_ to create a custom control library — you can actually create a custom control using a pre-defined control that’s already in a your project. All you have to do is define a x:Class property in the XAML…and then create a partial class of that same namespace/type in a seperate code-behind file.
After you’ve created your project, you need to modify the XAML of your custom control. By default, you custom control’s base class is set to derive from UserControl — meaning it starts with <UserControl …> and ends with </UserControl>. Developers familiar with older versions of WPF know/can tell you that the code-behind file for custom controls used to explicitly include the UserControl class in its inheritance chain. The base class of your control can be set to any control that you want it to be. This means if you change the UserControl to some other class, when you go to edit the partial class of your custom control, all the parent class’ methods, properties, etc. should be visible or overrideble.
To make an autocomplete box, we’re going to want to change our base class to Canvas. If you’re going to make a custom control that uses multiple controls, the you need derive your control from a control that inherits from Panel. This gives you the ability to control the layout of your controls a lot better. I would not recommend inheriting from Textbox, and trying to add a ComboBox “child” control using the Visual.AddVisualChild method. If you do, you’ll probably find it difficult (by difficult…I mean impossible) to set/change the ComboBox’s z-Index.
So after you’ve changed your base class to Canvas, it’s time to add a TextBox and a ComboBox. There are a couple of ways to do this. Option 1: Place the controls directly into the XAML. Or…the option that I find to be a tad-bit harder (but better for a “tutorial”)…just add the controls from the code-behind file. Hmm…so to facilitate Option 2, there are a couple of topics that we need to briefly touch upon.
Since we’re going to add controls to a Panel-based control and we want to control the Z-Index of only two control, it’s best to to just add them using a VisualCollection. Using a VisualCollection is like adding controls using the AddVisualChild method, but it requires that you override a couple of your control’s properties. Using a VisualCollection gives you more control over the child controls than using AddVisualChild. You can specify their size and layout.
So, let’s add some private objects to our custom control.
private VisualCollection vcControls;
private ComboBox cbWordList;
private TextBox tbInput;
As I said before, you’re going to need to override some basic properties of your control if you decide to use a VisualCollection. The first property you need to override is the VisualChildrenCount that is inherited from the Visual class. When your control is added to another Page/Window, it will first ask for the number of visual children so that it can loop through them, and display them. Let’s override this property to return the number of controls in our VisualCollection.
protected override int VisualChildrenCount { get { return vcControls.Count; } }
Next we need to override the GetVisualChild method — also inherited from the Visual class. This method is supposed to return a child control given an index. We’re going to make this method return the given index of our VisualCollection.
protected override Visual GetVisualChild(int index) { return vcControls[index]; }
And the last method we need to override is the ArrangeOverride method that is inherited from FrameworkElement. This method is called when the the window/page is first loaded in order to determine the necessary size of a control. It’s also called whenever the page/window is resized — this is when WPF makes use of its fancy vector graphics. When this method is called, we’re going to to want resize our TextBox and ComboBox accordingly. So we call the Arrange methods of our child controls in order to set it to the proper size.
protected override Size ArrangeOverride(Size arrangeSize)
{
tbInput.Arrange(new Rect(arrangeSize));
cbWordList.Arrange(new Rect(arrangeSize));
return base.ArrangeOverride(arrangeSize);
}
Now that we’ve set all the necessary overrides, we need to actually initialize our VisualCollection, and add our child controls. First, before the InitializeComponent method is called in the constructor of our control, we need to call the constructor for our VisualCollection. The VisualCollection constructor needs another Visual-derived class to act as a parent. So we’re obviously going to make our control the parent.
vcControls = new VisualCollection(this);
this.InitializeComponent();
Now we need to initialize the child controls and their properties.
cbWordList = new ComboBox();
cbWordList.IsSynchronizedWithCurrentItem = true;
//set the property so that the ComboBox can’t be “tabbed” to
cbWordList.IsTabStop = false;
//use this event to complete the the TextBox’s text
cbWordList.SelectionChanged += new SelectionChangedEventHandler(cbWordList_SelectionChanged);
tbInput = new TextBox();
//use this event to see if the text that’s been enter so far matches some pre-configured word list
tbInput.TextChanged += new TextChangedEventHandler(tbInputBox_TextChanged);
Now it’s time to add the controls to the VisualCollection.
vcControls.Add(cbWordList);
vcControls.Add(tbInput);
I’m not going to include the events because that should be up to you to implement. Basically, all you need to do is find all the words that start with the text in the TextBox on a TextChanged event and load them into the ComboBox (and then display the ComboBox) — and when the user changes the SelectedItem of the ComboBox, complete the text of TextBox with that item.
So there…that’s your tutorial.