#1,019 – Constraining a Slider to Integer Values

The Value property of a Slider can take on any value between the Minimum and Maximum values.  Because it is of type double, it will normally take on a series of real number values as the user drags the thumb.

1019-001

If you want to constrain the Slider values to be integer values only, you can set the following properties:

  • TickFrequency : 1
  • IsSnapToTickEnabled : True

Tickmarks will not be shown, but the Slider will now be constrained only to integer values.

        <Slider Name="mySlider" Margin="10"
                Minimum="1" Maximum="100"
                TickFrequency="1" IsSnapToTickEnabled="True"/>
        <StackPanel Orientation="Horizontal">
            <Label Content="Value:" VerticalAlignment="Center"/>
            <TextBlock Text="{Binding Path=Value, ElementName=mySlider}"
                       Margin="10"/>
        </StackPanel>

1019-002

#1,018 – Slider Basics

The Slider is a control that allows a user to drag a “thumb” across a range of values, to select a specific numeric value.

The Slider’s main properties are:

  • Value – The numeric value selected by the slider
  • Minimum – The minimum value that the slider can be set to (thumb dragged all of the way to the left)
  • Maximum – The maximum value that the slider can be set to (thumb dragged all of the way to the right)

You’ll typically set the Minimum and Maximum to some static values, setting them in XAML to indicate the allowed range of values that a user is allowed to input.

You’ll typically bind the Value property to some property in code, allowing the user to set that value using the Slider.

        <Slider Name="mySlider" Margin="10"
                Minimum="1" Maximum="100"/>
        <StackPanel Orientation="Horizontal">
            <Label Content="Value:" VerticalAlignment="Center"/>
            <TextBlock Text="{Binding Path=Value, ElementName=mySlider}"
                       Margin="10"/>
        </StackPanel>

1018-001
1018-002
1018-003

#1,017 – Scaling Items in a List Using a Slider

Below is an example of using a Slider control to scale a bunch of images in an ItemsControl.  The images are displayed within a WrapPanel.  As they are resized, the WrapPanel automatically updates the layout, so that the number of rows needed to display the images changes.

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ScrollViewer>
            <ItemsControl ItemsSource="{Binding ActorList}" Margin="20">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Image Source="{Binding Image}" Height="100">
                            <Image.LayoutTransform>
                                <ScaleTransform ScaleX="{Binding Value, ElementName=sliScale}"
                                                ScaleY="{Binding Value, ElementName=sliScale}"/>
                            </Image.LayoutTransform>
                        </Image>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </ScrollViewer>
        <Slider Name="sliScale" Grid.Row="1" Margin="10,5"
                Minimum="0.1" Maximum="3"
                Value="1.0"/>
    </Grid>

1017-001

 

1017-002

1017-003

#1,016 – Displaying a Collection of Items in a WrapPanel

You can use data binding to bind a collection of items to a WrapPanel by using the WrapPanel as the ItemsPanel for a simple ItemsControl.  (You could do the same thing with a ListBox).

In the example below, we bind to a collection of Actor objects and set the DataTemplate of our ItemsControl to just display the image of each actor.  The ItemsControl will resize to fit the containing window (via the StackPanel) and the WrapPanel will manage changing the layout of the images as the window size changes.

    <ItemsControl ItemsSource="{Binding ActorList}" Margin="20">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding Image}" Height="100"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

1016-001
1016-002
1016-003

#1,015 – Typing Text to Select an Item in a ComboBox, Part III

You set the TextSearch.TextPath property on a ComboBox to refer to the property on the bound object that contains the text that you can type in order to select an item.

You can change the ComboBox so that the text that you enter to select an item is visible as you enter the text.  To do this, you set the IsEditable property to true.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  IsEditable="True"
                  SelectedItem="{Binding SelectedActor}"
                  TextSearch.TextPath="LastName">
            <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="100"/>
                                <StackPanel Margin="10,0">
                                    <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                                    <TextBlock Text="{Binding Dates}"/>
                                    <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

        <Label Content="{Binding SelectedActor.NameAndDates}"/>

In this example, we can now type the actor’s last name in order to change the selected item.  We can demonstrate this by binding a Label to the selector item (actor).  Notice that the selected item changes as we enter text.
1015-001

#1,014 – Typing Text to Select an Item in a ComboBox, Part II

If a ComboBox has focus, you can normally just start typing text in order to select an item.  If the DisplayMemberPath property is set, you can enter text that matches the property on the bound object specified by DisplayMemberPath.  If you are using an item template to set content for each item, rather than DisplayMemberPath, you can specify the property used when typing text by setting the TextSearch.TextPath property.

In the example below, we set TextSearch.TextPath to LastName, which is a property of the Actor object that each item is bound to.  The user can then just type the actor’s last name in order to select that actor within the ComboBox.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  SelectedItem="{Binding SelectedActor}"
                  TextSearch.TextPath="LastName">
            <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="100"/>
                                <StackPanel Margin="10,0">
                                    <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                                    <TextBlock Text="{Binding Dates}"/>
                                    <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

1014-001

#1,013 – Typing Text to Select an Item in a ComboBox

If a ComboBox has focus, you can just type some text in order to select an item.  By default, the text that you enter will be matched against the property specified by the DisplayMemberPath property, or by the value of the bound object’s ToString method, if DisplayMemberPath is not specified.

In the example below, we don’t specify DisplayMemberPath, but instead specify an ItemTemplate.  If the ComboBox has focus and we start typing, the ToString method of the underlying Actor object is used to determine the object to navigate to.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  SelectedItem="{Binding SelectedActor}">
            <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="100"/>
                                <StackPanel Margin="10,0">
                                    <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                                    <TextBlock Text="{Binding Dates}"/>
                                    <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

If we’ve defined Actor.ToString() to return the actor’s name in a LastName, FirstName format, we can then navigate to an actor by typing their last name.  For example, entering “L” might select Hedy Lamarr.

1013-001

#1,012 – Using a Different Data Template for the Face of a ComboBox

When you define a data template to use as the item template for a ComboBox, this item template is used to render each item in the dropdown list when it appears.  The same item template is used to display the currently selected item on the face of the ComboBox.

1012-001

You can define a different template for the face of the ComboBox using a DataTemplateSelector.  You start by defining a data template selector that allows setting one of two templates and can determine whether the parent of the current item is the ComboBox itself (face of button) or a ComboBoxItem (dropdown).

    public class ComboBoxItemTemplateSelector : DataTemplateSelector
    {
        // Can set both templates from XAML
        public DataTemplate SelectedItemTemplate { get; set; }
        public DataTemplate ItemTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            bool selected = false;

            // container is the ContentPresenter
            FrameworkElement fe = container as FrameworkElement;
            if (fe != null)
            {
                DependencyObject parent = fe.TemplatedParent;
                if (parent != null)
                {
                    ComboBox cbo = parent as ComboBox;
                    if (cbo != null)
                        selected = true;
                }
            }

            if (selected)
                return SelectedItemTemplate;
            else
                return ItemTemplate;
        }
    }

You can now define two different templates in your XAML.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  SelectedItem="{Binding SelectedActor}">
            <ComboBox.ItemTemplateSelector>
                <local:ComboBoxItemTemplateSelector>
                    <local:ComboBoxItemTemplateSelector.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="100"/>
                                <StackPanel Margin="10,0">
                                    <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                                    <TextBlock Text="{Binding Dates}"/>
                                    <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
                    </local:ComboBoxItemTemplateSelector.ItemTemplate>
                    <local:ComboBoxItemTemplateSelector.SelectedItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Height="40" Margin="5,0"/>
                                <TextBlock Text="{Binding FullName}"/>
                            </StackPanel>
                        </DataTemplate>
                    </local:ComboBoxItemTemplateSelector.SelectedItemTemplate>
                </local:ComboBoxItemTemplateSelector>
            </ComboBox.ItemTemplateSelector>
        </ComboBox>

We now have a different layout on the face of the ComboBox, showing the currently selected item.

1012-002

#1,011 – ComboBox Data Binding Basics, Part III

To display the items in a ComboBox using something more than a simple string, you set the ItemTemplate of the ComboBox to define the layout of each item.  When you set the ItemTemplate, you don’t set the DisplayMemberPath property.  DisplayMemberPath defines the template for each item in the ComboBox to be a TextBlock that displays a single string.

Below, we set an item template for a ComboBox that binds to a collection of Actor objects so that we display an image and some information about the actor, for each item.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  SelectedItem="{Binding SelectedActor}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Image}" Height="100"/>
                        <StackPanel Margin="10,0">
                            <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                            <TextBlock Text="{Binding Dates}"/>
                            <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        <Label Content="{Binding SelectedActor.NameAndDates}"/>

As we select an item, notice that the ComboBox changes size, so that the surface can show the entire item.

1011-001

1011-002

#1,010 – ComboBox Data Binding Basics, Part II

When using data binding, you specify the collection of items to fill the ComboBox by setting the ItemsSource property.

You can also bind the currently selected item in the ComboBox to an instance of an object in code.  You do this by binding the SelectedItem property to a property in your code that represents an instance of the appropriate type.  When the user selects an item in the ComboBox, the corresponding object is updated to refer to the selected object.

Assume that we have the following in our code behind:

  • Actor class, representing an actor
  • ActorList property, which is an ObservableCollection<Actor>
  • SelectedActor property, of type Actor

In the example below, we bind the ComboBox to the list of actors and the currently selected actor to the SelectedActor property.  As we select an actor, the Label updates, since it also binds to SelectedActor.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  DisplayMemberPath="FullName"
                  SelectedItem="{Binding SelectedActor}"/>
        <Label Content="{Binding SelectedActor.NameAndDates}"/>

1010-001
1010-002