Answered DataGrid Column Header text change from ViewModel

  • Monday, September 13, 2010 4:15 PM
     
     

    Hi,

    I need to change the column header text of the datagrid. I have defined a viewmodel and exposed a property, but I am not sure how I can bind the column header to this property.

    I am trying to follow MVVM patern and using prism. I am very new to this and I am almost getting lost.

    How can I resolve this problem

    I am using Silverlight4 and VS2010


    Thanks

    ab


All Replies

  • Monday, September 13, 2010 4:57 PM
     
     

    I am not sure if you can, the last I looked at binding Headers was in SL 3 but back then it was not a FrameworkElement so you could not bind to it. Not sure if it changed since then.

    Can you post your xaml for the grid and your viewmodel bind property? 

  • Monday, September 13, 2010 5:26 PM
     
     

    What I am trying to do is very similar to an Email Client. When you click on th Inbox folder I need to show the Header for the recipient as "From" when in Send folder change the Header for the recipient as "To" If I can change this, I can use the same view for all the folders clicked, thats the plan. xaml



           <UserControl.Resources>
    		<DataTemplate x:Key="CheckboxGrid">
    			<Grid>
    				<CheckBox IsThreeState="False" 	IsChecked="False"/>
    			</Grid>			
    		</DataTemplate>
    	</UserControl.Resources>
        
        <Grid x:Name="LayoutRoot" Background="Aqua" HorizontalAlignment="Stretch" Margin="2,0" >
    
            <sdk:DataGrid ItemsSource="{Binding GetMessages}" AutoGenerateColumns="False" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
        		<sdk:DataGrid.Columns >
        			<sdk:DataGridTemplateColumn CellTemplate="{StaticResource CheckboxGrid}" Width="SizeToCells"/>
                    <sdk:DataGridTextColumn x:Name="ColParicipant" Binding="{Binding ParticipantName}" Header="From" IsReadOnly="True" Width="1*"/>
    				<sdk:DataGridTextColumn x:Name="ColFacility" Binding="{Binding FacilityName}" Header="Facility"  IsReadOnly="True" Width="1*"/>
    				<sdk:DataGridTextColumn x:Name="ColPatient" Binding="{Binding PatientName}" Header="Patient Name"  IsReadOnly="True" Width="1*"/>
    				<sdk:DataGridTextColumn x:Name="ColSubject" Binding="{Binding Subject}" Header="Subject"  IsReadOnly="True" Width="1*"/>
    				<sdk:DataGridTextColumn x:Name="ColTime" Binding="{Binding Timestamp}" Header="Timestamp" IsReadOnly="True" Width="*"/>
        		</sdk:DataGrid.Columns>
    		</sdk:DataGrid>
        </Grid>

    public partial class MessageListView : UserControl
        {
            public MessageListView(MessageListVM viewModel)
            {
                InitializeComponent();
    
                this.Loaded += (s, e) =>
                {
                    this.DataContext = viewModel;
                };
            }
    
        }





    (ViewModel)
    public class MessageListVM
        {
            public MessageListVM(IMessageService messageService)
            {
                this.messageService = messageService;
            }
    
            public IEnumerable<Message> GetMessages
            {
                get
                {
                    return messageService.GetFolderMessages();
                }
            }
    
            public object GetHeader
            {
                get
                {
                    return "From";
                }
            }
            private readonly IMessageService messageService;
        }




  • Monday, September 13, 2010 5:40 PM
     
     

    Have a look at this post, as you will see it is still not small task to achieve this.

     

    http://forums.silverlight.net/forums/p/176929/398718.aspx 

  • Tuesday, September 14, 2010 12:42 PM
     
     

    thanks....

    I could get this working by creating the ViewModel as a local resource, and by providing a empty constructor for the viewmodel.

    But I also set the datacontext to the same viewmdoel during load event of the view.

    Is it right to do this? Will it create 2 instance of the same viewmodel ? I can post the code for this if required.

  • Tuesday, September 14, 2010 2:00 PM
     
     

    A StaticResource declared ViewModel will create a new instance unless you use a ViewModel locator pattern. If you go this route maybe use your StaticResource ViewModel across your view and rather not set the DataContext on the load event.

    http://johnpapa.net/silverlight/simple-viewmodel-locator-for-mvvm-the-patients-have-left-the-asylum/ 

  • Monday, September 20, 2010 8:15 PM
     
     Answered

    Thanks

    I found another article  ...

    its not neat .. but will work for me...

  • Monday, September 20, 2010 10:01 PM
     
     

    Would you mind posting the link of that article here to share with other communites.

  • Tuesday, September 21, 2010 8:44 AM
     
     Answered

    I dont remember the link to the article.
    In case I get I can post it.
    Right now I am pasting the code I have
    <UserControl
    x:Class="ccc.RI.SMViewDefault.View.DefaultListView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
    xmlns:conv="clr-namespace:ccc.RI.Common.Converters;assembly=ccc.RI.Common"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
    <conv:BooleanFontConverter x:Key="boofont"></conv:BooleanFontConverter>
            <conv:BindingConverter x:Key="BindCon"/>
            <Style x:Key="ColBinding" TargetType="sdk:DataGridColumnHeader" >
                <Setter Property="ContentTemplate" >
                    <Setter.Value>
                        <DataTemplate>
                            <ContentPresenter Content="{Binding Converter={StaticResource BindCon}}"  />
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            
            <DataTemplate x:Key="ParticipantCol">
                <Grid>
                    <TextBlock Text="{Binding ParticipantName}" FontWeight="{Binding IsRead,Converter={StaticResource boofont}}" Margin="0,4"
    ></TextBlock>
                </Grid>
            </DataTemplate>
            
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" Margin="1,0,1,11">
            <TextBox Text="{Binding GetParticipantHeader}" x:Name="participantHeader" />
            
    <Border BorderBrush="#FFA6B6D6" BorderThickness="2" CornerRadius="2"
    x:Name="defaultview">
    <sdk:DataGrid ItemsSource="{Binding Path=GetMessages}" 
     AutoGenerateColumns="False" 
                              ColumnHeaderStyle="{StaticResource ColBinding}"
     >
    <sdk:DataGrid.Columns >
                        
                        
                        <sdk:DataGridTemplateColumn 
                            CellTemplate="{StaticResource ParticipantCol}" 
                            Header="{Binding Text, ElementName=participantHeader}"
                            Width="1*"  
                            SortMemberPath="ParticipantName"/>
                        
                        
    </sdk:DataGrid.Columns>
    </sdk:DataGrid>
    </Border>
    </Grid>
    </UserControl>
    Also u need a converter.
    namespace ccc.RI.Common.Converters
    {
        public class BindingConverter  : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value.GetType().Name == "Binding")
                {
                    ContentControl cc = new ContentControl();
                    Binding newValue = value as Binding;
                    newValue.Mode = BindingMode.TwoWay;
                    cc.SetBinding(ContentControl.ContentProperty, newValue as Binding);
                    return cc;
                }
                else
                {
                    return value;
                }
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return null;
            }
        }
    }
    Hope this helps

    I dont remember the link to the article.


    In case I get I can post it.


    Right now I am pasting the code I have


    <UserControl

    x:Class="ccc.RI.SMViewDefault.View.DefaultListView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 

    xmlns:conv="clr-namespace:ccc.RI.Common.Converters;assembly=ccc.RI.Common"

    mc:Ignorable="d"

    d:DesignHeight="300" d:DesignWidth="400">

    <UserControl.Resources>

    <conv:BooleanFontConverter x:Key="boofont"></conv:BooleanFontConverter>

            <conv:BindingConverter x:Key="BindCon"/>

            <Style x:Key="ColBinding" TargetType="sdk:DataGridColumnHeader" >

                <Setter Property="ContentTemplate" >

                    <Setter.Value>

                        <DataTemplate>

                            <ContentPresenter Content="{Binding Converter={StaticResource BindCon}}"  />

                        </DataTemplate>

                    </Setter.Value>

                </Setter>

            </Style>

            

            <DataTemplate x:Key="ParticipantCol">

                <Grid>

                    <TextBlock Text="{Binding ParticipantName}" FontWeight="{Binding IsRead,Converter={StaticResource boofont}}" Margin="0,4"

    ></TextBlock>

                </Grid>

            </DataTemplate>

            

    </UserControl.Resources>


    <Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" Margin="1,0,1,11">

            <TextBox Text="{Binding GetParticipantHeader}" x:Name="participantHeader" />

            

    <Border BorderBrush="#FFA6B6D6" BorderThickness="2" CornerRadius="2"

    x:Name="defaultview">

    <sdk:DataGrid ItemsSource="{Binding Path=GetMessages}" 

     AutoGenerateColumns="False" 

                              ColumnHeaderStyle="{StaticResource ColBinding}"

     >

    <sdk:DataGrid.Columns >

                        

                        

                        <sdk:DataGridTemplateColumn 

                            CellTemplate="{StaticResource ParticipantCol}" 

                            Header="{Binding Text, ElementName=participantHeader}"

                            Width="1*"  

                            SortMemberPath="ParticipantName"/>

                        

                        

    </sdk:DataGrid.Columns>

    </sdk:DataGrid>

    </Border>

    </Grid>

    </UserControl>



    Also u need a converter.


    namespace ccc.RI.Common.Converters

    {

        public class BindingConverter  : IValueConverter

        {


            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

            {

                if (value.GetType().Name == "Binding")

                {

                    ContentControl cc = new ContentControl();

                    Binding newValue = value as Binding;

                    newValue.Mode = BindingMode.TwoWay;

                    cc.SetBinding(ContentControl.ContentProperty, newValue as Binding);

                    return cc;

                }

                else

                {

                    return value;

                }

            }


            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

            {

                return null;

            }

        }

    }



    Hope this helps