This is a migrated thread and some comments may be shown as answers.

Column Header Binding

6 Answers 647 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Rick Glos
Top achievements
Rank 1
Rick Glos asked on 22 Mar 2010, 05:12 PM
Hello,

I have a Grid that displays a start and end time for each day of the week.  The column headers must include the Date and DayOfWeek formatted basically like this: ...ToString("ddd M/d")

I'm not sure how I go about setting the Binding property.  Here's what I have just using hard coded values but really, I need these to be bound to the view model (and not StaticResource either because if the user chooses a different week, then those values must update).

        <telerik:RadGridView Grid.Row="1" Margin="10" Name="radGridViewScheduleLines" ItemsSource="{Binding ScheduleLines}" AutoGenerateColumns="False" IsFilteringAllowed="False" ShowGroupPanel="False"
            <telerik:RadGridView.Columns> 
                <telerik:GridViewDataColumn DataMemberBinding="{Binding TeamMemberName}" Header="Team Member" CellStyle="{StaticResource TeamMemberColumnStyle}" IsSortable="False" /> 
                <telerik:GridViewDataColumn DataMemberBinding="{Binding JobCode}" Header="Code" IsSortable="False" /> 
                <telerik:GridViewComboBoxColumn DataMemberBinding="{Binding SundayStartDaySegment, Mode=TwoWay}" IsSortable="False" ItemsSource="{Binding DaySegments}" DisplayMemberPath="DisplayStart" Width="50"
                    <telerik:GridViewComboBoxColumn.Header> 
                        <StackPanel> 
                            <TextBlock Text="Sun 2/28 Start"  
                                       TextWrapping="Wrap"/> 
                        </StackPanel> 
                    </telerik:GridViewComboBoxColumn.Header> 
                </telerik:GridViewComboBoxColumn> 
                <telerik:GridViewComboBoxColumn DataMemberBinding="{Binding SundayEndDaySegment, Mode=TwoWay}" IsSortable="False" ItemsSource="{Binding DaySegments}" DisplayMemberPath="DisplayEnd" Width="50"
                    <telerik:GridViewComboBoxColumn.Header> 
                        <StackPanel> 
                            <TextBlock Text="Sun 2/28 End"  
                                       TextWrapping="Wrap"/> 
                        </StackPanel> 
                    </telerik:GridViewComboBoxColumn.Header> 
                </telerik:GridViewComboBoxColumn> 
                <telerik:GridViewComboBoxColumn DataMemberBinding="{Binding MondayStartDaySegment, Mode=TwoWay}" IsSortable="False" ItemsSource="{Binding DaySegments}" DisplayMemberPath="DisplayStart" Width="50"
                    <telerik:GridViewComboBoxColumn.Header> 
                        <StackPanel> 
                            <TextBlock Text="Mon 3/1 Start"  
                                       TextWrapping="Wrap"/> 
                        </StackPanel> 
                    </telerik:GridViewComboBoxColumn.Header> 
                </telerik:GridViewComboBoxColumn> 
            </telerik:RadGridView.Columns> 
        </telerik:RadGridView> 

See the pattern?  How do I go about making the date part of the Text in the TextBlock bound to something?  I was thinking I'd just have a property hanging off the ViewModel - one for each day and each Start/End column called MondayStartHeader, MondayEndHeader, etc. That won't work though because the grid is bound to a collection of objects on the ViewModel.

Thanks.


6 Answers, 1 is accepted

Sort by
0
Accepted
Rossen Hristov
Telerik team
answered on 23 Mar 2010, 10:04 AM
Hi Rick Glos,

First you will need to create an IValueConverter to use in the Binding. This converter will receive a DataTime value and will return a string such as string.Format("{0:ddd M/d} Start"). Or with "End" depending on the value.

Alternatively you can create two separate converters -- one that will append Start and one that will append End.

Yet another way is to create two TextBlocks standing next to each other with no space. The first can have a Binding to the date and the second can show the fixed text, i.e. Start or End. There are multiple ways to go about this thing.

Now, let us see how to set the Binding. We will attach to the loaded event of the TextBlock and set its Binding to the property of the ViewModel.

I have prepared a sample project. You can use it as a base and modify it to match your exact needs and architecture. Here are the important parts:

<Window x:Class="TicketID_292780_ColumnHeaderBinding.Window1"
    xmlns:local="clr-namespace:TicketID_292780_ColumnHeaderBinding"
    Title="Window1" Height="700" Width="600">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <telerik:RadGridView Name="clubsGrid"
                             Grid.Row="0"
                             AutoGenerateColumns="False"
                             ItemsSource="{Binding Clubs}">
            <telerik:RadGridView.Columns>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}">
                    <telerik:GridViewDataColumn.Header>
                        <StackPanel>
                            <TextBlock Loaded="TextBlock_Loaded"
                                       TextWrapping="Wrap"/>
                        </StackPanel>
                    </telerik:GridViewDataColumn.Header>
                </telerik:GridViewDataColumn>
            </telerik:RadGridView.Columns>
        </telerik:RadGridView>
        <Button Grid.Row="1" Content="Change Column 1 Header" Click="Button_Click"/>
    </Grid>
</Window>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
 
namespace TicketID_292780_ColumnHeaderBinding
{
    public class MyViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
 
        private ObservableCollection<Club> clubs = Club.GetClubs();
        private DateTime column1Header;
 
        public ObservableCollection<Club> Clubs
        {
            get { return this.clubs; }
        }
 
        public DateTime Column1Header
        {
            get { return this.column1Header; }
            set
            {
                if (value != this.column1Header)
                {
                    this.column1Header = value;
                    this.OnPropertyChanged("Column1Header");
                }
            }
        }
 
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, args);
            }
        }
 
        private void OnPropertyChanged(string propertyName)
        {
            this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
 
namespace TicketID_292780_ColumnHeaderBinding
{
    public class StartConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null && value is DateTime)
            {
                return string.Format("{0: ddd M/d} Start", (DateTime)value);
            }
 
            return null;
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

using System.Windows;
using Telerik.Windows.Controls;
using Telerik.Windows.Data;
using System;
using System.Windows.Controls;
using System.Windows.Data;
 
namespace TicketID_292780_ColumnHeaderBinding
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        MyViewModel vm = new MyViewModel();
 
        public Window1()
        {
            InitializeComponent();
 
            this.vm.Column1Header = DateTime.Now;
            this.clubsGrid.DataContext = this.vm;
        }
 
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.vm.Column1Header = this.vm.Column1Header.AddDays(7);
        }
 
        private void TextBlock_Loaded(object sender, RoutedEventArgs e)
        {
            TextBlock txt = (TextBlock)sender;
            txt.DataContext = this.vm;
            Binding b = new Binding("Column1Header"){Converter = new StartConverter()};
            txt.SetBinding(TextBlock.TextProperty, b);
        }
    }
}

You can find the whole project attached. When you click the button you will see how the header of the column changes.

I hope this helps.

Greetings,
Ross
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
Rick Glos
Top achievements
Rank 1
answered on 24 Mar 2010, 09:32 PM
Thanks Ross.  Very helpful. 

Not only does it solve this problem I was having above, but this solution also works great for setting Grand Total Footer values for the Silverlight version of the RadGirdView I'm using in another application.  I was setting the values programmitacilly instead of binding them.  Now I see how I can reset the DataContext on the TextBox to the parent ViewModel.  Excellent.
0
Rick Glos
Top achievements
Rank 1
answered on 25 Mar 2010, 10:18 PM
In case this helps someone else, here's how I actually implemented this.

Instead of using converters, I put the property path I wanted to bind the header to in the Tag property of the TextBlock.

<TextBlock Tag="SundayStartHeaderText" TextWrapping="Wrap" Loaded="HeaderTextBlock_Loaded"/> 

Then in the event handler, just used that to set the binding of the TextBlock

        private void HeaderTextBlock_Loaded(object sender, RoutedEventArgs e) 
        { 
            TextBlock textBlock = sender as TextBlock; 
            if (textBlock != null
            { 
                // Set the DataContext to the ViewModel 
                textBlock.DataContext = this._viewModel; 
                // The tag property contains the property path we want to bind to 
                string propertyPath = textBlock.Tag.ToString(); 
                Binding binding = new Binding(propertyPath); 
                textBlock.SetBinding(TextBlock.TextProperty, binding); 
            } 
        } 

Thanks again for the input Ross.
0
M
Top achievements
Rank 1
answered on 27 Mar 2012, 08:53 AM
It works but in my opinion this is not a real elegant solution. Since you are talking about a viemodel I guess you are using mvvm like me and in mvvm you really don't want events or whatever in code behind.
I found a xaml only solution that also works. I don't use an event but directly bind to a property in the first row (Projects[0].Days) of the object that I am binding. If there is no data you will get a binding error and the header will stay empty but in my case that is exactly what I want.
Here is the code:
<telerik:GridViewDataColumn.Header>
    <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=telerik:GridViewDataControl}, Path=DataContext.Projects[0].Days[0].Date}"/>
</telerik:GridViewDataColumn.Header>

You might want to add a converter to format the date to any format you like.
0
M
Top achievements
Rank 1
answered on 27 Mar 2012, 09:34 AM

There is even a better solution without converter but with a stringformat so you really have zero code behind:

<telerik:GridViewDataColumn.Header>
    <TextBlock>
        <TextBlock.Text>
            <Binding RelativeSource="{RelativeSource AncestorType=telerik:GridViewDataControl}" Path="DataContext.Projects[0].Days[0].Date" StringFormat="{}{0:D}"/>
        </TextBlock.Text>
    </TextBlock>
</telerik:GridViewDataColumn.Header>
0
Rohan
Top achievements
Rank 1
answered on 16 Jul 2014, 01:49 PM
Thank you for the solution. Worked like a charm!
Tags
GridView
Asked by
Rick Glos
Top achievements
Rank 1
Answers by
Rossen Hristov
Telerik team
Rick Glos
Top achievements
Rank 1
M
Top achievements
Rank 1
Rohan
Top achievements
Rank 1
Share this question
or