#825 – Two Way Binding for a CheckBox

You can bind the IsChecked property of a CheckBox to a boolean variable, so that the variable will always reflect the current value of the CheckBox in the user interface.

You can also do two-way binding, where the boolean variable changes when the user toggles the CheckBox, but the CheckBox also toggles when the value of the variable changes.

        <Label Content="Things my dog can do:"/>
        <CheckBox Content="Sit" IsChecked="{Binding CanSit, Mode=TwoWay}"/>
        <CheckBox Content="Stay" IsChecked="{Binding CanStay, Mode=TwoWay}"/>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Button Content="Report State" Click="btnReportState_Click"
                    Margin="5"/>
            <Button Content="Change State" Click="btnChangeState_Click"
                    Margin="5"/>
        </StackPanel>

Code-behind:

    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private bool canSit;
        public bool CanSit
        {
            get { return canSit; }
            set
            {
                canSit = value;
                RaisePropertyChanged("CanSit");
            }
        }

        private bool canStay;
        public bool CanStay
        {
            get { return canStay; }
            set
            {
                canStay = value;
                RaisePropertyChanged("CanStay");
            }
        }

        public MainWindow()
        {
            this.InitializeComponent();
            this.DataContext = this;
        }

        private void btnReportState_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(string.Format("Sit: {0}, Stay: {1}", CanSit, CanStay));
        }

        private void btnChangeState_Click(object sender, RoutedEventArgs e)
        {
            CanSit = CanSit ? false : true;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

#635 – Using a Value Converter to Change User Input

Instead of modifying user input by handling the TextChanged event, you can use a value converter to change the text input.  Below, we bind the Text property of a TextBox to a string property and specify a converter, which will convert vowels to uppercase.

<Window x:Class="WpfApplication9.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication9"
        Title="TextChanged"
        Height="150" Width="400">

    <Window.Resources>
        <ResourceDictionary>
            <local:CapVowelsConverter x:Key="capVowelsConverter"/>
        </ResourceDictionary>
    </Window.Resources>

    <StackPanel Orientation="Vertical">
        <TextBox HorizontalAlignment="Center" Width="150" Margin="10"
                 Text="{Binding Path=MyText, Converter={StaticResource capVowelsConverter}, UpdateSourceTrigger=PropertyChanged}"/>
        <Button Content="What Is My Text?" HorizontalAlignment="Center" Margin="10" Click="Button_Click"/>
    </StackPanel>
</Window>

Here’s the code for the value converter:

    public class CapVowelsConverter : IValueConverter
    {
        // From bound property TO the control -- no conversion
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
        }

        // To bound property FROM the control -- capitalize vowels
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string input = (string)value;

            const string vowels = "aeiou";

            StringBuilder sbInput = new StringBuilder(input);
            for (int i = 0; i < sbInput.Length; i++)
            {
                if (vowels.Contains(char.ToLowerInvariant(sbInput[i])))
                    sbInput[i] = char.ToUpper(sbInput[i]);
            }

            return sbInput.ToString();
        }
    }


#495 – Binding to a Visibility Property Without Using a Value Converter

You can use a value converter to convert a string value to a value of type System.Windows.Visibility, allowing data binding to a Visibility property.  You can also just set a Visibility property directly to a string, avoiding the need for a value converter.

In the example below, we bind to the Content property of a ComboBoxItem, which we access through the SelectedValue property of a ComboBox.  Since Content contains a string, the binding to Visibility works without a conversion.

    <StackPanel>
        <StackPanel Orientation="Horizontal" Margin="10">
            <Label Content="Snoopy" Margin="3" Background="BurlyWood"/>
            <Label Content="Waldo" Margin="3" Background="Thistle"
                   Visibility="{Binding ElementName=cboVisibility, Path=SelectedValue.Content}"/>
            <Label Content="Dagwood" Margin="3" Background="LightGreen"/>
        </StackPanel>
        <ComboBox Name="cboVisibility" HorizontalAlignment="Center" SelectedIndex="0">
            <ComboBox.Items>
                <ComboBoxItem Content="Visible"/>
                <ComboBoxItem Content="Collapsed"/>
                <ComboBoxItem Content="Hidden"/>
            </ComboBox.Items>
        </ComboBox>
        <Label Content="Select visibility of middle Label" HorizontalAlignment="Center"/>
    </StackPanel>

#494 – Using a Value Converter to Bind to a Visibility Property

You can bind the Visibility property of a control to a data item whose type is System.Windows.Visibility.  You can also bind to an item whose type is string, provided that the string values returned represent one of the enumerated values from the Visibility type.

The example below shows how to use a value converter to convert from the SelectedValue of a ComboBox (a ComboBoxItem) to the Visibility type.

        <StackPanel Orientation="Horizontal" Margin="10">
            <Label Content="Snoopy" Margin="3" Background="BurlyWood"/>
            <Label Content="Waldo" Margin="3" Background="Thistle"
                   Visibility="{Binding ElementName=cboVisibility, Path=SelectedValue, Converter={StaticResource cboVisibilityConverter}}"/>
            <Label Content="Dagwood" Margin="3" Background="LightGreen"/>
        </StackPanel>
        <ComboBox Name="cboVisibility" HorizontalAlignment="Center" SelectedIndex="0">
            <ComboBox.Items>
                <ComboBoxItem Content="Visible"/>
                <ComboBoxItem Content="Collapsed"/>
                <ComboBoxItem Content="Hidden"/>
            </ComboBox.Items>
        </ComboBox>

Code for IValueConverter.Convert:

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Visibility visibility = Visibility.Visible;

            try
            {
                if (value != null)
                {
                    ComboBoxItem item = (ComboBoxItem)value;
                    visibility = (Visibility)Enum.Parse(typeof(Visibility), (string)item.Content, false);
                }
            }
            catch { }

            return visibility;
        }

#485 – Binding a ComboBox to an Enumerated Type’s List of Values

You can easily bind a ComboBox (or ListBox) to an enumerated type’s values using an ObjectDataProvider.  The ObjectDataProvider allows calling a method and then using the result of the method call as a binding source.

To get the list of values for an enumerated type, we call the Enum.GetValues method, passing in the specific enumerated type.  In the example below, we do this in an ObjectDataProvider.

    <Window.Resources>
        <ObjectDataProvider x:Key="dateTimeKindValues" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="sys:DateTimeKind"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>

(This assumes that we’ve defined the sys namespace):

    xmlns:sys="clr-namespace:System;assembly=mscorlib"

The ObjectDataProvider is equivalent to the following code:

            DateTimeKind[] values = (DateTimeKind[])Enum.GetValues(typeof(DateTimeKind));

We can now use the output of the ObjectDataProvider as a data source for our binding.

    <ComboBox Height="25" Width="150"
              ItemsSource="{Binding Source={StaticResource dateTimeKindValues}}"/>

This gives us a ComboBox that lists the possible values of the DateTimeKind enumerated type.

#397 – Rich ListBox Content Using Data Binding, part III

This post continues the example of displaying information about a series of movies in a ListBox, using data binding.

In previous posts, we created code for a Movie class and filled an ObservableCollection<Movie> with movie data.

To complete this example, we just need the XAML code.  Below is the XAML that defines a ListBox that contains the list of movies.  We set the ItemTemplate property to a DataTemplate that defines the layout of each item in the list.  We then use data binding to bind to properties of the Movie class.

        <ListBox ItemsSource="{Binding MovieList}" SnapsToDevicePixels="True">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Image}"/>
                        <StackPanel Orientation="Vertical">
                            <Label Content="{Binding Title}" FontWeight="Bold"/>
                            <Label Content="{Binding Year}"/>
                        </StackPanel>

                        <Border BorderBrush="Black" BorderThickness="0.5"/>

                        <StackPanel Orientation="Vertical">
                            <Label Content="Actors:"/>
                            <Label Content="{Binding ActorLead}" Margin="10,0"/>
                            <Label Content="{Binding ActressLead}" Margin="10,0"/>
                        </StackPanel>

                        <Border BorderBrush="Black" BorderThickness="0.5"/>

                        <StackPanel Orientation="Vertical">
                            <Label Content="Director:"/>
                            <Label Content="{Binding Director}" Margin="10,0"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

#396 – Rich ListBox Content Using Data Binding, part II

This post continues the example of displaying information about a series of movies in a ListBox, using data binding.

Last time, we showed the code for a Movie class, which stored data for a single movie.

The next step is to create some Movie instances and put them in a list, which we will then bind the ListBox to.  We start by adding a property containing a list of movies, which we will bind to.

        public ObservableCollection<Movie> MovieList { get; protected set; }

Next, we’ll add some code to set the data context of the main window to itself–which allows data binding GUI elements in the window to properties in the code-behind class that represents the window.

We also add code to the constructor to populate the list of movies.

        public MainWindow()
        {
            this.InitializeComponent();

            // Set data context of main window to itself, allowing to bind
            // elements in the GUI to properties in the code-behind.
            this.DataContext = this;

            // Populate movie list
            MovieList = new ObservableCollection<Movie>();
            MovieList.Add(new Movie("King Kong", 1933, new Uri(@"..\Images\KingKong-1933.png", UriKind.Relative), "Bruce Cabot", "Fay Wray", "Merian C. Cooper"));
            MovieList.Add(new Movie("The Gay Divorcee", 1934, new Uri(@"..\Images\GayDiv-1934.png", UriKind.Relative), "Fred Astaire", "Ginger Rogers", "Mark Sandrich"));
            MovieList.Add(new Movie("Captain Blood", 1935, new Uri(@"..\Images\CptBlood-1935.png", UriKind.Relative), "Errol Flynn", "Olivia de Havilland", "Michael Curtiz"));
            MovieList.Add(new Movie("Modern Times", 1936, new Uri(@"..\Images\ModTimes-1936.png", UriKind.Relative), "Charlie Chaplin", "Paulette Goddard", "Charlie Chaplin"));
            MovieList.Add(new Movie("Topper", 1937, new Uri(@"..\Images\Topper-1937.png", UriKind.Relative), "Cary Grant", "Constance Bennett", "Norman Z. McLeod"));
            OnPropertyChanged("MovieList");
        }

#395 – Rich ListBox Content using Data Binding, part I

In talking about the SnapsToDevicePixels property, I used as an example a ListBox that contained a list of movies.  Each entry in the ListBox had a number of data items related to the movie, including a thumbnail.

Let’s look at how to create this in WPF.  To start with, we need a class that stores information about an individual movie.  We’re going to use data binding to bind to instances of this class, and we want the binding to update when elements of the class change, so we implement the INotifyPropertyChanged interface.

    public class Movie : INotifyPropertyChanged
    {
        private string title;
        public string Title
        {
            get { return title; }
            set
            {
                if (value != title)
                {
                    title = value;
                    OnPropertyChanged("Title");
                }
            }
        }

        public int year;
        public int Year
        {
            get { return year; }
            set
            {
                if (value != year)
                {
                    year = value;
                    OnPropertyChanged("Year");
                }
            }
        }

        private Uri image;
        public Uri Image
        {
            get { return image; }
            set
            {
                if (value != image)
                {
                    image = value;
                    OnPropertyChanged("Image");
                }
            }
        }

        private string actorLead;
        public string ActorLead
        {
            get { return actorLead; }
            set
            {
                if (value != actorLead)
                {
                    actorLead = value;
                    OnPropertyChanged("ActorLead");
                }
            }
        }

        private string actressLead;
        public string ActressLead
        {
            get { return actressLead; }
            set
            {
                if (value != actressLead)
                {
                    actressLead = value;
                    OnPropertyChanged("ActressLead");
                }
            }
        }

        private string director;
        public string Director
        {
            get { return director; }
            set
            {
                if (value != director)
                {
                    director = value;
                    OnPropertyChanged("Director");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void OnPropertyChanged(string prop)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }

        public Movie(string title, int year, Uri image, string actorLead, string actressLead, string director)
        {
            Title = title;
            Year = year;
            Image = image;
            ActorLead = actorLead;
            ActressLead = actressLead;
            Director = director;
        }
    }

#370 – Binding a Label’s Content to the Current Date and Time, part II

You can bind a Label control’s Content property to the DateTime.Now property to display the current date or time, but the label will not update when the time changes.

To get a Label control that continuously updates with the current time, you can bind to a property that updates periodically and notifies us using the INotifyPropertyChanged interface.  We can do this by creating a timer that updates a DateTime property whenever it ticks.

Here’s the XAML:

        <Label Content="{Binding CurrentDateAndTime}" ContentStringFormat="Current time - {0:T}"/>

In the code-behind, we define the property and set up a timer.

        public DateTime CurrentDateAndTime { get; set; }

        public MainWindow()
        {
            this.InitializeComponent();
            this.DataContext = this;

            DispatcherTimer dayTimer = new DispatcherTimer();
            dayTimer.Interval = TimeSpan.FromMilliseconds(500);
            dayTimer.Tick += new EventHandler(dayTimer_Tick);
            dayTimer.Start();
        }

Whenever the timer fires, we update our property and fire the INotifyPropertyChanged.PropertyChanged event.

        void dayTimer_Tick(object sender, EventArgs e)
        {
            CurrentDateAndTime = DateTime.Now;

            PropertyChanged(this, new PropertyChangedEventArgs("CurrentDateAndTime"));
        }

The end result:

#369 – Binding a Label’s Content to the Current Date and Time

You can use data binding to assign the current date and time to a Label control.

You start by creating an instance of a DateTime object using the ObjectDataProvider tag.

    <Window.Resources>
        <ObjectDataProvider x:Key="today" ObjectType="{x:Type sys:DateTime}"/>
    </Window.Resources>

Note that we’re using a sys: prefix, which requires the following namespace declaration.

    xmlns:sys="clr-namespace:System;assembly=mscorlib"

We can now use data binding to bind to the DateTime.Now property.

        <Label Content="{Binding Source={StaticResource today}, Path=Now}" ContentStringFormat="Today is {0:D}"
               HorizontalContentAlignment="Center" Padding="10"/>
        <Label Content="{Binding Source={StaticResource today}, Path=Now}" ContentStringFormat="The time is {0:t}"
               HorizontalContentAlignment="Center" Padding="10"/>

The result will look like this:

This solution is not very good, since the binding happens just once, when the application starts.  Neither label will update when the date or time changes.  A better solution would be to bind to a property in a class that changes periodically, using the INotifyPropertyChanged interface.

Follow

Get every new post delivered to your Inbox.

Join 234 other followers