Friday, December 30, 2011

Playing with Tooltip in WPF



ToolTip displays information in popup for an element or control. It is used to display some useful information to user. ToolTip class is derived from ContentControl class hence Tooltip can contain single object. WPF provides fully customizable Tooltip. In this post I will describe some majorly used functionality of ToolTip.

Simple Tooltip

<Grid>
    <Button Height="35" Width="120"
            Content="Buy"
            ToolTip="Click here to Buy" />
</Grid>


Or

<Grid>
    <Button Height="35" Width="120"
            Content="Buy">
        <Button.ToolTip>
            <StackPanel>
                <TextBlock FontSize="15"
                            Text="Purchase" />
                <TextBlock Margin="5,5,0,0"
                            Text="Click here to Buy" />
            </StackPanel>
        </Button.ToolTip>
    </Button>
</Grid>


ToolTip Placement

Tooltip provides different types of placement. We can set placement property to Left, Right, Top, Bottom, Relative, Absolute etc. This placement property is available in ToolTip class as well in ToolTipService.

Placement = “Top”

<Grid>
    <Button Height="35" Width="120"
            ToolTipService.Placement="Top"
        Content="Buy">
        <Button.ToolTip>
            <StackPanel>
                <TextBlock FontSize="15"
                        Text="Purchase" />
                <TextBlock Margin="5,5,0,0"
                        Text="Click here to Buy" />
            </StackPanel>
        </Button.ToolTip>
    </Button>
</Grid>


Placement = “Relative”
HorizontalOffset=”25”
VerticalOffset =”20”

<Grid>
    <Button Height="35" Width="120"
            ToolTipService.Placement="Relative"
            ToolTipService.HorizontalOffset="25"
            ToolTipService.VerticalOffset="20"
            Content="Buy">
        <Button.ToolTip>
            <StackPanel>
                <TextBlock FontSize="15"
                        Text="Purchase" />
                <TextBlock Margin="5,5,0,0"
                        Text="Click here to Buy" />
            </StackPanel>
        </Button.ToolTip>
    </Button>
</Grid>


Setting duration of ToolTip

Showduration property allows you to specify duration for ToolTip.

<Grid>
    <Button Height="35" Width="120"
        ToolTip="Click here to Buy"
        ToolTipService.ShowDuration="500"
        Content="Buy" />
</Grid>



Showing ToolTip of Disabled Controls

ToolTip can also be displayed on disabled control using ShowOnDisable property of ToolTipService.

<Grid>
    <Button Height="35" Width="120"
            ToolTip="Click here to Buy"
            IsEnabled="False"
            ToolTipService.ShowOnDisabled="True"
            Content="Buy" />
</Grid>



See Also – 

Thursday, December 29, 2011

WPF Content Model


WPF provides many controls which are displaying different types of content. WPF content model describes which control can be used to display what kind of content. Below is the list of major classes from which many controls are derived and displaying their content accordingly. 


Below is the list of majorly used controls in WPF with their parent class.

For more information, see MSDN Page.



See Also - 
WPF Class Hierarchy
WPF Architecture
Logical vs. Visual Tree

Tuesday, December 27, 2011

Freezable Objects in WPF



Freezable is a type which represents frozen and unfrozen states. When object state is frozen, no one can modify the object. Freezable class provides Freeze method to freeze object. Once object is frozen, can never be reverted to unfrozen state. Freezable class provides clone method to clone frozen object to another unfrozen object.

Not necessary that every Freezable objects can be frozen so before calling freeze method need to check whether object can be freezable or not using CanFreeze property. Forcefully freeze an unfreezable object throws InvalidOperationException.  CanFreeze returns true if object is freezable else return false. IsFrozen property returns true if an object is already freeze otherwise returns false. It is best practice to freeze an object (if freezable) which is not going to modify until application ends.

Why Freeze an object?

There are classes like Brush, Camera, Transform, Geometry, BitmapEffect are derived from Freezable class. Some of these graphic related objects contain unmanaged resources so when change in original object, system must monitor these object modification and need to update corresponding unmanaged resources as well. These might cause performance hit because system needs to monitor resource even there is no change in original object. Freezable class can help to improve WPF application performance.

Let’s have a look on below code.

XAML

<Grid>
    <Label Content="Hello"
            Name="MyText"
            HorizontalContentAlignment="Center"
            FontSize="30"
            Width="200" Height="50" />
</Grid>

Code

void FreezableObjects_Loaded(object sender, RoutedEventArgs e)
{
    RadialGradientBrush radialBrush = new RadialGradientBrush();
    radialBrush.GradientStops.Add(new GradientStop(Colors.Red, 0.2));
    radialBrush.GradientStops.Add(new GradientStop(Colors.White, 0.9));

    MyText.Background = radialBrush;

    if (radialBrush.CanFreeze)
        radialBrush.Freeze();

    if (radialBrush.IsFrozen)
    {
        radialBrush.GradientStops.Add(
             new GradientStop(Colors.Blue, 0.4)); //Throws InvalidOperationException. Can’t modify frozen object.

    }
}



How to clone frozen objects?

void FreezableObjects_Loaded(object sender, RoutedEventArgs e)
{
    RadialGradientBrush radialBrush = new RadialGradientBrush();
    RadialGradientBrush radialBrushClone = new RadialGradientBrush();
    
    radialBrush.GradientStops.Add(new GradientStop(Colors.Red, 0.2));
    radialBrush.GradientStops.Add(new GradientStop(Colors.White, 0.9));
    
    MyText.Background = radialBrush;

    if (radialBrush.CanFreeze)
        radialBrush.Freeze();

    if (radialBrush.IsFrozen)
    {
        radialBrushClone = radialBrush.Clone();
        radialBrushClone.GradientStops.Add(new GradientStop(Colors.Blue, 1));
        MyText.Background = radialBrushClone;
    }
}


As per first example, once radialBrush object is frozen and tries to modify the radiaBrush object throws an InvalidOperationException. Another example demonstrate how to create clone object from frozen object.

See Also – 


WPF – Repeat Button


WPF Repeat button is similar to normal button but it gives you control how and when button's click event will get fired. Repeat button allows you to repeatedly fire click event starting from pressed until it is released. The repeated behavior defines by Delay and Interval properties of repeat button. The delay property defines time to start click event and the Interval property controls the time to repeat click event.

Repeat button continuously fires click event when it is pressed and held. The below example demonstrates two repeat buttons add and remove. On press and hold of add button counter value increase and decrease on press and hold of remove button.

XAML

<Grid>
<Grid.ColumnDefinitions>
    <ColumnDefinition />
    <ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
</Grid.RowDefinitions>
<RepeatButton Width="100" Height="40"
                Name="btnAdd"
                Content="Add"
                Grid.Column="0" Grid.Row="0"
                Interval="100" Delay="1000"
                Click="btnAdd_Click" />
<RepeatButton Width="100" Height="40"
                Name="btnRemove"
                Content="Remove"
                Grid.Column="1" Grid.Row="0"
                Interval="100" Delay="1000"
                Click="btnRemove_Click" />
<TextBlock Height="50" Width="50"
            Name="txtDisplay"
            Grid.Row="1" Grid.ColumnSpan="2"
            TextAlignment="Center"
            FontWeight="Bold"
            FontSize="35"
            Foreground="Red" />
</Grid>

Code

public partial class RepeatButtonDemo : Window
{
    public int counter;
    public RepeatButtonDemo()
    {
        InitializeComponent();
    }

    private void btnAdd_Click(object sender, RoutedEventArgs e)
    {
        txtDisplay.Text = (++counter).ToString();
    }

    private void btnRemove_Click(object sender, RoutedEventArgs e)
    {
        txtDisplay.Text = (--counter).ToString();
    }
}

Output




As per above code, when mouse button pressed and hold on add button, the label (in red text) value increases as per delay and interval specified on add repeat button. The reverse thing happens when mouse button is pressed and hold on remove button.

See Also – 

Monday, December 26, 2011

WPF - Toggle Button


Toggle button is similar to checkbox control that holds its state when it clicked.  When Toggle button clicked first time it will set IsChecked property to true and on click again it will set IsChecked property to false. Toggle button also fires Checked event when IsChecked property set to true and UnChecked event when set to false. Toggle button is available in System.Windows.Controls.Premitives namespace.

Toggle Button also implements IsThreeState property. If IsThreeState property is enabled, the first click sets IsChecked property to true, the second click sets it to null and the third click sets it to false. 

Let’s have a look on below example.

<Window.Resources>
    <Style TargetType="{x:Type ToggleButton}"
           x:Key="toggleButtonStyle">
        <Setter Property="FontWeight" Value="Bold" />
        <Style.Triggers>
            <Trigger Property="IsChecked" Value="True">
                <Setter Property="Content" Value="IsChecked='True'" />
                <Setter Property="Foreground" Value="Green" />
            </Trigger>
            <Trigger Property="IsChecked" Value="False">
                <Setter Property="Content" Value="IsChecked='False'" />
                <Setter Property="Foreground" Value="Red" />
            </Trigger>
            <Trigger Property="IsChecked" Value="{x:Null}">
                <Setter Property="Content" Value="IsChecked='Null'" />
                <Setter Property="Foreground" Value="Blue" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <ToggleButton IsChecked="True"
                    IsThreeState="True"
                    Height="30" Width="150"
                    Style="{StaticResource toggleButtonStyle}">
    </ToggleButton>
</Grid>

IsChecked property set to true when application starts, and text color of Toggle Button appears as ‘green’.



On toggle button click, IsChecked property set to null and text color changes to ‘blue’.


Again click on toggle button, IsChecked property set to false and text color changes to  ‘red’.




See Also –