5

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>

Community
  • 1
  • 1
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
  • Do you have an element named "LayoutRoot", on which you've set the DataContext to your ViewModel? Could you post a little more XAML (specifically the definition of the "LayoutRoot" element)? Thanks! – Mark Carpenter Feb 19 '11 at 01:40
  • I'm not a WPF expert at all, but isn't LayoutRoot built in - isn't that automatically the top-most UI element in scope? Or is that just completely wrong and I need to add a name of LayoutRoot to said UI element? Actually, I can see fairly clearly that's the case. Just write that in an answer and I'll close this up. Thanks. – Adam Rackis Feb 19 '11 at 01:58
  • Actually, no, it didn't. I was convinced it would. Updating the question now... – Adam Rackis Feb 19 '11 at 02:55
  • +1, very good question. I'm very surprised by this behavior and the answer I posted isn't a very good solution but it's the only one I can think of. I have no idea why it doesn't work with ElementName or RelativeSource but I'll be observing this question to see if someone comes up with a better explanation or workaround for this :) – Fredrik Hedblad Feb 19 '11 at 03:11
  • @Adam Rackis: See my updated answer for a workaround – Fredrik Hedblad Feb 19 '11 at 21:42

2 Answers2

3

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.

Danny S
  • 403
  • 4
  • 12
2

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>
Fredrik Hedblad
  • 83,499
  • 23
  • 264
  • 266
  • It may not have a data context, but it still supports DataBinding, doesn't it? In the columns when binding text to a column (or a button) wouldn't the same binding expressions work as anywhere else? Sorry, again, I'm not a WPF expert. – Adam Rackis Feb 19 '11 at 03:11
  • @Adam Rackis: The problem as I see it has nothing to do with DataContext. I agree with you, and I can't see any reason for your the Binding in your question not to work. I tried a bunch of different ways of getting this to work but they all failed when using RelativeSource or ElementName – Fredrik Hedblad Feb 19 '11 at 03:15
  • 1
    Bah - I guess it's not just me then - hopefully something will come up. I don't want to go stringing this together in the code behind if possible. – Adam Rackis Feb 19 '11 at 03:17
  • @Adam Rackis: Clarifying my comment. It has nothing to do with the DataContext of the `Button` – Fredrik Hedblad Feb 19 '11 at 03:17
  • ok - thanks again for the help. I'll upvote your answer either way once I can get this resolved. – Adam Rackis Feb 19 '11 at 03:19
  • Thanks for the update. Might be Monday morning before I get back to this - thanks again! – Adam Rackis Feb 19 '11 at 22:17
  • Thanks again for the answer, and all the work you put into writing it. +1, but I have to accept the RelativeSource/Ancestor Binding answer. Much simpler for me to implement. Thanks again again! – Adam Rackis Feb 21 '11 at 16:27
  • @Adam Rackis: I couldn't get RelativeSource to work but if it's working for you then that's the way to go for sure! – Fredrik Hedblad Feb 21 '11 at 17:01