#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.

#126 – Reacting to a Dependency Property Change Using Binding

One way to react to a dependency property’s value changing is by binding the property of one control to the property of another control.

The idea with binding is that there is a source object and property, where the data is coming from, and a target object and property.

Here’s an example where we bind the contents of a Label control to the value of a Slider.

        <Slider Name="slider1" Maximum="100" />
        <Label Name="lblTest" Content="{Binding ElementName=slider1, Path=Value}"/>

The Label is the target control.  We bind its Content property to the Slider control’s Value content.  When a user slides the slider, its value will change and the new value will be displayed in the Label.

Binding the property of one control to the property of another control

#25 – Data Binding Overview

Data binding is a core feature in WPF.  In a typical application, there is a presentation layer that contains the visual controls allowing a user to interact with the application and its data.  Below the presentation layer is typically a business layer, which contains the CLR objects that contain the actual data.  (There may also be a lower data layer where the data is persisted, e.g. a database).

As a user works with an application, there is an expectation that:

  • When data in the CLR objects changes, the changes are reflected in the GUI
  • When a user changes data via the GUI, the changes are replicated in the CLR objects

The data binding model in WPF automates this relationship by binding properties of a CLR object to user interface controls through a Binding object.

Follow

Get every new post delivered to your Inbox.

Join 129 other followers