New to Telerik UI for WPF? Download free 30-day trial

Add a Close Button to a RadTileViewItem

This article demonstrates how to add a close button next to the tile state change (minimize/maximize) button of the RadTileViewItems. The Command property of the close button will be bound to an ICommand that removes the item from the RadTileView's ItemsSource.

You can see the final result on the picture bellow: radtileview-howto-add-close-button-to-radtileiewitem.aml 01

Define the RadTileView in XAML and create the view model

The RadTileView in this scenario will be data bound to a collection of business objects.

public class DataItem 
{ 
    public string Header { get; set; } 
    public string Content { get; set; } 
} 

The collection passed to the RadTileView's ItemsSource can be wrapped in a View Model class

public class MainViewModel 
{ 
    public ObservableCollection<DataItem> Items { get; set; } 
 
    public MainViewModel() 
    { 
        this.Items = new ObservableCollection<DataItem>(); 
 
        for (int i = 0; i < 2; i++) 
        { 
            var dataItem = new DataItem() 
            { 
                Header = "Item " + i, 
                Content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit." 
            }; 
 
            this.Items.Add(dataItem); 
        } 
    } 
} 

After creating the view models you can add the RadTileView definition in xaml.

<telerik:RadTileView ItemsSource="{Binding Items}"                    
                     MinimizedRowHeight="150"  
                     MinimizedColumnWidth="200"  
                     HeaderStyle="{StaticResource TileViewItemHeaderStyle1}"> 
    <telerik:RadTileView.DataContext> 
        <local:MainViewModel /> 
    </telerik:RadTileView.DataContext> 
    <telerik:RadTileView.ItemTemplate> 
        <DataTemplate> 
            <TextBlock Text="{Binding Header}" HorizontalAlignment="Right"/> 
        </DataTemplate> 
    </telerik:RadTileView.ItemTemplate> 
    <telerik:RadTileView.ContentTemplate> 
        <DataTemplate> 
            <TextBlock Margin="16" Text="{Binding Content}" TextWrapping="Wrap" /> 
        </DataTemplate> 
    </telerik:RadTileView.ContentTemplate> 
</telerik:RadTileView> 

Extract and Edit the RadTileViewItem HeaderStyle

The RadTileViewItem’s header is represented by TileViewItemHeader control. To add close button you can extract the Style of the TileViewItemHeader and slightly modify its ControlTemplate. Basically, you can find the RadToggleButton that represents the Minimize/Maximize button and wrap it in a Grid (or another panel) along with the new close button.

You can see the Editing Control Templates help article that demonstrates how to extract the Style with the ControlTemplate of a control.

................ 
<Border BorderBrush="White" BorderThickness="0,0,0,1" Background="{TemplateBinding Background}" CornerRadius="1" Padding="10,0,7,0"> 
<Grid MinHeight="28"> 
    <Border x:Name="GripBarElement" Background="Transparent"> 
        <ContentPresenter x:Name="HeaderElement" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="0,0,10,0" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> 
    </Border> 
 
    <Grid HorizontalAlignment="Right" VerticalAlignment="Center"> 
        <Grid.ColumnDefinitions> 
            <ColumnDefinition /> 
            <ColumnDefinition /> 
        </Grid.ColumnDefinitions> 
 
        <telerik:RadButton Margin="2 0 0 0" Command="local:TileViewCommandsExtension.Delete" Grid.Column="1" x:Name="CloseButton" InnerCornerRadius="0"> 
            <telerik:RadButton.Style> 
                <Style TargetType="{x:Type telerik:RadButton}"> 
                    <Setter Property="VerticalAlignment" Value="Center"/> 
                    <Setter Property="HorizontalAlignment" Value="Right"/> 
                    <Setter Property="Width" Value="17"/> 
                    <Setter Property="Height" Value="17"/> 
                    <Setter Property="Template"> 
                        <Setter.Value> 
                            <ControlTemplate TargetType="{x:Type telerik:RadButton}"> 
                                <Grid Background="Transparent" SnapsToDevicePixels="True"> 
                                    <VisualStateManager.VisualStateGroups> 
                                        <VisualStateGroup x:Name="CommonStates"> 
                                            <VisualState x:Name="Disabled"/> 
                                            <VisualState x:Name="Normal"/> 
                                            <VisualState x:Name="MouseOver"> 
                                                <Storyboard> 
                                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke" Storyboard.TargetName="closeButtonPath"> 
                                                        <DiscreteObjectKeyFrame KeyTime="0"> 
                                                            <DiscreteObjectKeyFrame.Value> 
                                                                <SolidColorBrush Color="White" /> 
                                                            </DiscreteObjectKeyFrame.Value> 
                                                        </DiscreteObjectKeyFrame> 
                                                    </ObjectAnimationUsingKeyFrames> 
                                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="closeButtonPath"> 
                                                        <DiscreteObjectKeyFrame KeyTime="0"> 
                                                            <DiscreteObjectKeyFrame.Value> 
                                                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> 
                                                                    <GradientStop Color="#FFFEEDB7" Offset="0"/> 
                                                                    <GradientStop Color="#FFFACA6A" Offset="1"/> 
                                                                    <GradientStop Color="#FFFFC94A" Offset="0.526"/> 
                                                                    <GradientStop Color="#FFFEEDB7" Offset="0.509"/> 
                                                                </LinearGradientBrush> 
 
                                                            </DiscreteObjectKeyFrame.Value> 
                                                        </DiscreteObjectKeyFrame> 
                                                    </ObjectAnimationUsingKeyFrames> 
                                                </Storyboard> 
                                            </VisualState> 
                                        </VisualStateGroup> 
                                    </VisualStateManager.VisualStateGroups> 
 
                                    <Grid x:Name="closeButtonContent">                                       
                                        <Path x:Name="closeButtonPath" Stretch="Uniform" 
                                              Stroke="White" 
                                              StrokeThickness="1.5" 
                                              VerticalAlignment="Center"  
                                              Height="15" Width="15" 
                                              Data="M41.191966,0.5 L71.431967,0.5 71.431967,41.207996 112.12394,42.350311 111.27536,72.578407 71.431967,71.459915 71.431967,111.319 41.191966,111.319 41.191966,70.611007 0.5,69.468688 1.3485718,39.240596 41.191966,40.359092 z"> 
                                            <Path.LayoutTransform> 
                                                <TransformGroup> 
                                                    <ScaleTransform ScaleX="-1"/> 
                                                    <SkewTransform/> 
                                                    <RotateTransform Angle="45.01"/> 
                                                    <TranslateTransform/> 
                                                </TransformGroup> 
                                            </Path.LayoutTransform> 
 
                                            <Path.Fill> 
                                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> 
                                                    <GradientStop Color="#FF282828"/> 
                                                    <GradientStop Color="#FF7C7C7C" Offset="1"/> 
                                                </LinearGradientBrush> 
                                            </Path.Fill> 
                                        </Path> 
                                    </Grid> 
                                </Grid> 
                            </ControlTemplate> 
                        </Setter.Value> 
                    </Setter> 
                </Style> 
            </telerik:RadButton.Style> 
        </telerik:RadButton> 
 
        <telerik:RadToggleButton x:Name="MaximizeToggleButton" Command="TileView:TileViewCommands.ToggleTileState" InnerCornerRadius="0"> 
            ................. 
        </telerik:RadToggleButton> 
    </Grid>  
</Grid> 
</Border> 
........... 

The code snippet above doesn't contain the complete definition of the TileViewItemHeader.ControlTemplate, but only the part of it that is changed. You can see the complete template in our GitHub SDK repository.

Implement the Close button’s command

The final stage of this tutorial is to implement the Close button’s command. We will use a static class holding an RoutedUICommand and then we will implement its behavior by adding command binding for it. To do so, you can follow the next steps:

  1. Create a static class that holds the command.

        public static class TileViewCommandsExtension 
        { 
            static TileViewCommandsExtension() 
            { 
                TileViewCommandsExtension.Delete = new RoutedUICommand("Deletes a tile view item", "Delete", typeof(TileViewCommandsExtension)); 
            } 
     
            public static RoutedUICommand Delete { get; private set; } 
        } 
  2. Set the Command property of the close RadButton in the ControlTemplate of the TileViewItemHeader to the command.

        <telerik:RadButton Margin="2 0 0 0" Command="local:TileViewCommandsExtension.Delete" Grid.Column="1" x:Name="CloseButton" InnerCornerRadius="0"> 
  3. Register command binding for the command in the static constructor of the UserControl where the RadTileView is used.

        public partial class Example : UserControl 
        { 
            static Example() 
            { 
                var deleteBinding = new CommandBinding(TileViewCommandsExtension.Delete, OnDeleteCommandExecute, OnCanDeleteCommandExecute); 
                CommandManager.RegisterClassCommandBinding(typeof(RadTileViewItem), deleteBinding); 
            } 
     
            private static void OnCanDeleteCommandExecute(object sender, CanExecuteRoutedEventArgs e) 
            {             
            } 
     
            private static void OnDeleteCommandExecute(object sender, ExecutedRoutedEventArgs e) 
            { 
            } 
     
            public Example() 
            { 
                InitializeComponent(); 
            } 
        } 
  4. Define behavior for the command by implementing the Execute and CanExecute event handlers.

        public partial class Example : UserControl 
        { 
            static Example() 
            { 
                var deleteBinding = new CommandBinding(TileViewCommandsExtension.Delete, OnDeleteCommandExecute, OnCanDeleteCommandExecute); 
                CommandManager.RegisterClassCommandBinding(typeof(RadTileViewItem), deleteBinding); 
            } 
     
            private static void OnCanDeleteCommandExecute(object sender, CanExecuteRoutedEventArgs e) 
            { 
                e.CanExecute = true; 
            } 
     
            private static void OnDeleteCommandExecute(object sender, ExecutedRoutedEventArgs e) 
            { 
                var tileViewItem = sender as RadTileViewItem; 
                var tileView = tileViewItem.ParentTileView as RadTileView; 
                if (tileViewItem == null || tileView == null) return; 
     
                if (tileView.ItemsSource != null) 
                { 
                    var dataItem = tileView.ItemContainerGenerator.ItemFromContainer(tileViewItem) as DataItem; 
     
                    // Note: This will change the DataContext's Items collection. 
                    var source = tileView.ItemsSource as IList; 
                    if (dataItem != null && source != null) 
                        source.Remove(dataItem); 
                } 
                else 
                { 
                    tileView.Items.Remove(tileViewItem); 
                } 
            } 
     
            public Example() 
            { 
                InitializeComponent(); 
            } 
        } 

Find a runnable project of the previous example in the WPF Samples GitHub repository.