I'm going to come right out and say that you probably don't want to walk the visual tree to achieve your goal (particularly if it is to only do something with the buttons / set cell color)...
The controls on the rows will come in and out of existance as the datagrid is scrolled by the user meaning you would need to constantly monitor and update this (for small numbers of rows this probably wont happen, but it should give indication that this isn't a good way to approach things, but LPL has linked to a relevant answer for that if you really are needing to go that route).
In order to do something when the buttons are clicked, then you would want to setup commands on those buttons and bind them in your data model; this page is a tutorial application which describes and shows how to bind commands MSDN: WPF Apps With The Model-View-ViewModel Design Pattern
You can then use a style with a binding or datatrigger to alter the background color on a cell (among many other things). I've knocked together a quicky example to show this in action (although I haven't used command binding for this small example, but I do highly recommend doing so).
Firstly you xaml modified to have a background color bind, and to also trigger a function on Button click of ModuleLock.
<DataGrid SelectionUnit="FullRow" SelectionMode="Single" AutoGenerateColumns="False" Name="LockDataGrid" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn IsReadOnly="True" Header="Name" Width="200" Binding="{Binding Name}">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="{Binding CellColor}" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn IsReadOnly="True" Header="ModuleLock" Binding="{Binding ModuleLock}"></DataGridTextColumn>
<DataGridTextColumn IsReadOnly="True" Header="StringLock" Binding="{Binding StringLock}"></DataGridTextColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Click="Button_Click">Lock module string</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button>Lock strings</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Next the button click handler in the code behind, in this example I'm simply only going to set the CellColor property of the row data to Red. As mentioned above a command could be setup for the button which can be configured to be much more relevant (e.g. the commandparameter could be set to the DataContext which in the default case will be the data for the row).
private void Button_Click(object sender, RoutedEventArgs e)
{
var lockModuleButton = sender as Button;
if (lockModuleButton == null)
{
return;
}
var theRowData = lockModuleButton.DataContext as Class1;
if (theRowData == null)
{
return;
}
theRowData.CellColor = "Red";
}
And one final important part - The data class (where I've created the CellColor property) will need to notify of property changes so that the binding updates INotifyPropertyChanged (also note I've only bothered to setup the CellColor to update bindings when it changes):
using System.ComponentModel;
namespace WpfApplication7
{
class Class1 : INotifyPropertyChanged
{
private string cellColor;
public string CellColor
{
get
{
return cellColor;
}
set
{
cellColor = value;
OnPropertyChanged("CellColor");
}
}
public bool ModuleLock { get; set; }
public bool StringLock { get; set; }
public string Name { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
}
}
And here is the quick code in the window open event to dummy up some data and set the datacontext of the DataGrid:
public MainWindow()
{
InitializeComponent();
List<Class1> MyList = new List<Class1>();
MyList.Add(new Class1());
MyList.Add(new Class1());
MyList.Add(new Class1());
MyList.Add(new Class1());
MyList.Add(new Class1());
MyList.Add(new Class1());
LockDataGrid.ItemsSource = MyList;
}
Edit: While building this I spotted that the actual problem you're wanting to solve is to lock down access to those string fields when the button is pressed (it may be worth updating your question to reflect this if that is the case, and if so I will refine this answer down if it meets your needs or is along the right track).
Unfortunately it appears that the DataGrid isn't well designed for this (from what I can see anyway) - however it can be done by using DataGridTemplateColumn
With the following for the column:
<DataGridTemplateColumn Header="ModuleLock">
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="IsEditing" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Background="{Binding CellColor}" Text="{Binding ModuleLock}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Background="{Binding CellColor}" BorderThickness="0" IsReadOnly="{Binding ModuleLockFlag}" Text="{Binding ModuleLock}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The style (LPL will recognise it ;) is there because there is strange focusing behaviour with the mouse; unfortunately you will want something else for a slight odd behaviour with using tab focusing that can be found here: