Introduction
WPF is a really powerful user interface, but certainly it has been released lacking certain basic controls for 'normal' business applications.
Here we are going to explain how we have implemented these 'holes', but as time goes on and the Microsoft guys have released their own version, our intention is to deprecate our own and change it for the new one.
These controls are primitives used by some EntityControls but are also usable in other contexts.
Some examples in this page assume you have a xmlns declaratin like this in your xaml file:
xmlns:m="clr-namespace:Signum.Windows;assembly=Signum.Windows"
AutoCompleteTextBox
AutoCompleteTextBox is a TextBox with a ListBox in a Popup that appears. You write text, filling the list from an external source of possible values.
By double-clicking on an element in the Pop-up (or pressing Enter) the element becomes the SelecteItem, since any kind of object can be returned by the lock up event, SelectedItem is defined as an object.
public partial class AutoCompleteTextBox : Grid
{
public string Text {...}
public object SelectedItem {...}
public int Threshold {...}
public int Delay {...}
public event RoutedEventHandler SelectedItemChanged {...}
public event RoutedEventHandler RealLostFocus {...}
public event Func<string, IEnumerable> AutoCompleting {...}
}
- Text: Get/set Text in the inner TextBox.
- SelectedItem: The element selected in the list.
- Threshold: Minimum lenth of Text to start searching for results. Default is 0.
- Delay: Time (in milliseconds) from the last key stroke to start searching, to avoid searching while user writes text. Default is 300.
- SelectedItemChanged: Event raised when the user picks an element in the pop-up (double click or enter).
- RealLostFocus: Event raised then the focus is lost in the TextBox and on the Popup (dealing with Popup is hard in WPF).
- AutoCompleting: The actual locking up function for you to implement that retrieves some objects for a given string.
Example
Let's code a very simple AutoCompleteTextBox for your directory tree.
In our Xaml:
<m:AutoCompleteTextBox
x:Name="tbPath"
AutoCompleting="AutoCompleteTextBox_AutoCompleting"
SelectedItemChanged="AutoCompleteTextBox_SelectedItemChanged" />
Using a little bit of Linq and the System.IO API we implement AutoCompleting like this:
private IEnumerable AutoCompleteTextBox_AutoCompleting(string arg)
{
if (string.IsNullOrEmpty(arg))
return null;
string dir = System.IO.Path.GetDirectoryName(arg);
if (string.IsNullOrEmpty(dir))
return null;
string file = System.IO.Path.GetFileName(arg);
DirectoryInfo di = new DirectoryInfo(dir);
var directories = di.GetDirectories(file + "*").Select(a => a.FullName);
var files = di.GetFiles(file + "*.*").Select(a => a.FullName);
return directories.Concat(files).ToArray();
}
And finally, when SelectedItemChanged is raised, we set Text and focus to continue writing:
private void AutoCompleteTextBox_SelectedItemChanged(object sender, RoutedEventArgs e)
{
tbPath.Text = (string)tbPath.SelectedItem;
tbPath.Focus();
}
The end result looks like this:
ColorPicker
ColorPicker is just a drop-down control with a
HSV Color picker that allows fast selection of colors.
It contains three simple dependency properties:
public class ColorPicker : Control
{
public Color SelectedColor {...}
public bool IsReadOnly {...}
public bool IsEditable {...}
(...)
}
- SelectedColor: The actual System.Windows.Media.Color that is selected.
- IsReadOnly: When true, the SelectedColor can't be changed from the user interface.
- IsEditable: Enables free text modification using the TextBox.
Example
Let's bind a Border Background property to the SelectedColor of a ColorPicker.
<Border Margin="10" Background="{Binding SelectedColor, ElementName=cp, Converter={x:Static m:Converters.ColorBrushConverter}}"/>
<m:ColorPicker x:Name="cp" SelectedColor="Red" />
Note that, since Background property is defined as a Brush we need to use a converter. Take a look at what Signum.Windows contributes to converters
here.
ColorPicker has full alpha support, the following example we have added a checker bachground to our border to show it. This is the end result:
NumericTextBox
A NumericTextBox extends TextBox to allow easy manipulation of numeric values.
Internally it just uses a
Converter to convert string to decimal and vice-versa. So it doesn't force you to write only numeric characters (allowing Copy-Paste), but will be boxed with a red square if the input is not a valid number.
public class NumericTextBox : TextBox
{
public decimal? Value {...}
public decimal XIncrement {...}
public decimal YIncrement {...}
public bool ShowAnchor {...}
public NullableDecimalConverter NullableDecimalConverter {...}
}
- Value: Returns the TextBox text converted to decimal if possible, null otherwise.
- XIncrement: Fixes the amount of increment when the anchor is dragged horizontally (if visible) or Shift+Up/Shift+Down keys are pressed. Default value is 0.1m.
- YIncrement: Fixes the amount of increment when the anchor is dragged vertically (if visible) or Up/Down keys are pressed. Default value is 1.0m.
- ShowAnchor: Shows an spheric anchor in the left of the TextBox that increments the value in XIncrement when dragged horizontally, and YIncrement when dragged vertically.
- NullableDecimalConverter: Get and set the current NullableDecimalConverter, a mixture of IValueConverter and ValidationRule to make the string to decimal conversions and notify if it's not possible errors. Default is NullableDecimalConverter.Number.
NullableDecimalConverter class contains three readonly static fields with NullableDecimalConverter instances already created:
- Number: Uses
"0.00" format and NumberStyles.Number for the conversion. - Integer: Uses
"0" format and NumberStyles.Integer for the conversion. - Currency: Uses
"N" format and NumberStyles.Currency for the conversion.
but feel free to write your own if necessary.
Example
Here we are going to bind and slider with a NumericTextBox. It's that simple:
<Slider Value="{Binding Value, ElementName=ntb}" Minimum="0" Maximum="400"/>
<m:NumericTextBox Value="100" x:Name="ntb"/>
The end result is that you can modify the value using the slider, the NumericTextBox anchor, using Up/Down or Shift+Up/Shift+Down on the TextBox.

Or manually introducing the number (it will be marked as incorrect if it's not a valid number).

Finally, you can change the NullableDecimalConverter and use Integer like this:
<m:NumericTextBox Value="100" x:Name="ntb" NullableDecimalConverter="{x:Static m:NullableDecimalConverter.Integer}"/>
MonthCalendar
MonthCalendar, based on
Kevin's Bag O Tricks, allows you to pick a date in a calendar, a unforgivable missed feature in WPF.
There are some changes with Kevin's MonthCalendar though:
- Different style, imitiating Silverlight date controls.
- Remove selection of Data ranges, for simplicity.
- Integrate in Signum.Windows (namespaces and stuff).
Here are the more important properties and events of MonthCalendar control:
public class MonthCalendar : Control
{
public DateTime? SelectedDate;
public DayOfWeek FirstDayOfWeek;
public DateTime MinDate;
public DateTime MaxDate;
public DateTime VisibleMonth;
public bool ShowsTitle;
public bool ShowsWeekNumbers;
public bool ShowsDayHeaders;
public event RoutedPropertyChangedEventHandler<DateTime?> SelectedDateChanged
public event RoutedPropertyChangedEventHandler<DateTime> VisibleMonthChanged
}
- SelectedDate: The actual selected date. Null if nothing is selected. Default is null.
- FistDayOfWeek: The day of the week that will be first in the calendar, default is current culture's FirstDayOfWeek.
- MinDate: Minimum date shown in the calendar. Default is 1-1-1752.
- MaxDate: Maximum date shown in the calendar. Default is 31-12-9998.
- VisibleMonth: Some day in the current shown month (not guaranteed day 1). Default is DateTime.Today.
Example
Let's see three MonthCalendar controls with different show options:
<StackPanel Orientation="Horizontal">
<m:MonthCalendar Margin="10" VerticalAlignment="Top" ShowsDayHeaders="True" ShowsTitle="True" ShowsWeekNumbers="True" />
<m:MonthCalendar Margin="10" VerticalAlignment="Top"/>
<m:MonthCalendar Margin="10" VerticalAlignment="Top" ShowsDayHeaders="False" ShowsTitle="False" ShowsWeekNumbers="False"/>
</StackPanel>
DateTimePicker
DateTimePicker is a drop-down control with a TextBox for writing dates and a MonthCalendar inside of the Popup. It's usefull for selecting a date, just like MonthCalendar, but it takes much less space and allows you to write the date manually.
Here are the most important properties in DateTimePicker class:
public class DateTimePicker: Control
{
public string Text;
public DateTime? SelectedDate;
public bool IsReadOnly;
public bool IsEditable;
public DateTimeConverter DateTimeConverter;
}
- Text: Get/set Text in the inner TextBox.
- SelectedDate: The actual selected date. Null if nothing is selected. Default is null.
- IsReadOnly: When true, the SelectedColor can't be changed from the user interface.
- IsEditable: Enables free text modification using the TextBox.
- DateTimeConverter: Get and set the current DateTimeConverter, a mixture of IValueConverter and ValidationRule to make the string to DateTime conversions and notify it's not possible. Default is DateTimeConverter.DateAndTime.
DateTimeConverter class contains two readonly static fields with DateTimeConverter instances already created:
- DateOnly: Uses
CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern for the conversion and validation. - DateAndTime: Use
ShortDatePattern + " " + ShortTimePattern for the conversion and validation.
but feel free to write your own if necessary.
Example
Let's see a small example of two DateTimePicker controls, one using DateAndTime converter (default) and the othe explicitly using DateOnly Converter.
<StackPanel>
<m:DateTimePicker />
<m:DateTimePicker DateTimeConverter="{x:Static m:DateTimeConverter.DateOnly}" />
</StackPanel>
And the end result:
ImageButton
ImageButton control extends Button with an image that will be placed on a 16x16 px square on the left of the button. These buttons are used on
EntityWindows and
Search.
ImageButton class couldn't be simpler:
public class ImageButton : Button
{
public ImageSource Image;
}
Example
Just a pair of buttons:
<StackPanel Orientation="Horizontal" Height="32" Width="264">
<m:ImageButton Margin="4" Image="save.png" Content="Save" Width="70" IsDefault="true" />
<m:ImageButton Margin="4" Image="open.png" Content="Open" Width="70" />
</StackPanel>
The result: