2

I have a DataGrid with DataGridTemplateColumn. The DataGridTemplateColumn contains a button and TextBlock. I want that pressing the button will clear the textBlock's text. How do I do that ?

enter image description here

XAML:

 <Grid>
    <DataGrid ItemsSource="{Binding Persons}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}">
            </DataGridTextColumn>
            <DataGridTemplateColumn Header="Mask Expiration Time">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                            <TextBlock Text="{Binding Name}"></TextBlock>
                            <Button Name="btnClear" Click="btnClear_Click" >Clear</Button>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

CS code:

 public partial class MainWindow : Window
{
    public List<Person> Persons { get; set; }

    public MainWindow()
    {
        Persons = new List<Person> { new Person { Name = "James" }, new Person { Name = "Kate" } };
        DataContext = this;
        InitializeComponent();
    }

    private void btnClear_Click(object sender, RoutedEventArgs e) {
        var clearbutton = (Button) sender;

        // clear the Name
    }
}

public class Person
{
    public string Name { get; set; }
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
Erez
  • 6,405
  • 14
  • 70
  • 124

3 Answers3

2

I would suggest using a Command instead and passing the current Person object via the CommandParameter property. Something like this:

<Button Content="Clear" 
        Command="{Binding DataContext.ClearNameCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" 
        CommandParameter="{Binding}" />

then all you'd need to do is set the property of the object (and update the binding, since it doesn't look like Person implements INotifyPropertyChanged)

H.B.
  • 166,899
  • 29
  • 327
  • 400
Tim
  • 14,999
  • 1
  • 45
  • 68
  • Very redundant, you have the `Person` already in the `Button.DataContext`. – H.B. May 23 '11 at 16:38
  • If you want to be accessing parts of the UI, yeah. But no reason to do so, in my opinion. He's already working with bindings, might as well stick with the MVVM pattern. Your code is certainly simpler though. Probably just personal opinion. – Tim May 23 '11 at 16:42
  • The asker indicated in the code that click-event is being used, that is why i suggested using the DataContext. – H.B. May 23 '11 at 16:55
  • @H.B. I understand. His code sample showed the click event, but he didn't say that was a requirement. I was just giving him my recommendation for the whole solution. Looks like sixlettervariables did similar as well. Perhaps I overstepped. But like I said, I think its probably just personal preference - I'm always going to suggest an MVVM-style solution unless something in the question precludes that. – Tim May 23 '11 at 16:57
  • I guess I should weigh in now that I've been named, I'm not a fan of any of these solutions as it sort of breaks the distinction between the data grid's view and edit modes. But that's just me. If he's already doing work in the click handler, he should go with @H.B.'s, if he's not he should go with @Tim's or mine. But I agree with @H.B. regarding the Path=DataContext.ClearNameCommand, it likely should just be Path=ClearNameCommand. – user7116 May 23 '11 at 17:06
  • Are you talking about the binding on Command in Button in my example? It can't be just ClearNameCommand - the DataContext of the Button is the current Person object since its inside his DataTemplate. Or am I missing something? – Tim May 23 '11 at 17:13
  • The binding is fine, since a source is specified the DataContext is needed in the path, i did mean the whole commanding-approach when i said "redundant". – H.B. May 23 '11 at 17:15
  • I'd just place the ClearNameCommand on the Person VM, but that's me. – user7116 May 23 '11 at 17:49
2

Use the inherited DataContext of the Button:

var person = (sender as FrameworkElement).DataContext as Person;
person.Name = String.Empty;
H.B.
  • 166,899
  • 29
  • 327
  • 400
  • Thanks! I don't care about architecture so much in this specific application and this is the easiest solution. – Erez May 24 '11 at 06:47
1

You could use an ICommand:

public class ClearNameCommand : ICommand
{
    public bool CanExecute(object parameter, IInputElement target)
    {
        var person = parameter as Person;
        return (person != null && person.Name.Length > 0);
    }

    public void Execute(object parameter, IInputElement target)
    {
        var person = parameter as Person;
        if (person != null)
        {
            person.Name = String.Empty;
        }
    }
}

Then in the XAML:

<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
    <TextBlock Text="{Binding Name}"></TextBlock>
    <Button x:Name="btnClear"
            Command="{StaticResource ClearCommand}"
            CommandParameter="{Binding}">Clear</Button>
</StackPanel>
H.B.
  • 166,899
  • 29
  • 327
  • 400
user7116
  • 63,008
  • 17
  • 141
  • 172