Why would 'this.ContentTemplate.FindName' throw an InvalidOperationException on its own template? - wpf

Ok... this has me stumped. I've overridden OnContentTemplateChanged in my UserControl subclass. I'm checking that the value passed in for newContentTemplate does in fact equal this.ContentTemplate (it does) yet when I call this...
var textBox = this.ContentTemplate.FindName("EditTextBox", this);
...it throws the following exception...
"This operation is valid only on elements that have this template applied."
Per a commenter in another related question, he said you're supposed to pass in the content presenter for the control, not the control itself, so I then tried this...
var cp = FindVisualChild<ContentPresenter>(this);
var textBox = this.ContentTemplate.FindName("EditTextBox", cp);
...where FindVisualChild is just a helper function used in MSDN's example (see below) to find the associated content presenter. While cp is found, it too throws the same error. I'm stumped!!
Here's the helper function for reference...
private TChildItem FindVisualChild<TChildItem>(DependencyObject obj)
where TChildItem : DependencyObject {
for(int i = 0 ; i < VisualTreeHelper.GetChildrenCount(obj) ; i++) {
var child = VisualTreeHelper.GetChild(obj, i);
if(child is TChildItem typedChild) {
return typedChild;
}
else {
var childOfChild = FindVisualChild<TChildItem>(child);
if(childOfChild != null)
return childOfChild;
}
}
return null;
}

Explicitly applying the template before calling the FindName method will prevent this error.
this.ApplyTemplate();

As John pointed out, the OnContentTemplateChanged is being fired before it is actually applied to the underlying ContentPresenter. So you'd need to delay your call to FindName until it is applied. Something like:
protected override void OnContentTemplateChanged(DataTemplate oldContentTemplate, DataTemplate newContentTemplate) {
base.OnContentTemplateChanged(oldContentTemplate, newContentTemplate);
this.Dispatcher.BeginInvoke((Action)(() => {
var cp = FindVisualChild<ContentPresenter>(this);
var textBox = this.ContentTemplate.FindName("EditTextBox", cp) as TextBox;
textBox.Text = "Found in OnContentTemplateChanged";
}), DispatcherPriority.DataBind);
}
Alternatively, you may be able to attach a handler to the LayoutUpdated event of the UserControl, but this may fire more often than you want. This would also handle the cases of implicit DataTemplates though.
Something like this:
public UserControl1() {
InitializeComponent();
this.LayoutUpdated += new EventHandler(UserControl1_LayoutUpdated);
}
void UserControl1_LayoutUpdated(object sender, EventArgs e) {
var cp = FindVisualChild<ContentPresenter>(this);
var textBox = this.ContentTemplate.FindName("EditTextBox", cp) as TextBox;
textBox.Text = "Found in UserControl1_LayoutUpdated";
}

The ContentTemplate isn't applied to the ContentPresenter until after that event. While the ContentTemplate property is set on the control at that point, it hasn't been pushed down to bindings internal to the ControlTemplate, like the ContentPresenter's ContentTemplate.
What are you ultimately trying to do with the ContentTemplate? There might be a better overall approach to reach your end goal.

Related

WPF DataGrid: How to get binding expression of a cell?

I need to get access to the binding expression of the DataGrid cell in a DataGridTextColumn. For example:
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
I managed to get the TextBlock associated with the cell:
var cell = dataGrid.GetCellCtrl<TextBlock>(dataGrid.CurrentCell);
And cell seems to be correct. I can call
cell.SetValue(TextBlock.TextProperty, value);
To update the cell text. It seems to be working on the grid (number updated). However, as I realize after a while, the source doesn't get updated. It didn't help even if I turn UpdateSourceTrigger to PropertyChange. Then, I thought I need to get the binding expression and call UpdateSource explicitly.
var bindingExpr = cell.GetBindingExpression(TextBlock.TextProperty);
but bindingExpr is always null. Why?
EDIT:
The original problem I had was that I can get to the binding TextBlock for the cell, and set the TextBlock.TextProperty. However, the source doesn't get updated. This is something I'm trying to resolve this problem.
The TextBox in the DataGridTextColumn will not have a binding expression the column itself has the binding.
DataGridTextColumn is derived from DataGridBoundColumn which uses a BindingBase property not TextBlock.TextProperty, However the Binding property is not a DependancyProperty so you will have to access using normal public properties.
So you will have to do a bit of casting as the Binding property in DataGridTextColumn is type BindingBase.
Something like this should work (untested)
var binding = (yourGrid.Columns[0] as DataGridBoundColumn).Binding as Binding;
You need to find the TextBlock:
var textBlock = cell.FindVisualChild<TextBlock>();
BindingExpression bindingExpression = textBlock.GetBindingExpression(
TextBlock.TextProperty);
Code for FindVisualChild():
public static class DependencyObjectExtensions
{
[NotNull]
public static IEnumerable<T> FindVisualChildren<T>([NotNull] this DependencyObject dependencyObject)
where T : DependencyObject
{
if (dependencyObject == null) throw new ArgumentNullException(nameof(dependencyObject));
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(dependencyObject, i);
if (child is T o)
yield return o;
foreach (T childOfChild in FindVisualChildren<T>(child))
yield return childOfChild;
}
}
public static childItem FindVisualChild<childItem>([NotNull] this DependencyObject dependencyObject)
where childItem : DependencyObject
{
if (dependencyObject == null) throw new ArgumentNullException(nameof(dependencyObject));
foreach (childItem child in FindVisualChildren<childItem>(dependencyObject))
return child;
return null;
}
}
TextBox t = e.EditingElement as TextBox;
string b= t.GetBindingExpression(TextBox.TextProperty).ResolvedSourcePropertyName;

Force Propagation of Coerced Value

tl;dr: Coerced values are not propagated across data bindings. How can I force the update across the data binding when code-behind doesn't know the other side of the binding?
I'm using a CoerceValueCallback on a WPF dependency property and I'm stuck at the issue that coerced values don't get propagated through to bindings.
Window1.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace CoerceValueTest
{
public class SomeControl : UserControl
{
public SomeControl()
{
StackPanel sp = new StackPanel();
Button bUp = new Button();
bUp.Content = "+";
bUp.Click += delegate(object sender, RoutedEventArgs e) {
Value += 2;
};
Button bDown = new Button();
bDown.Content = "-";
bDown.Click += delegate(object sender, RoutedEventArgs e) {
Value -= 2;
};
TextBlock tbValue = new TextBlock();
tbValue.SetBinding(TextBlock.TextProperty,
new Binding("Value") {
Source = this
});
sp.Children.Add(bUp);
sp.Children.Add(tbValue);
sp.Children.Add(bDown);
this.Content = sp;
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value",
typeof(int),
typeof(SomeControl),
new PropertyMetadata(0, ProcessValueChanged, CoerceValue));
private static object CoerceValue(DependencyObject d, object baseValue)
{
if ((int)baseValue % 2 == 0) {
return baseValue;
} else {
return DependencyProperty.UnsetValue;
}
}
private static void ProcessValueChanged(object source, DependencyPropertyChangedEventArgs e)
{
((SomeControl)source).ProcessValueChanged(e);
}
private void ProcessValueChanged(DependencyPropertyChangedEventArgs e)
{
OnValueChanged(EventArgs.Empty);
}
protected virtual void OnValueChanged(EventArgs e)
{
if (e == null) {
throw new ArgumentNullException("e");
}
if (ValueChanged != null) {
ValueChanged(this, e);
}
}
public event EventHandler ValueChanged;
public int Value {
get {
return (int)GetValue(ValueProperty);
}
set {
SetValue(ValueProperty, value);
}
}
}
public class SomeBiggerControl : UserControl
{
public SomeBiggerControl()
{
Border parent = new Border();
parent.BorderThickness = new Thickness(2);
parent.Margin = new Thickness(2);
parent.Padding = new Thickness(3);
parent.BorderBrush = Brushes.DarkRed;
SomeControl ctl = new SomeControl();
ctl.SetBinding(SomeControl.ValueProperty,
new Binding("Value") {
Source = this,
Mode = BindingMode.TwoWay
});
parent.Child = ctl;
this.Content = parent;
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value",
typeof(int),
typeof(SomeBiggerControl),
new PropertyMetadata(0));
public int Value {
get {
return (int)GetValue(ValueProperty);
}
set {
SetValue(ValueProperty, value);
}
}
}
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
Window1.xaml
<Window x:Class="CoerceValueTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CoerceValueTest" Height="300" Width="300"
xmlns:local="clr-namespace:CoerceValueTest"
>
<StackPanel>
<local:SomeBiggerControl x:Name="sc"/>
<TextBox Text="{Binding Value, ElementName=sc, Mode=TwoWay}" Name="tb"/>
<Button Content=" "/>
</StackPanel>
</Window>
i.e. two user controls, one nested inside the other, and the outer one of those in a window. The inner user control has a Value dependency property that is bound to a Value dependency property of the outer control. In the window, a TextBox.Text property is bound to the Value property of the outer control.
The inner control has a CoerceValueCallback registered with its Value property whose effect is that this Value property can only be assigned even numbers.
Note that this code is simplified for demonstration purposes. The real version doesn't initialize anything in the constructor; the two controls actually have control templates that do everything that's done in the respective constructors here. That is, in the real code, the outer control doesn't know the inner control.
When writing an even number into the text box and changing the focus (e.g. by focusing the dummy button below the text box), both Value properties get duly updated. When writing an odd number into the text box, however, the Value property of the inner control doesn't change, while the Value property of the outer control, as well as the TextBox.Text property, show the odd number.
My question is: How can I force an update in the text box (and ideally also in the outer control's Value property, while we're at it)?
I have found an SO question on the same problem, but doesn't really provide a solution. It alludes to using a property changed event handler to reset the value, but as far as I can see, that would mean duplicating the evaluation code to the outer control ... which is not really viable, as my actual evaluation code relies on some information basically only known (without much effort) to the inner control.
Moreover, this blogpost suggests invoking UpdateTarget on the binding in TextBox.Text in the CoerceValueCallback, but first, as implied above, my inner control cannot possibly have any knowledge about the text box, and second, I would probably have to call UpdateSource first on the binding of the Value property of the inner control. I don't see where to do that, though, as within the CoerceValue method, the coerced value has not yet been set (so it's too early to update the binding), while in the case that the value is reset by CoerceValue, the property value will just remain what it was, hence a property changed callback will not get invoked (as also implied in this discussion).
One possible workaround I had thought of was replacing the dependency property in SomeControl with a conventional property and an INotifyPropertyChanged implementation (so I can manually trigger the PropertyChanged event even if the value has been coerced). However, this would mean that I cannot declare a binding on that property any more, so it's not a really useful solution.
I have been looking for an answer to this rather nasty bug myself for a while.
One way to do it, without the need to force an UpdateTarget on the bindings is this:
Remove your CoerceValue callback.
Shift the logic of the CoerceValue callback into your ProcessValueChanged callback.
Assign your coerced value to your Value property, when applicable (when the number is odd)
You will end up with the ProcessValueChanged callback being hit twice, but your coerced value will end up being effectively pushed to your binding.
Base on your code, your dependency property declaration would become this:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value",
typeof(int),
typeof(SomeControl),
new PropertyMetadata(0, ProcessValueChanged, null));
And then, your ProcessValueChanged would become this:
private static void ProcessValueChanged(object source, DependencyPropertyChangedEventArgs e)
{
int baseValue = (int) e.NewValue;
SomeControl someControl = source as SomeControl;
if (baseValue % 2 != 0)
{
someControl.Value = DependencyProperty.UnsetValue;
}
else
{
someControl.ProcessValueChanged(e);
}
}
I slightly modified your logic, to prevent raising the event when the value needs to be coerced. As mentionned before, assigning to someControl.Value the coerced value will cause your ProcessValueChanged to be called twice in a row. Putting the else statement would only raise the events with valid values once.
I hope this helps!

In WPF, how to display AdornerLayer on top of DataGrid

I am using WPF datagrid from codeplex. I am using DatagridTemplateColumn and I have written datatemplates to display contents in each column.
Now I have to display some help message to a user when the any control in datagrid is focussed.
For this I thought of using adorner layer. I used ComboBox loaded event and accessed the adrorner layer of it. I then added my own adorner layer with some thing to be displayed there similar to tooltip. Below is the code.
TextBox txtBox = (TextBox)comboBox.Template.FindName("PART_EditableTextBox", comboBox);
if (txtBox == null)
return;
txtBox.ToolTip = comboBox.ToolTip;
AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(txtBox);
Binding bind = new Binding("IsKeyboardFocused");
bind.Converter = new KeyToVisibilityConverter();
bind.Source = txtBox;
bind.Mode = BindingMode.OneWay;
PEAdornerControl adorner = new PEAdornerControl(txtBox);
adorner.SetBinding(PEAdornerControl.VisibilityProperty, bind);
PEAdorner layer is this ::
public class PEAdornerControl : Adorner
{
Rect rect;
// base class constructor.
public PEAdornerControl(UIElement adornedElement)
: base(adornedElement)
{ }
protected override void OnRender(DrawingContext drawingContext)
{
.....
}
}
Now the problem is as follows. I am attaching screenshot of how it is looking in datagrid. If the datagrid has more than 4 rows, things are fine.Below is the screenshot
If the datagrid has less number of row, this adorner goes inside datagrid and is not visible to user. The screenshot is below
How do I get this adorner layer above the DataGrid? Please help me !!!
I looked at your question again and i think this is what you would need.
TextBox txtBox = (TextBox)comboBox.Template.FindName("PART_EditableTextBox", comboBox);
if (txtBox == null)
return;
txtBox.ToolTip = comboBox.ToolTip;
//this is locating the DataGrid that contains the textbox
DataGrid parent = FindParent<DataGrid>(this);
//Get the adorner for the parent
AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(parent);
Binding bind = new Binding("IsKeyboardFocused");
bind.Converter = new KeyToVisibilityConverter();
bind.Source = txtBox;
bind.Mode = BindingMode.OneWay;
PEAdornerControl adorner = new PEAdornerControl(txtBox);
adorner.SetBinding(PEAdornerControl.VisibilityProperty, bind);
The find parent method is this:
public T FindParent<T>(DependencyObject obj) where T : DepedencyObject
{
if (obj == null)
return null;
DependencyOBject parent = VisualTreeHelper.GetParent(obj);
if (parent is T)
return parent as T;
else
return FindParent<T>(parent);
}
You may need to set the position of your adorner in the OnRender method but this should work. One thing to consider though is that if your DataGrid is within another container (such as a panel, grid, etc) then you may still run into your clipping problem.
The clipping problem is due to the fact that when a container checks the layout of its children it does not normally take into account their adorners. To combat this you would possibly need to create your own control and override the MeasuerOverride(Size constraint) method.
Example:
public class MyPanel : Panel
{
protected override Size MeasureOverride(Size constraint)
{
Size toReturn = new Size();
foreach (UIElement child in this.InternalChildren)
{
//Do normal Measuring of children
foreach( UIElement achild in AdornerLayer.GetAdorners(child))
//Measure child adorners and add to return size as needed
}
return toReturn;
}
}
That code is really rough for measure but should point you in the right direction. Look at the documentation page http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.measureoverride.aspx for information about measuring child elements in a panel.
Just get the topmost AdornerLayer, instead
static AdornerLayer GetAdornerLayer(FrameworkElement adornedElement)
{
var w = Window.GetWindow(adornedElement);
var vis = w.Content as Visual;
return AdornerLayer.GetAdornerLayer(vis);
}
Also, if you have the name of your DataGrid you can get the nearest layer above it:
AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(myDataGrid);

WPF doesn't honor Textbox.MinLines for Auto height calculation

I want to have a TextBox which Height grows as Iam entering lines of Text.
I've set the Height property to "Auto", and so far the growing works.
Now I want that the TextBox's Height should be at least 5 lines.
Now I've set the MinLines property to "5" but if I start the app the TextBox's height is still one line.
Try setting the MinHeight property.
A hack to make the MinLines property work
public class TextBoxAdv : TextBox
{
bool loaded = false;
/// <summary>
/// Constructor
/// </summary>
public TextBoxAdv()
{
Loaded += new RoutedEventHandler( Control_Loaded );
SetResourceReference( StyleProperty, typeof( TextBox ) );
}
void Control_Loaded( object sender, RoutedEventArgs e )
{
if( !loaded )
{
loaded = true;
string text = Text;
Text = "Text";
UpdateLayout();
Text = text;
}
}
}
I propose a different solution that properly respects the MinLines property, rather than forcing you to use MinHeight.
First, start with a convenience method to allow you to Post an action to the window loop. (I'm including both one where you need to pass state and one where you don't.)
public static class Globals {
public static void Post(Action callback){
if(SynchronizationContext.Current is SynchronizationContext currentContext)
currentContext.Post( _ => callback(), null);
else{
callback();
}
}
public static void Post<TState>(TState state, Action<TState> callback){
if(SynchronizationContext.Current is SynchronizationContext currentContext)
currentContext.Post(_ => callback(state), null);
else{
callback(state);
}
}
}
Next, create an extension method for TextBox to 'initialize' the proper size based on MinLines. I put this in a Hacks class because to me, that's what this is and it clearly identifies the code as such.
public static void FixInitialMinLines(this TextBox textBox) {
Globals.Post(() => {
var textBinding = textBox.GetBindingExpression(TextBox.TextProperty)?.ParentBinding;
if (textBinding != null) {
BindingOperations.ClearBinding(textBox, TextBox.TextProperty);
textBox.UpdateLayout();
BindingOperations.SetBinding(textBox, TextBox.TextProperty, textBinding);
}
else {
var lastValue = textBox.Text;
textBox.Text = lastValue + "a";
textBox.UpdateLayout();
textBox.Text = lastValue;
}
});
}
The above code handles both bound and unbound TextBox controls, but rather than simply changing the value like other controls which may cascade that change down through the bindings, it first disconnects the binding, forces layout, then reconnects the binding, thus triggering the proper layout in the UI. This avoids unintentionally changing your bound sources should the binding be two-way.
Finally, simply call the extension method for every TextBox where MinLines is set. Thanks to the Post call in the extension method, You can call this immediately after InitializeComponent and it will still be executed after all other events have fired, including all layout and the Loaded event.
public partial class Main : Window {
public Main() {
InitializeComponent();
// Fix initial MinLines issue
SomeTextBoxWithMinLines.FixInitialMinLines();
}
...
}
Add the above code to your 'library' of functions and you can address the issue with a single line of code in all of your windows and controls. Enjoy!

How can I access the ListViewItems of a WPF ListView?

Within an event, I'd like to put the focus on a specific TextBox within the ListViewItem's template. The XAML looks like this:
<ListView x:Name="myList" ItemsSource="{Binding SomeList}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<!-- Focus this! -->
<TextBox x:Name="myBox"/>
I've tried the following in the code behind:
(myList.FindName("myBox") as TextBox).Focus();
but I seem to have misunderstood the FindName() docs, because it returns null.
Also the ListView.Items doesn't help, because that (of course) contains my bound business objects and no ListViewItems.
Neither does myList.ItemContainerGenerator.ContainerFromItem(item), which also returns null.
To understand why ContainerFromItem didn't work for me, here some background. The event handler where I needed this functionality looks like this:
var item = new SomeListItem();
SomeList.Add(item);
ListViewItem = SomeList.ItemContainerGenerator.ContainerFromItem(item); // returns null
After the Add() the ItemContainerGenerator doesn't immediately create the container, because the CollectionChanged event could be handled on a non-UI-thread. Instead it starts an asynchronous call and waits for the UI thread to callback and execute the actual ListViewItem control generation.
To be notified when this happens, the ItemContainerGenerator exposes a StatusChanged event which is fired after all Containers are generated.
Now I have to listen to this event and decide whether the control currently want's to set focus or not.
As others have noted, The myBox TextBox can not be found by calling FindName on the ListView. However, you can get the ListViewItem that is currently selected, and use the VisualTreeHelper class to get the TextBox from the ListViewItem. To do so looks something like this:
private void myList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myList.SelectedItem != null)
{
object o = myList.SelectedItem;
ListViewItem lvi = (ListViewItem)myList.ItemContainerGenerator.ContainerFromItem(o);
TextBox tb = FindByName("myBox", lvi) as TextBox;
if (tb != null)
tb.Dispatcher.BeginInvoke(new Func<bool>(tb.Focus));
}
}
private FrameworkElement FindByName(string name, FrameworkElement root)
{
Stack<FrameworkElement> tree = new Stack<FrameworkElement>();
tree.Push(root);
while (tree.Count > 0)
{
FrameworkElement current = tree.Pop();
if (current.Name == name)
return current;
int count = VisualTreeHelper.GetChildrenCount(current);
for (int i = 0; i < count; ++i)
{
DependencyObject child = VisualTreeHelper.GetChild(current, i);
if (child is FrameworkElement)
tree.Push((FrameworkElement)child);
}
}
return null;
}
I noticed that the question title does not directly relate to the content of the question, and neither does the accepted answer answer it. I have been able to "access the ListViewItems of a WPF ListView" by using this:
public static IEnumerable<ListViewItem> GetListViewItemsFromList(ListView lv)
{
return FindChildrenOfType<ListViewItem>(lv);
}
public static IEnumerable<T> FindChildrenOfType<T>(this DependencyObject ob)
where T : class
{
foreach (var child in GetChildren(ob))
{
T castedChild = child as T;
if (castedChild != null)
{
yield return castedChild;
}
else
{
foreach (var internalChild in FindChildrenOfType<T>(child))
{
yield return internalChild;
}
}
}
}
public static IEnumerable<DependencyObject> GetChildren(this DependencyObject ob)
{
int childCount = VisualTreeHelper.GetChildrenCount(ob);
for (int i = 0; i < childCount; i++)
{
yield return VisualTreeHelper.GetChild(ob, i);
}
}
I'm not sure how hectic the recursion gets, but it seemed to work fine in my case. And no, I have not used yield return in a recursive context before.
You can traverse up the ViewTree to find the item 'ListViewItem' record set that corresponds to the cell triggered from hit test.
Similarly, you can get the column headers from the parent view to compare and match the cell's column. You may want to bind the cell name to the column header name as your key for your comparator delegate/filter.
For example: HitResult is on TextBlock shown in green. You wish to obtain the handle to the 'ListViewItem'.
/// <summary>
/// ListView1_MouseMove
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListView1_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) {
if (ListView1.Items.Count <= 0)
return;
// Retrieve the coordinate of the mouse position.
var pt = e.GetPosition((UIElement) sender);
// Callback to return the result of the hit test.
HitTestResultCallback myHitTestResult = result => {
var obj = result.VisualHit;
// Add additional DependancyObject types to ignore triggered by the cell's parent object container contexts here.
//-----------
if (obj is Border)
return HitTestResultBehavior.Stop;
//-----------
var parent = VisualTreeHelper.GetParent(obj) as GridViewRowPresenter;
if (parent == null)
return HitTestResultBehavior.Stop;
var headers = parent.Columns.ToDictionary(column => column.Header.ToString());
// Traverse up the VisualTree and find the record set.
DependencyObject d = parent;
do {
d = VisualTreeHelper.GetParent(d);
} while (d != null && !(d is ListViewItem));
// Reached the end of element set as root's scope.
if (d == null)
return HitTestResultBehavior.Stop;
var item = d as ListViewItem;
var index = ListView1.ItemContainerGenerator.IndexFromContainer(item);
Debug.WriteLine(index);
lblCursorPosition.Text = $"Over {item.Name} at ({index})";
// Set the behavior to return visuals at all z-order levels.
return HitTestResultBehavior.Continue;
};
// Set up a callback to receive the hit test result enumeration.
VisualTreeHelper.HitTest((Visual)sender, null, myHitTestResult, new PointHitTestParameters(pt));
}
We use a similar technique with WPF's new datagrid:
Private Sub SelectAllText(ByVal cell As DataGridCell)
If cell IsNot Nothing Then
Dim txtBox As TextBox= GetVisualChild(Of TextBox)(cell)
If txtBox IsNot Nothing Then
txtBox.Focus()
txtBox.SelectAll()
End If
End If
End Sub
Public Shared Function GetVisualChild(Of T As {Visual, New})(ByVal parent As Visual) As T
Dim child As T = Nothing
Dim numVisuals As Integer = VisualTreeHelper.GetChildrenCount(parent)
For i As Integer = 0 To numVisuals - 1
Dim v As Visual = TryCast(VisualTreeHelper.GetChild(parent, i), Visual)
If v IsNot Nothing Then
child = TryCast(v, T)
If child Is Nothing Then
child = GetVisualChild(Of T)(v)
Else
Exit For
End If
End If
Next
Return child
End Function
The technique should be fairly applicable for you, just pass your listviewitem once it's generated.
Or it can be simply done by
private void yourtextboxinWPFGrid_LostFocus(object sender, RoutedEventArgs e)
{
//textbox can be catched like this.
var textBox = ((TextBox)sender);
EmailValidation(textBox.Text);
}

Resources