#376 – Getting Text to Wrap in a Tooltip

When you specify the value of a tooltip by setting the Tooltip property for a control, a popup window for the tooltip is created and the window contains a single label.  By default, this label does not wrap, but displays in a single long line.

If you want the text in a tooltip to wrap, you can specify an explicit Tooltip control in XAML and set it up to contain a TextBlock.  The TextBlock has a TextWrapping property that lets you wrap the text.

        <TextBox Text="Now is the winter of our discontent Made glorious summer by this sun of York; And all the clouds that lour'd upon our house In the deep bosom of the ocean buried."
            Width="100" Margin="10">
            <TextBox.ToolTip>
                <ToolTip DataContext="{Binding Path=PlacementTarget, RelativeSource={x:Static RelativeSource.Self}}">
                    <TextBlock Text="{Binding Text}" TextWrapping="Wrap" Width="200"/>
                </ToolTip>
            </TextBox.ToolTip>
        </TextBox>

Advertisement

#375 – Binding Something in a Tooltip to a Property on the Parent Control

You can use data binding to bind the value of a simple Tooltip property to some other property of the control.  But you might also want to use data binding when you create a Tooltip as a child element in XAML.

Suppose you want a Tooltip to include several labels and you want the Content of the second label to bind back to a property on the parent control.

You can do this by using the PlacementTarget of the Tooltip to find its parent and then set the DataContext of the Tooltip.

        <TextBox Text="Now is the winter of our discontent etc"
            Width="100" Margin="10">
            <TextBox.ToolTip>
                <ToolTip DataContext="{Binding Path=PlacementTarget, RelativeSource={x:Static RelativeSource.Self}}">
                    <StackPanel>
                        <Label FontWeight="Bold" Content="Full Text"/>
                        <Label Content="{Binding Text}"/>
                        <Label Content="--Gloster, in Richard III (Act I, Scene I)"/>
                    </StackPanel>
                </ToolTip>
            </TextBox.ToolTip>
        </TextBox>

#374 – Using a Tooltip to Display the Full Contents of a TextBox

It might often be the case that a TextBox control is not wide enough to display all of its text (the current value of its Text property).

The user could click in the TextBox control and move the cursor in order to see all of the text, but it would be handy to display the full contents in a tooltip.

You can set up a tooltip to display the full text of the Text property by setting the Tooltip property of the TextBox and using data binding to bind its value to the Text property.

        <TextBox Text="Now is the winter of our discontent Made glorious summer by this sun of York; And all the clouds that lour'd upon our house In the deep bosom of the ocean buried."
            ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Text}"
            Width="100" Margin="10"/>

#373 – Creating More Complex Tooltips

You typically set a tooltip as a simple textual label, setting the value of the Tooltip property for a control to a text string.  You can also define a more complex tooltip that includes several controls.  In the example below, hovering over one of the tractor brands causes a tooltip to be displayed that shows the logo for the brand.

A tooltip is actually a popup window represented by an instance of the Tooltip control.  Because it inherits from ContentControl, its content can be any .NET object.

You can specify a tooltip’s content in XAML as a child element of the parent control.  The content must be a single element, but can be a container that in turn contains other elements.

            <RadioButton Content="Deere"
                         VerticalAlignment="Center" Margin="5">
                <RadioButton.ToolTip>
                    <StackPanel>
                        <Label Content="John Deere" FontWeight="Bold"/>
                        <Image Source="Deere.jpg"/>
                        <Label Content="Nothing runs like a Deere"/>
                    </StackPanel>
                </RadioButton.ToolTip>
            </RadioButton>
/RadioButton>

#372 – Defining Tooltips for GUI Elements

A tooltip is a small popup that appears when a user hovers the mouse pointer over some user interface element.  It’s typically used to provide further information about the element that the user hovers over.

In WPF, you can set a textual tooltip by setting the Tooltip property of a control (inherited from FrameworkElement or FrameworkContentElement class).

    <StackPanel>
        <Label Content="Buy a Tractor:" />
        <StackPanel Orientation="Horizontal" >
            <Label Content="Brand:"/>
            <RadioButton Content="Deere" ToolTip="Nothing runs like a Deere"/>
            <RadioButton Content="New Holland" ToolTip="Smart Design. Built Strong. Farm Raised."/>
            <RadioButton Content="Kubota" ToolTip="The Orange Way"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" >
            <Label Content="Series:" />
            <ComboBox SelectedIndex="0" >
                <ComboBoxItem Content="BX Series" ToolTip="Little guy"/>
                <ComboBoxItem Content="B Series" ToolTip="18-32hp, smaller landscaping"/>
                <ComboBoxItem Content="TLB Series" ToolTip="21-59hp, professional"/>
                <ComboBoxItem Content="L Series" ToolTip="30-59HP, larger landscaping"/>
                <ComboBoxItem Content="M Series" ToolTip="43-135hp, all-purpose agricultural"/>
            </ComboBox>
        </StackPanel>
        <Button Content="Buy It" ToolTip="Charge my credit card and send me my tractor" />
    </StackPanel>

#371 – Specifying a Default Date for a Calendar Control to Display

When you use a Calendar control, it will default to showing the current date when the application starts.

You can override the default date displayed by setting the DisplayDate property.

        <Calendar SelectionMode="SingleDate" DisplayDate="7/20/1969"/>


You can also specify a range of dates that the Calendar control is allowed to display by using the DisplayDateStart and DisplayDateEnd properties.

        <Calendar SelectionMode="SingleDate" DisplayDateStart="12/7/1941" DisplayDateEnd="8/14/1945"/>

The Calendar control will now allow selecting only dates that fall within this time period.  When you navigate to the month containing the earliest date, you’ll be unable to navigate further back in time.  Similarly, you’ll be unable to navigate to a date later than the date specified in the DisplayDateEnd property.


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

#368 – Specifying Blackout Dates in a Calendar Control

You can use the BlackoutDates property of a Calendar control to specify dates that a user cannot select.

The BlackoutDates property is of type CalendarBlackoutDatesCollection, which is an observable collection of CalendarDateRange objects.  You can specify a set of blackout dates for a Calendar control in XAML by defining a series of CalendarDateRange instances.

        <Calendar Name="calMuseum" SelectionMode="SingleDate">
            <Calendar.BlackoutDates>
                <CalendarDateRange Start="8/6/11" End="8/7/11"/>
                <CalendarDateRange Start="8/20/11" End="8/20/11"/>
                <CalendarDateRange Start="8/28/11" End="8/30/11"/>
            </Calendar.BlackoutDates>
        </Calendar>
        <Label Content="Choose a day to visit the museum." HorizontalContentAlignment="Center" />

The dates specified as blackout dates are not selectable by a user and will appear x‘d out on the calendar.

You can also add specific blackout dates from code-behind.

            // Blackout holidays
            calMuseum.BlackoutDates.Add(new CalendarDateRange(new DateTime(2011,1,17)));
            calMuseum.BlackoutDates.Add(new CalendarDateRange(new DateTime(2011,2,21)));
            calMuseum.BlackoutDates.Add(new CalendarDateRange(new DateTime(2011,5,30)));
            calMuseum.BlackoutDates.Add(new CalendarDateRange(new DateTime(2011,7,4)));
            calMuseum.BlackoutDates.Add(new CalendarDateRange(new DateTime(2011,9,5)));
            calMuseum.BlackoutDates.Add(new CalendarDateRange(new DateTime(2011,10,10)));
            calMuseum.BlackoutDates.Add(new CalendarDateRange(new DateTime(2011,11,11)));
            calMuseum.BlackoutDates.Add(new CalendarDateRange(new DateTime(2011,11,24)));
            calMuseum.BlackoutDates.Add(new CalendarDateRange(new DateTime(2011,12,26)));

#367 – You Can’t Bind to a Calendar Control’s SelectedDates Property

A Calendar control’s SelectedDate property (single selected date) is read/write, so you are able to use data binding to bind it to a nullable DateTime.

The SelectedDates property (collection of selected dates), on the other hand, is read-only.  This means that you can’t bind to the SelectedDates property.

If you want to store a Calendar control’s set of currently selected dates in a variable, you can handle the calendar’s SelectedDatesChanged event.

XAML fragment:

        <Calendar SelectionMode="MultipleRange" SelectedDatesChanged="Calendar_SelectedDatesChanged"/>

Code-behind, where we store selected dates in array:

        public DateTime[] MyVacation { get; set; }

        private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
        {
            System.Windows.Controls.Calendar cal = (System.Windows.Controls.Calendar)sender;

            MyVacation = cal.SelectedDates.ToArray();
        }

This event handler will be called whenever the user selects or unselects dates in the Calendar control.  Because we reset the MyVacation array in the handler, it will always reflect the current set of selected dates.