Probably the most common question I get from people new to WPF is how to bind the Visibility
of a control based on a System.Boolean
value. WPF provides IValueConverter
in System.Windows.Data
specifically for converting one type to another and back when binding. Let's setup a very simple example.
/// <summary> /// ViewModel for MainWindow /// Assigned to MainWindow.DataContext in its class constructor /// </summary> internal class MainWindowDataContext : INotifyPropertyChanged { private bool _visible; public bool Visible { get { return _visible; } set { _visible = value; PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs("Visible")); } } } public event PropertyChangedEventHandler PropertyChanged; }
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525"> <Grid> <Button Visibility="{Binding Visible}" /> </Grid> </Window>
You should already know that line 7 doesn't work. There isn't a conversion from System.Boolean
to System.Windows.Visibility
. This is where IValueConverter
comes in, so we will make a new class that implements the interface and call it BoolToVisibilityConverter
.
internal class BoolToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (!(value is bool)) { throw new System.ArgumentException("value is not of type System.Boolean", "value"); } return (bool)value ? Visibility.Visible : Visibility.Hidden; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (!(value is Visibility)) { throw new System.ArgumentException("value is not of type System.Windows.Visibility", "value"); } switch ((Visibility)value) { case Visibility.Visible: return true; default: return false; } } }
The implementation is simple. When the binding gets the value from MainWindow.DataContext
(eg. MainWindowDataContext.Visible
) it is passed to the value
parameter of object Convert
. Then it's up to the convert method to return the appropriate value based on the parameter. In this case, we do a simple check to make sure the parameter is in fact a System.Boolean
value, and if it is we return the appropriate Visibility
enumeration value. Obviously, ConvertBack
does exactly the opposite when the value of the binding is set, and is propagated down to the data context. It takes a Visibility
value and converts it to a System.Boolean
value, which is assigned to MainWindowDataContext.Visible
.
Now we need to update our Xaml to use the converter. This is done by including it as a resource and specifying the Converter
attribute on the binding.
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.Resources> <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverterResourceKey"/> </Grid.Resources> <Button Visibility="{Binding Visible, Converter={StaticResource BoolToVisibilityConverterResourceKey}}" /> </Grid> </Window>
You can implement IValueConverter
any time you need to convert one type to another and back in a binding.
1 Comment
Leave a Comment
You must be logged in to post a comment.
Awesome, thanks!