#398 – WrapPanel Element

The WrapPanel element serves as a container for a collection of child elements, positioning its children in one of two ways:

  • In a horizontal orientation (the default).  Child elements are added left to right, until a row fills up, and then wrapped to the next row
  • In a vertical orientation.  Child elements are added top to bottom, until a column fills up, and then wrapped to the next column
    <WrapPanel Orientation="Horizontal">
        <Label Background="AliceBlue" Content="William I" />
        <Label Background="AntiqueWhite" Content="William II"/>
        <!-- etc -->
    </WrapPanel>

    <WrapPanel Orientation="Vertical">
        <Label Background="AliceBlue" Content="William I" />
        <Label Background="AntiqueWhite" Content="William II"/>
        <!-- etc -->
    </WrapPanel>

#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;
        }
    }

#394 – Specify Canvas Child Element Position Using Two Properties

When positioning child elements in a Canvas element, you can position the child element by specifying one or more of the properties: Left, Top, Right, Bottom.

In practice, the values of only two of these properties are ever used.  If Left and Right are specified, Right is ignored.  If Top and Bottom are specified, Bottom is ignored.

If neither Left nor Right are specified, a value of 0 is used for Left.  If neither Top nor Bottom are specified, a value of 0 is used for Top.

It’s a good idea, then, to always specify exactly two of these four properties, in any of the following combinations:

  • Left / Top
  • Left / Bottom
  • Right / Top
  • Right / Bottom

By always specifying exactly two properties, none are ignored and you never implicitly use a value of 0, but make the positioning clear by explicitly specifying both values that are to be used.

#393 – Canvas Element

The Canvas panel serves as a container for a collection of child elements and allows positioning its children using exact coordinates (in WPF Units).

You can specify the following attached properties for a child element of the Canvas, to control how the child element is positioned.

  • Left – Distance between left side of element and left side of canvas
  • Top – Distance between top side of element and top side of canvas
  • Right – Distance between right side of element and right side of canvas
  • Bottom – Distance between bottom side of element and bottom of canvas

If you don’t specify values for any of these properties for a child element, it will be positioned in the upper left corner of the Canvas.

    <Canvas>
        <Label Content="Pease Porridge Hot"/>
        <Label Content="Pease Porridge Cold" Canvas.Left="99" Canvas.Top="23" />
        <Button Content="In the Pot" Canvas.Left="55" Canvas.Top="63" />
        <TextBox Text="Nine Days Old" Canvas.Left="161" Canvas.Top="111" />
    </Canvas>

#392 – Use SnapsToDevicePixels Property to Prevent Anti-Aliasing

Because WPF position GUI elements using device-independent units, small GUI elements can look fuzzy when rendered, due to anti-aliasing.

Notice the inconsistent appearance of the vertical lines in the example below. Every line should be the same width, since they were defined to be 1 WPF unit wide (1 pixel at 96 dpi).

You can prevent fuzziness due to anti-aliasing by setting the SnapsToDevicePixels property of an UIElement to true.  Setting this property to true tells the rendering system to line elements up with pixel boundaries, which prevents anti-aliasing.  This is known as pixel snapping.

Setting SnapsToDevicePixels to true on the parent ListBox in the above example leads to vertical lines that are consistently sized (1 pixel wide on a 96 dpi display).

#391 – Anti-Aliasing Can Lead to Fuzzy GUI Elements

You specify positions and sizes for GUI elements in WPF using device-independent units.  A unit is 1/96 of an inch, or 1 pixel on a 96 dpi display.  This allows the object to have a consistent physical size, regardless of the output resolution.

Because you’re not specifying things in terms of pixels, object edges don’t always line up exactly with pixels.  WPF uses anti-aliasing when rendering GUI elements.  For example, if an element only covers half of a pixel, that pixel is rendered at half intensity.

This can lead to fuzzy edges of GUI elements and looks especially bad for elements designed to be very small.

Below is an example of a ListBox containing items that include a couple of vertical lines (specified using a Border element).  The lines are all 1 display unit wide.  Some are 1 pixel wide, but many of them look fuzzy.

I’ll talk next time about how to fix this.

#390 – Scrollbar Visibility in a ScrollViewer

The HorizontalScrollbarVisibility and VerticalScrollbarVisibility properties dictate which scrollbars appear in a ScrollViewer.  The properties can be set to one of the ScrollBarVisibility values:

  • Disabled – scrollbar doesn’t appear and user can’t scroll any of the contained content

  • Hidden – scrollbar doesn’t appear, but the user can still scroll the content, e.g. with arrow keys

  • Visible – scrollbar always visible, but greyed out if there is nothing to scroll

  • Auto – Scrollbar appears only when needed

#389 – Wrap a Panel in A ScrollViewer to Provide Scrolling Support

The layout containers in WPF do not automatically provide scrolling support.  To scroll the content in a container, however, you can wrap it in a ScrollViewer control.

    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <StackPanel Orientation="Vertical" >
            <Label Content="I am happy to join with you today in what will go down in history as the greatest demonstration for freedom in the history of our nation." />
            <Label Content="Some famous speeches:"/>
            <Label Content="I Have a Dream. --MLK" />
            <Label Content="Inaugural Address --JFK"/>
            <Label Content="First Inaugural --FDR"/>
            <Label Content="Pearl Harbor Address --FDR"/>
            <Label Content="1976 DNC Keynote --Barbara Jordan"/>
        </StackPanel>
    </ScrollViewer>



Notice that we’ve set the visibility of both scrollbars to Auto. By default, though, the horizontal scrollbar is disabled and the vertical scrollbar is visible.

You can set the HorizontalScrollbarVisibility and VerticalScrollbarVisibility properties to one of the following: Disabled, Visible, Auto or Hidden.