This question already has answers here:
ComboBox ItemsSource changed => SelectedItem is ruined
(8 answers)
Closed 4 years ago.
I have following Situation.
I have a ListView set up as following:
<ListView Margin="3,3,3,3" ItemsSource="{Binding Toner}" SelectedValue="{Binding CurrentToner}" IsSynchronizedWithCurrentItem="True">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="BorderBrush" Value="LightGray" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{Binding Id}" FontWeight="Bold"></Label>
<Label Grid.Row="0" Grid.Column="1" Content="{Binding Name}" FontWeight="Bold"></Label>
<Label Grid.Row="1" Grid.Column="0" Content="{Binding Ratio}">
</Label>
<Label Grid.Row="1" Grid.Column="1" Content="{Binding TonerType.Name}" ></Label>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I set the Property CurrentToner in the corresponding ViewModel:
private Toner currentToner = new Toner();
public Toner CurrentToner
{
get => currentToner;
set
{
SetProperty(ref currentToner, value);
updateTonerCommand.RaiseCanExecuteChanged();
deleteTonerCommand.RaiseCanExecuteChanged();
increaseAmountCommand.RaiseCanExecuteChanged();
RaisePropertyChanged(nameof(Changes));
}
}
Now in the same View as above i also have some Controls bound to Properties of the CurrentToner.
<TextBox Style="{StaticResource TextBoxStyle}" Grid.Row="0" Grid.Column="1" Text="{Binding CurrentToner.Name}"></TextBox>
<TextBox Style="{StaticResource TextBoxStyle}" Grid.Row="1" Grid.Column="1" Text="{Binding CurrentToner.Level}" ></TextBox>
<ComboBox Grid.Row="2" Grid.Column="1" SelectedValue="{Binding CurrentToner.TonerType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding TonerTypes, Mode=OneWay}" DisplayMemberPath="Name"></ComboBox>
<TextBox Style="{StaticResource TextBoxStyle}" Grid.Column="1" Grid.Row="3" Text="{Binding CurrentToner.Note}" AcceptsReturn="True" VerticalScrollBarVisibility="Visible"></TextBox>
Now i can click arround in the ListView and my TextControls will be updated as they are supposed to.
However, if i reload the Data in the Observable Collection, the selected Item will no longer be updated in the Combobox (The data is still available, i checked with the Debugger and the Combobox can still set the TonerType in the CurrentToner)
I reload the Data from an SQL Server using Entity Framework :
private void ReloadToner()
{
Toner.Clear();
using (var uw = new UnitOfWork(new Gritly_DEVEntities1()))
{
Toner.AddRange(uw.Toners.GetAll());
}
}
How do i have to implement my Reload logic to update the selected item again? (It works before the reload)
EDIT: Screenshots of how it is supposed to be and how it's not.
it should be like this
not like this
EDIT2: I found the Answer, I had to override Equals() on TonerType to compare based on Id instead of Adress
If you reload the data then you have new objects in your collection.
I missed what that object type is if it's there but let's call that a Toner anyhow.
Make sure Toner has something uniquely identifies it, like an ID.
If you look at a Toner object , you can probably work out which is the old current one but computers are very literal minded. They need you to tell them exactly how they're supposed to know a Toner is a specific Toner rather than just any old one.
When you're going to re-read your data, save that ID in a private variable.
Read the data.
Build your observable collection.
Find the appropriate entry using some linq matching on id.
Something like:
Toner newSelectedToner = Toners.Where(x=>x.ID = lastSelectedID).FirstOrDefault();
That's just air code by the way.
Set CurrentToner to that instance.
Also, override equals on your Toner to use ID.
Related
i have a list box in which there are different controls like button , text box etc in its item template, i have a collection which i bind with listbox, it works fine , but now i want to move my code to MVVM , and i write some commands in my View Model for clicks events of buttons , how can i bind my collection + my commands to list box ??? because commands are not in the collection, this is the Data Template for my list Box
<DataTemplate x:Key="listItemTemplate">
<Grid ShowGridLines="False">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Name="commentsPanel" LastChildFill="False" MinWidth="350">
<TextBlock Name="txtUserName" IsEnabled="False" Text="{Binding UserName}"
Width="Auto" DockPanel.Dock="Left" Foreground="GhostWhite" Margin="0,6,0,0"></TextBlock>
<TextBlock Name="txtDate" IsEnabled="False" Text="{Binding CreateDt}"
Width="Auto" DockPanel.Dock="Left" Foreground="Green" Margin="4,6,0,0"></TextBlock>
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" Width="{Binding EditPanelWidth}" x:Name="EditDeletePanel" Visibility="{Binding ButtonVisibilityText }">
<Button Name="btnEdit" Content="Edit" Width="Auto" DockPanel.Dock="Right" Height="20"
Click="btnEdit_Click_1" Margin="4,4,0,4" Foreground="GhostWhite" VerticalContentAlignment="Top" Visibility="{Binding ButtonVisibilityText}"></Button>
<Button Name="btnDelete" Content="Delete" Width="Auto" Height="20" VerticalContentAlignment="Top" DockPanel.Dock="Right" Visibility="{Binding ButtonVisibilityText}"
Click="btnDelete_Click_1" Margin="4"></Button>
</StackPanel>
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" x:Name="SaveCancelPanel" Visibility="{Binding CancelSaveEnableText}">
<Button Name="btnSave" Content="Save" Width="Auto" Height="20" DockPanel.Dock="Right"
Click="btnSave_Click_1" Margin="4"></Button>
<Button Name="btnCancel" Content="Cancel" Height="20" Width="Auto" DockPanel.Dock="Right"
Click="btnCancel_Click_1" Margin="4"></Button>
</StackPanel>
</DockPanel>
<dxe:TextEdit ShowBorder="False" Grid.Row="1" Name="txtComment" Width="Auto" Foreground="Red"
TextWrapping="WrapWithOverflow" EditValue="{Binding Note}" IsEnabled="{Binding IsCommentTextEnable}">
</dxe:TextEdit>
<dxe:TextEdit Text=".............." Grid.Row="2" ShowBorder="False" IsEnabled="False">
</dxe:TextEdit>
</Grid>
</DataTemplate>
and here is the collection + my commands which i want to bind to buttons ,
public ICommand CancelCommand
{
get { return _cancelCommand ?? (_cancelCommand = new CommandHandler(Cancel)); }
set { _cancelCommand = value; }
}
public TList<ProgramNote> NotesCollection
{
get { return _notes; }
set
{
_notes = value;
RaisePropertyChanged("NotesCollection");
}
}
I know i can use this code to bind my commands with button
<Button Command={Binding CancelCommand}
but this command is not present in the collection , i am new in MVVM , kindly help , may be i am missing some little thing to bind my commands , but i am confused that how to add commands in my collection , so that i can get them in my view
You can bind the commands to your data template buttons etc by finding the appropriate viewmodel
example
<DataTemplate x:Key="listItemTemplate">
<Button Command="{Binding DataContext.CancelCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=LixtBox}}"
CommandParameter="{Binding}">
</DataTemplate>
in example we'll find the datacontext of LixtBox which I assume to be your viewmodel then will bind to the command and pass the current object as the command parameter to perform actions on.
you'll then receive the item as parameter in the implementation of your command
public void Execute(object parameter)
{
ProgramNote note = parameter as ProgramNote;
//your logic here, eg cancelling download etc.
}
Thanx to all of you specially thanx to #Sheridan and #PushPraj, I am able to do it now , here is the code of data template in which i have a button
<Button Name="btnCancel" Content="Cancel" Height="20" Width="Auto" DockPanel.Dock="Right"
Command="{Binding DataContext.CancelCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dxe:ListBoxEdit}}"
CommandParameter="{Binding}" Margin="4"></Button>
and this is the code of ListBox
<dxe:ListBoxEdit Name="listComments" Grid.Row="1" ItemTemplate="{StaticResource listItemTemplate}"
ItemsSource="{Binding NotesCollection}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Visible" >
</dxe:ListBoxEdit>
and lastly this is my back end code
listComments.DataContext = viewModel;
It's always difficult to answer new user's questions because they always leave out important information from their questions. However, judging by your question text, it sounds to me like you have set your collection property as the DataContext of your Window. If you want to data bind to your commands instead, then you'll need to change the DataContext to the object that contains both the collection and the commands... an instance of your view model:
DataContext = new YouViewModel();
Now that the DataContext is set to an instance of your view model, you can data bind to its properties as you showed us:
<Button Command="{Binding CancelCommand}" />
...
<ListBox ItemsSource="{Binding NotesCollection}" />
Ahhh, sorry I misunderstood - so your Button is inside the ListBox. In that case, you could try something like this:
<Button Command="{Binding DataContext.CancelCommand,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
This should reach out of the scope of the collection, looking in the DataContext of a Window, so if you have set the instance of your view model to the Window.DataContext, this should work.
As silly as this sounds I'm a little stumped at this one. Here's my XAML in a Win Phone 8 App:
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="Page" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector x:Name="MainLongListSelector" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="MainLongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock x:Name="TextBlock1" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
</Grid>
I've searched around but I don't know why I can't write code against the TextBlock1 control in code behind. When I type TextBlock1.Text= .... I get the error TextBlock1 is not declared. It may be inaccessible due to its protection level. But I can't see how it is private?
All I'm trying to do is add a textblock, assign some content to it, and then that selected value is passed across another page to perform relevant action.
In addition as soon as I remove it outside of the PhoneListSelector I can access it.
TextBlock1 is defined inside an ItemTemplate, anything defined a Template cannot be access directly as it will be created on runtime by the control.
You probably need to do binding on the TextBlock if you want to manipulate anything that the LongListSelector's DataContext has.
<phone:LongListSelector x:Name="MainLongListSelector" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="MainLongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock x:Name="TextBlock1" Text="{Binding Content"} HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
MainLongListSelector.DataContext = new List<TestViewModel>();
public class TestViewModel : INotifyPropertyChanged
{
//Assuming you've implemented the interface
private string _content;
public string Content { get { return _content; } { set { _content = value; NotifyOfPropertyChanged("Content"); } }
}
From here, you can try to access the selected value content and pass that to the next page.
var selectedItem = MainLongListSelector.SelectedItem as TestViewModel;
GoToNextPage(selectedItem.Content);
I strongly suggest to read MVVM design pattern and everything should be easy for you to implement, always remember UI is not DATA it's responsibility is only to show something that is passed through the ViewModel.
I have implemented a DataGrid that way:
<DataGrid
x:Name="MyDataGridFilter"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn
x:Name="FilterTextCol01">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox
Grid.Column="0"
IsHitTestVisible="True"
Text="{Binding Path=FilterTextCol01}" />
<CheckBox
Grid.Column="1"
x:Name="FilterAktivTextCol01"
IsHitTestVisible="True"
IsChecked="{Binding Path=FilterAktivTextCol01}"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The binding in the Code goes this way:
FilterItemsList = new ObservableCollection<DataGridFilterEntity>();
MyDataGridFilter.DataContext = FilterItemsList;
(it is shorted)
FilterItemsList is implemented as an INotifyPropertyChanged clas:
public class DataGridFilterEntity : INotifyPropertyChanged
With the member FilterTextCol01 (of course):
public string FilterTextCol01
{
get { return _FilterTextCol01; }
set
{
_FilterTextCol01 = value;
Changed("FilterTextCol01");
}
}
Everything works fine. When I change the FilterItemsList the DataGrid refelcts these changes.
But when I make some changes in the UI (in the DataGrid) it isn't reflected by the ObservableCollection (FilterItemsList).
I searched and tried some hours but did not find any solution.
Does anyone know how to solve this?
Thank you!
You need TwoWay binding.
For example,
<TextBox
Grid.Column="0"
IsHitTestVisible="True"
Text="{Binding Path=FilterTextCol01, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox
Grid.Column="1"
x:Name="FilterAktivTextCol01"
IsHitTestVisible="True"
IsChecked="{Binding Path=FilterAktivTextCol01, Mode=TwoWay}"/>
What kind of changes are you doing to the GUI? Are you updating the Text of the TextBox and checking the CheckBox?
If so the same example works in my case. I receive the updated text and checked boolean back in my model when I focus off the textbox or checkbox.
I've used the AutoCompleteBox without problem on a WPF form. Now I would like to do the same thing inside a WPF DataGrid. Almost everything works except the setter for SelectedItem. I see the getter get called but after typing a value and hitting tab (or using the arrow keys) the setter never gets called. In the console output I see no binding errors. I'm hoping someone can tell me what I'm doing wrong and how to get SelectedItem to fire the setter on the property in ViewModel class when it's inside a DataGrid. First the snippet of the ViewModel class:
public static List<ImpaSimple> AllImpas { get { return ImpaListRepository.ImpaList; } }
private ImpaSimple _selectedImpa;
public ImpaSimple SelectedImpa
{
get { return _selectedImpa; }
set
{
if (value == _selectedImpa) return;
_selectedImpa = value;
//Manually set Description and Unit fields because user can override the IMPA default values.
// Description = _selectedImpa.Name;
//TODO Set Units too
RaisePropertyChanged("SelectedImpa");
}
}
The XAML
In the XAML below I have added a code behind handler for LostFocus as a temporary work-around. The addition of the UpdateSourceTrigger attribute was also an attempt to get this working.
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<TextBlock Style="{StaticResource DataGridHeader}">LImpa</TextBlock>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Hots:AutoCompleteBoxEx ToolTip="Start typing an IMPA number"
ItemsSource="{Binding AllImpas}"
Width="50"
HorizontalContentAlignment="Left"
FilterMode="StartsWith"
IsDropDownOpen="True"
IsTextCompletionEnabled="True"
LostFocus="ImpaBoxExLostFocus"
SelectedItem="{Binding SelectedImpa,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<Hots:AutoCompleteBoxEx.ItemTemplate>
<DataTemplate>
<Grid Width="450">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="275" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding ImpaId}"
Grid.Column="0" />
<TextBlock Text="{Binding Name}"
Grid.Column="1" />
<TextBlock Text="{Binding Unit}"
Grid.Column="2" />
</Grid>
</DataTemplate>
</Hots:AutoCompleteBoxEx.ItemTemplate>
</Hots:AutoCompleteBoxEx>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
Ah, I think I know what that is - the defect I call 'shy datacontext' - try setting your
Hots:AutoCompleteBoxEx DataContext to:
DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type YourDataSourceItemType}}}"
The way to check it is create a dummy converter and use it like that:
ItemsSource="{Binding Converter={StaticResource DummyConverter}}"
then put a breakpoint inside its Convert and check for the value. Since no Path is specified - the input value is the DataContext itself, if it's null, then it never gets set/got lost.
I got a problem trying to find an element declared in DataTemplate, that after was applied like a ContentTemplate to TabItem object.
I saw that there is already some solutions in regard of this problem, but no one of them actually works in my case, and I would like to understand why (obviously I make mistake in some place)
Here is a sample code:
<DataTemplate x:Key="TabItemDataTemplate">
<Grid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Name="templateGrid">
<Grid.RowDefinitions>
<RowDefinition Height="6.0*"> </RowDefinition>
<RowDefinition Height="6" ></RowDefinition>
<RowDefinition Height="6.0*" ></RowDefinition>
<RowDefinition Height="*" ></RowDefinition>
</Grid.RowDefinitions>
<ListView x:Name="repoView" Grid.Row="0"
VerticalAlignment="Stretch"
ItemsSource="{Binding Source={StaticResource DataProviderForListView}}">
<GridView>
<GridViewColumn Header="State"
DisplayMemberBinding="{Binding Path=RepositoryItemState}"/>
<GridViewColumn Header="Working Copy Rev num."
DisplayMemberBinding="{Binding Path=WCRevision}"/>
<GridViewColumn Header="Repository Rev num."
DisplayMemberBinding="{Binding Path=RepoRevision}"/>
<GridViewColumn Header="User"
DisplayMemberBinding="{Binding Path=Account}"/>
<GridViewColumn Header="Item"
DisplayMemberBinding="{Binding Path=ItemName}"/>
</GridView>
</ListView>
<GridSplitter x:Name="gridSplitter" Grid.Row="1"
ResizeDirection="Rows" Background="Gray"
Height="4" HorizontalAlignment="Stretch"
Style="{StaticResource gridSplitterStyle}"/>
<RichTextBox x:Name="rowView" Grid.Row="2"
BorderBrush="Bisque" VerticalAlignment="Stretch"
IsReadOnly="True" Background="YellowGreen"
FontFamily="Comic Sans Serif"/>
<ToggleButton x:Name="rbWorkingCopy"
Template="{StaticResource ToggleButtonControlTemplate}"
Grid.Row="3" Width="100" Height="22"
Content="{StaticResource WorkingCopyTitle}"
HorizontalAlignment="Left" VerticalAlignment="Bottom"
Command="repoManager:AppCommands.GetWorkingCopyInfoCommand" />
<ToggleButton x:Name="rbRepository"
Template="{StaticResource ToggleButtonControlTemplate}"
Grid.Row="3" Width="100" Height="22"
Content="{StaticResource RepositoryTitle}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom" Margin="120,0,0,0"
Command="repoManager:AppCommands.GetRepoInfoCommand" />
<ProgressBar x:Name="checkRepositoryProgress" Grid.Row="3"
Width="220" Height="22" HorizontalAlignment="Right"
VerticalAlignment="Bottom" Margin="250,0,10,0"
IsIndeterminate="True"
IsEnabled="{Binding repoManager:ExecutingCommand}" />
</Grid>
</DataTemplate>
This code is porgrammatically applied to the given TabItem object in following way :
this.ContentTemplate = FindResource("TabItemDataTemplate") as DataTemplate;
After I need access to the ListView element declared in DataTemplate, so I execute the codes found around in internet, and also on this site. Here is a short example:
/* Getting the ContentPresenter of myListBoxItem*/
ContentPresenter myContentPresenter =
FindVisualChild<ContentPresenter>(this);
// this.GetVisualChild(0)
/* Finding textBlock from the DataTemplate that is set on that ContentPresenter*/
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
ListView repoListView = (ListView)myDataTemplate.FindName("repoView",
myContentPresenter);
Problem1: In this case ContentTemplate of ContentPresenter is Null, so code execution crashes.
Prolem2: Ok, I think, may be I need to navigate throw TabItem content directly, so the code becomes, more or less:
/* Getting the ContentPresenter of myListBoxItem*/
ContentPresenter myContentPresenter =
FindVisualChild<ContentPresenter>(this);
// this.GetVisualChild(0)
/* Finding textBlock from the DataTemplate that is set on that ContentPresenter*/
DataTemplate myDataTemplate = this.ContentTemplate;
ListView repoListView = (ListView)myDataTemplate.FindName("repoView",
myContentPresenter);
this is TabItem object. But the strage things, that the ContentTemplate of this is completely different from that one assigned above. I'm sure that I missed something somewhere, can you help me to figure out the problem ?
Thank you.
You don't want to use any of the template properties of the TabItem, since those are used to create the actual controls, rather than storing them. You should be able to search the visual tree for the ListView directly, rather than going through the DataTemplate.
Ok, here we come :)
I resolve the problem, in not very nice way, but it seems that works correctly.
As I mentioned above I used LoadContent method and it returns me the ListView object, but by the way it wasn't the ListView that UI actually uses. So to resolve that problem I add static property to hold my REAL ListView object (static as I have single DataTemplate that contains ListView shared across multiple TabItems, so the ListView shared too) and add event handler to my DataTemplate -> Loaded. Catching this event, that in my case raises only ones in lifetime of application, in RoutedEvent's OriginalSource I got the REAL ListView object that WPF engine uses for rendering on UI.
Hope my solution will help someone.
Thank you all.
Simply, if you have a DataGrid, and a TemplateColumn which contains a data template, you can use the following code sample:
<DataGridTemplateColumn x:Name="photoPathColumn" Header="{x:Static resx:FrmResource.Photo}" Width="Auto">
<DataGridTemplateColumn.CellEditingTemplate x:Uid="keyelm">
<DataTemplate x:Name="dodo">
<StackPanel Orientation="Horizontal" Height="Auto">
<TextBlock x:Name="photo" x:Uid="imageFile" Text="{Binding Path=PhotoPath}"></TextBlock>
<Button x:Name="Browse" Content="..." Click="Browse_Click"></Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
TextBlock tBlock = (TextBlok)photoPathColumn.CellEditingTemplate.FindName(
"photo",
photoPathColumn.GetCellContent(CustomersDataGrid.CurrentItem));
Where photo is the name of text block
Where photoPathColumn is the DataGrid's TemplateColumn.