1

I have the following grid:

<DataGrid 
    x:Name="CandiesDataGrid" 
    ItemsSource="{Binding Candies}" 
    SelectedItem="{Binding SelectedCandy}">

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <i:InvokeCommandAction Command="{Binding CandySelectedCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>

    <DataGrid.Columns>
        <DataGridTextColumn KeyboardNavigation.IsTabStop="False" IsReadOnly="True" Width="100" Header="{l:LocText Candy_Prop1}" Binding="{Binding CandyInfo.Name}"/>
        <DataGridTemplateColumn >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox Name="IsConfirmed" Grid.Column="0"
                        Style="{StaticResource CandyCheckBox}"
                        IsChecked="{Binding IsConfirmed, Mode=TwoWay}"
                        Margin="-75 0 0 0"
                        Command="{Binding IsConfirmedCommand}">

                    </CheckBox>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

    </DataGrid.Columns>
</DataGrid>

My property uses the OnPropertyChanged. Not only it does not change the value of IsConfirmed but also does not executes the ICommand IsConfirmedCommand.

I searched on the internet and it seems DataGridTemplateColumn loses the ItemSource of the datagrid.

I did try to put RelativeSource in after the mode=TwoWay on my checkbox but it does not work.

Is there any way to have access to the ItemSource in my TemplateColumn?

EDIT:

//Properties
public ObservableCollection<Candy> Candies{ get; } = new ObservableCollection<Candy>();

public Candy SelectedCandy { get { return _selectedCandy; } set { SetProperty(ref _selectedCandy, value); } } //SetProperty acts as OnPropertyChanged

private Candy _selectedCandy;

//Constructor:
        public CandyClass()
        {
            IsConfirmedCommand = new DelegateCommand(IsConfirmedCommand_Execute);
        }

//Method
        private void IsConfirmedCommand_Execute()
        {
            //Doing something
        }
4
  • 1
    please show definitions of your view models Commented Aug 22, 2019 at 19:52
  • 1
    In the CellTemplate, the datacontext will be the row, a Candy instance. That's the point of a grid. To bind to a property of the "parent" viewmodel that owns the Candies collection, you'll need a binding that goes back up the visual tree and locates the command on the DataContext of the DataGrid: Command="{Binding DataContext.IsConfirmedCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}" What is IsConfirmed a property of? Commented Aug 22, 2019 at 20:06
  • 1
    "I did try to put RelativeSource in after the mode=TwoWay on my checkbox" -- please don't say you "tried something" without telling us what you tried. RelativeSource isn't a magic spell that just makes things work via pony sparkles, and if the pony sparkles fail you toss it in the bin. You have to understand what it does and use it correctly. We can help you with that. Commented Aug 22, 2019 at 20:11
  • 1
    Maybe I did try it in the wrong way, is it possible that you make an aswer in how to use RelativeSource and what is it that solves the issue? IsConfirmed is a property of Candy and is a bool. Commented Aug 22, 2019 at 20:14

1 Answer 1

3

Inside your CellTemplate, the DataContext is the DataGrid row, whatever that may be (Candy in this case). So by default, that Candy instance will be the Source property of any Binding in that DataTemplate. That's where the binding will look for the property named in the Path (IsConfirmed and IsConfirmedCommand, in this case).

That's what you want: You've got more than one row in the grid, and the row is what you care about in a cell, usually. That or the field: But very often a cell template will want to look at more than one field, so they give you the whole row.

But in this case, you want to go back up and grab something off the parent viewmodel. Viewmodels have no natural parent/child hierarchy, though you could give them one if you wanted: Candy could have a Parent property that had reference to the viewmodel that owns the Candies collection. If you did, you could bind like this:

Command="{Binding Parent.IsConfirmed}"

But that's not common practice. I don't know if it's a particularly great idea or not.

One reason we don't need to do that is we can tell the binding to use a different source instead. UI elements do have a natural parent/child hierarchy, and bindings can navigate it. If you’re doing things right, your parent viewmodel will be the DataContext of something up there somewhere.

{Binding Path=DataContext.IsConfirmed, 
        RelativeSource={RelativeSource AncestorType=DataGrid}}

"Walk the UI tree upwards until you find a DataGrid. That's your source. Now, once you have a source, find the source object's DataContext property, if any. If it's got a DataContext, take the value of DataContext and look on that object for some property called IsConfirmed."

DataGrid has a DataContext property. Since your binding to Candies worked, we know that DataContext must be your class that has a Candies property. You assure me that class has IsConfirmed as well.

Hence:

<DataTemplate>
    <CheckBox 
        Style="{StaticResource CandyCheckBox}"
        IsChecked="{Binding DataContext.IsConfirmed, 
            RelativeSource={RelativeSource AncestorType=DataGrid}}"
        Margin="-75 0 0 0"
        Command="{Binding DataContext.IsConfirmedCommand,
            RelativeSource={RelativeSource AncestorType=DataGrid}}"
        />
</DataTemplate>

Sign up to request clarification or add additional context in comments.

2 Comments

Great, Now the command is working, what it does not seem to work is the IsChecked for some reason. I did put a break point in my IsConfirmed property but never goes to the set property.
Either IsConfirmed is called something else, or it's a property of a different class than IsConfirmedCommand. That's the property you didn't include in your question. If one of those bindings works, the other will work -- provided the source property is actually there. Check in the VS Output pane for binding errors. Add PresentationTraceSources.TraceLevel=High for a large amount of very detailed diagnostics. Just remember not to leave it there; it's expensive.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.