Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF DataGrid - Databinding Column to Page's ViewModel

Tags:

c#

wpf

I'm trying to bind a data on one of my columns to data that's in my page's ViewModel (as opposed to the objects that the grid is bound to).

What I have below was recommended here, to no avail.

   <DataGridTemplateColumn>
      <DataGridTemplateColumn.CellTemplate>
         <DataTemplate>
            <Button Content="{Binding ElementName=LayoutRoot, Path=DataContext.JUNK}"></Button>
         </DataTemplate>
      </DataGridTemplateColumn.CellTemplate>
   </DataGridTemplateColumn>

In my ViewModel

public string JUNK { get; set; }

Which is set to "HELLO" in the ViewModel's constructor

Does anyone see what I'm doing wrong?

EDIT

Here's the entire XAML. Relevant column is all the way at the bottom, in the grid within the grid

ALSO - I'm having trouble getting my entire source into here again (not sure if it's citrix or what) but I took that same exact binding expression that's not working in the datagrid's button, and I dropped it onto the Text of a plain old TextBlock apart from the grid, and it worked like a charm. I also added a new dummy text column to the grid, and used that same binding expression for the text, and it still did not work. It seems this binding expression is fine, but refuses to work anywhere near the grid.

<UserControl x:Class="MainApp.WPF.ucFmvHistoryDisplayGrid"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="1000" x:Name="LayoutRoot">

<UserControl.Resources>
    <Style x:Name="rightAlignedColumn" x:Key="rightAlignedColumn" TargetType="TextBlock">
        <Setter Property="HorizontalAlignment" Value="Right" />
    </Style>

    <Style x:Name="centerAlignedColumn" x:Key="centerAlignedColumn" TargetType="TextBlock">
        <Setter Property="HorizontalAlignment" Value="Center" />
    </Style>
</UserControl.Resources>

<Grid>
    <DataGrid x:Name="dbTop" ItemsSource="{Binding PropertyGroupSource}" HorizontalAlignment="Left" Background="White" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeRows="False" IsReadOnly="True" AutoGenerateColumns="False" Grid.Row="1" Width="800">
        <DataGrid.Columns>
            <DataGridTextColumn Width="120" Header="Property Num" Binding="{Binding PropertyNum}"></DataGridTextColumn>
            <DataGridTextColumn Width="120" Header="Alt Description" Binding="{Binding AltDescription}"></DataGridTextColumn>
            <DataGridTextColumn Width="80" Header="County" Binding="{Binding County}"></DataGridTextColumn>
            <DataGridTextColumn Width="100" Header="State" Binding="{Binding State}" ElementStyle="{StaticResource centerAlignedColumn}"></DataGridTextColumn>
            <DataGridTextColumn Width="85" Header="Phase" Binding="{Binding Phase}"></DataGridTextColumn>
            <DataGridTextColumn Width="85" Header="FMV" Binding="{Binding FmvTotal}"></DataGridTextColumn>
            <DataGridTextColumn Width="100" Header="Assessed Value" Binding="{Binding AssessedValueTotal}"></DataGridTextColumn>
        </DataGrid.Columns>
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <Border Margin="5" BorderBrush="Black" BorderThickness="1">
                    <DataGrid Margin="5" Background="White" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeRows="False" IsReadOnly="True" AutoGenerateColumns="False" Grid.Row="1" ItemsSource="{Binding PropertyFmvSource}">
                        <DataGrid.Columns>
                            <DataGridTextColumn Width="125" Header="County Acct Num" Binding="{Binding Property.CountyAccountNum, StringFormat=d}" ElementStyle="{StaticResource rightAlignedColumn}"></DataGridTextColumn>
                            <DataGridTextColumn Width="80" Header="City" Binding="{Binding Property.City, StringFormat=d}" ElementStyle="{StaticResource rightAlignedColumn}"></DataGridTextColumn>
                            <DataGridTextColumn Width="80" Header="Jurisdiction" Binding="{Binding Property.Jurisdiction, StringFormat=d}" ElementStyle="{StaticResource rightAlignedColumn}"></DataGridTextColumn>
                            <DataGridTextColumn Width="80" Header="FMV Date" Binding="{Binding MostRecentFMV.FMVDate, StringFormat=d}" ElementStyle="{StaticResource rightAlignedColumn}"></DataGridTextColumn>
                            <DataGridTextColumn Width="100" Header="FMV" Binding="{Binding MostRecentFMV.FMV, StringFormat=N0}" ElementStyle="{StaticResource rightAlignedColumn}"></DataGridTextColumn>
                            <DataGridTextColumn Width="85" Header="Assess Ratio" Binding="{Binding MostRecentFMV.AssessmentRatio, StringFormat=N3}" ElementStyle="{StaticResource rightAlignedColumn}"></DataGridTextColumn>
                            <DataGridTextColumn Width="105" Header="Assessed Value" Binding="{Binding MostRecentFMV.AssessedValue, StringFormat=N0}" ElementStyle="{StaticResource rightAlignedColumn}"></DataGridTextColumn>
                            <DataGridTemplateColumn>
                                <DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <Button Content="{Binding ElementName=LayoutRoot, Path=DataContext.JUNK}"></Button>
                                    </DataTemplate>
                                </DataGridTemplateColumn.CellTemplate>
                            </DataGridTemplateColumn>
                        </DataGrid.Columns>
                    </DataGrid>
                </Border>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
</Grid>

like image 330
Adam Rackis Avatar asked Feb 18 '11 20:02

Adam Rackis


2 Answers

Binding to the DataContext of the containing DataGrid using a RelativeSource binding should work:

<Button Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=2}, Path=DataContext.JUNK}"></Button>

As you've nested the DataGrids, the AncestorLevel must be set to "2" to Bind to the DataContext of the outermost DataGrid.

like image 165
Danny S Avatar answered Nov 15 '22 09:11

Danny S


Update

@Danny Shisler's answer is correct. Leaving this answer since it shows how to do Bindings inside of DataGridColumn which isn't in the Visual Tree and doesn't have a DataContext


Here is a blog post that presents a workaround for this issue: http://blogs.infragistics.com/blogs/josh_smith/archive/2008/06/26/data-binding-the-isvisible-property-of-contextualtabgroup.aspx

The workaround is to create a DataContextSpy that looks like this

DataContextSpy

public class DataContextSpy
: Freezable // Enable ElementName and DataContext bindings
{
    public DataContextSpy()
    {
        // This binding allows the spy to inherit a DataContext.
        BindingOperations.SetBinding(this, DataContextProperty, new Binding());
    }

    public object DataContext
    {
        get { return (object)GetValue(DataContextProperty); }
        set { SetValue(DataContextProperty, value); }
    }

    // Borrow the DataContext dependency property from FrameworkElement.
    public static readonly DependencyProperty DataContextProperty =
        FrameworkElement.DataContextProperty.AddOwner(typeof(DataContextSpy));

    protected override Freezable CreateInstanceCore()
    {
        // We are required to override this abstract method.
        throw new NotImplementedException();
    }
}

And then you can use an instance of DataContextSpy as the Source for the Bindings in the DataGridColumns like this

<Grid Name="LayoutRoot">
    <Grid.Resources>
        <local:DataContextSpy x:Key="dataContextSpy" />
    </Grid.Resources>
    <DataGrid ...>
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="{Binding Path=DataContext.JUNK,
                                           Source={StaticResource dataContextSpy}}">
                <!--..-->
            </DataGridTemplateColumn>
            <!--..-->
        </DataGrid.Columns>
    </DataGrid>
</Grid>
like image 34
Fredrik Hedblad Avatar answered Nov 15 '22 09:11

Fredrik Hedblad