Emulating OwnerDraw controls in WPF
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 de开发者_JS百科clarative 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.
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.
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.
精彩评论