views:

29

answers:

2

In the past, I developed a customized combo box in win forms which implements auto complete behavior where the matched portion of the text is highlighted in blue, whilst the rest of the string has the normal background color. In win forms this can be done fairly simply using OwerDraw mode. I need to do similar kinds of things for WPF controls. I know that in WPF templates can be used to customize how controls are displayed but as templates are declarative in nature I'm not sure how this would work - I need to change the way the text is drawn based on the internal state of the control. I realize I will to do some reading to figure this out but as WPF is a big topic I'd appreciate some pointers in the right general direction so I know where to start looking.

A: 

In WPF, look of the control is performed by a combination of templates, styles and sometimes style selectors. If you want to change the look of a control based on the state of some data (it could be internal or external to the control, it doesn't really matter), then you can bind style values to this data and when it changes, the look of the control changes (provided that there is a notification mechanism to communicate the change). You can also transform data values by way of types called value converters (IValueConverter).

As a simple example, we can change the text style of the text block based on an underlying data value:

// In a C# class
public class MyState : INotifyPropertyChanged
{
     public bool IsEmphasized
     {
         get { return _isEmphasized; }
         set 
         { 
             if (_isEmphasized == value) 
             { 
                 return; 
             } 

             _isEmphasized = value;
             OnPropertyChanged("IsEmphasized"); // This is how to notify that the data is updated
     }
}


// A converter
public class BooleanToBoldConverter : IValueConverter
{
    public Object ConvertTo(Object value)
    {
        if (value is bool)
        {
             if ((bool)value)
             {
                 return FontWeights.Bold;
             }
             else 
             {
                 return FontWeights.Normal;
             }
        }
    }
}

<TextBlock DataContext="{Binding Source={StaticResource myStateInstance}}" 
           FontWeight="{Binding IsEmphasized, Converter={StaticResource BooleanToBoldConverter}}" Text="Text" />

While this is a simple example, and some details are elided, the main idea here to understand is that we can drive the UI from data values bound to properties and styles in a declarative way. We don't need to do the actual drawing.

codekaizen
In this example you are binding an existing control property to a some data. In the example of the auto complete combo box I would need to change the drawing behavior of the text box (but not the items in the drop down list) of the combo. There isn't an existing widget that has the right property so do I need to make one? Maybe something like a TextBlock with and integer property called HighlightUpToThisIndex? (continued below).
Shane
Also, I need to create a new reusable self contained combo box - in win forms you could create an inherited control for customizations of existing ones. How does this work in WPF? Maybe what I want to do is a just a more complicated version of what you have described but I'm yet to be convinced. I think I just don't know enough about WPF yet. Am currently reading WPF Control Development Unleashed - maybe this will help.
Shane
I had a look at the code for ComboBox using reflector. There is very little code to do with UI most of the code is to do with behavior, so as codekaizen mentions, the is a strong separation between behaviour and appearance. Still, I think customizing the behavior of exiting controls can be challenging as controls may not always provide public hooks at the level of detail you need.
Shane
A: 

The important thing to remember with WPF is that you don't issue drawing commands when told to paint, but rather inform the rendering system what types of shapes it should render. If you want to explore low-level drawing, took a look at the DrawingVisual class, which allows you to queue up rendering commands at a level similar to drawing on a WinForms canvas. As codekaizen mentioned, this is often not necessary in WPF, but it's good to know about if you have something particularly tricky that you'd like to encapsulate in a control or if you need to instantiate lots of these controls and need better performance.

Dan Bryant