views:

2004

answers:

3

Hi. I am in the process of implimenting the MVVC pattern and am having trouble binding a property in the viewmodel from within a DataTemplate within a datagrid. If I have a textblock outside the DataTemplate in the column it works fine (since I am directly referencing the datacontext of the UserConrol, i.e. the VM) however from within the DataTemplate it wont return the plain text property. It will however return a property from the iterated IEnumerable item.

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  
    x:Class="Timesheet.Silverlight.Modules.Views.HistoryView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     
    xmlns:Commands="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:ViewModels="clr-namespace:Timesheet.Silverlight.Modules.ViewModels" 
   x:Name="View">
    <StackPanel>            
    <TextBlock Text="{Binding Path=DataContext.testText, ElementName=View}" />    
            <data:DataGrid  Height="280" Width="500" ItemsSource="{Binding TimeSlots}" AutoGenerateColumns="False" >                        
            <data:DataGrid.Columns>
                <data:DataGridTextColumn Header="Allocation Area" Binding="{Binding TimeAllocationArea.TimeAllocationName}" Width="200" />
                <data:DataGridTextColumn Header="Start" Binding="{Binding StartTime}" Width="80" />
                <data:DataGridTextColumn Header="End" Binding="{Binding Path=DataContext.testText, ElementName=View}" Width="80" />
                <data:DataGridTemplateColumn Header="Modify" Width="200" >
                    <data:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Path=DataContext.testText, ElementName=View}" />
                            </StackPanel>
                        </DataTemplate>
                    </data:DataGridTemplateColumn.CellTemplate>
                </data:DataGridTemplateColumn>
            </data:DataGrid.Columns>
        </data:DataGrid>    
    </StackPanel>
</UserControl>

Is there some sort of problem with the DataTemplate that im ignoring?? Note the "{Binding Path=DataContext.testText, ElementName=View}" works for all elements except the one in the DataTemplate. (Note I know that the 1st Textblock outside the DG doesnt need the ElementName etc but i have just done it this way to prove to myself that its referencing the right thing)

A: 

Make sure you set the ItemSource of the data grid. Mark

Mark Cooper
If you read the source code you might notice i had already done that
Rob
A: 

I don't know if this applies to SL, but you can check this out:

"The Columns collection is just a property in the Datagrid; this collection is not in the logical (or visual) tree, therefore the DataContext is not being inherited, which leads to there being nothing to bind to."

http://blogs.msdn.com/jaimer/archive/2008/11/22/forwarding-the-datagrid-s-datacontext-to-its-columns.aspx

gschuager
Jaime's post is specific to WPF but definitely explains why this doesn't work in both WPF and Silverlight. However, the workaround in Jaime's post won't work for element-to-element data binding so it doesn't solve this issue.
Matt Casto
A: 

You can still data bind to static resources inside your DataTemplates even when element-to-element data binding doesn't work. One method for views to reference the view model in the MVVM pattern is storing the view model in a static resource, such as the ViewModelLocator used by the MVVM Light Toolkit.

Assuming your view model is named TestViewModel, I can modify your example XAML to use a ViewModelLocator and end up with this.

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  
    x:Class="Timesheet.Silverlight.Modules.Views.HistoryView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     
    xmlns:Commands="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:ViewModels="clr-namespace:Timesheet.Silverlight.Modules.ViewModels" 
    x:Name="View"
    DataContext="{Binding TestViewModel, Source={StaticResource Locator}}"
    >
    <StackPanel>            
        <TextBlock Text="{Binding Path=DataContext.testText, ElementName=View}" />    
        <data:DataGrid  Height="280" Width="500" ItemsSource="{Binding TimeSlots}" AutoGenerateColumns="False" >                        
            <data:DataGrid.Columns>
                <data:DataGridTextColumn Header="Allocation Area" Binding="{Binding TimeAllocationArea.TimeAllocationName}" Width="200" />
                <data:DataGridTextColumn Header="Start" Binding="{Binding StartTime}" Width="80" />
                <data:DataGridTextColumn Header="End" Binding="{Binding Path=DataContext.testText, ElementName=View}" Width="80" />
                <data:DataGridTemplateColumn Header="Modify" Width="200" >
                    <data:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <!--<TextBlock Text="{Binding Path=DataContext.testText, ElementName=View}" />-->
                                <TextBlock Text="{Binding Source={StaticResource Locator}, Path=TestViewModel.testText}" />
                            </StackPanel>
                        </DataTemplate>
                    </data:DataGridTemplateColumn.CellTemplate>
                </data:DataGridTemplateColumn>
            </data:DataGrid.Columns>
        </data:DataGrid>    
    </StackPanel>
</UserControl>
Matt Casto