How to get the contents of a ListView cell (GridView) when clicked

I am trying to get the text value of a "cell" inside a GridView that is set as a ListView. I don’t want to get the SelectedItem ListView, as this only returns my View Model (but not which property the cell refers to).

I can get a text value by responding to direct mouse events (up or down), and if that value is a text block, I can use text. This works great, and now this is my only solution, although it is currently limited.

I would like to do this even further and be able to click anywhere in the cell area, navigate it to find the corresponding text block, and then use this value. I tried half a million ways to do this, but what seems logical doesn't seem to work at all, as it should.

Setup:

I have a dynamic GridView that creates its own columns and bindings based on the data models that I pass to it. I use the program cell template (shown below) to have individual control over the cells, in particular, so I can add a β€œborder” to it, thanks to which it actually separates each cell. I named the objects, so I can access them more easily when I move around VisualTree.

Here is the template code. (Note that the text block itself was originally the content presenter, but this was changed for later flexibility).

private DataTemplate GetCellTemplate(string bindingName) { StringBuilder builder = new StringBuilder(); builder.Append("<DataTemplate "); builder.Append("xmlns='http://schemas.microsoft.com/winfx/"); builder.Append("2006/xaml/presentation' "); builder.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' "); builder.Append("xmlns:local = 'clr-namespace:XXXXXXXX"); builder.Append(";assembly=XXXXXXXXX'>"); builder.Append("<Border Name=\"border\" BorderThickness=\"1,0,0,0\" BorderBrush=\"Gray\" Margin=\"-6,-3,-6,-3\">"); builder.Append("<Grid Margin=\"6,3,6,3\">"); builder.Append("<ContentPresenter Name=\"content\" HorizontalAlignment=\"Stretch\" Content=\"{Binding "); builder.Append(string.Format("{0}", bindingName)); builder.Append("}\"/>"); builder.Append("</Grid>"); builder.Append("</Border>"); builder.Append("</DataTemplate>"); DataTemplate cellTemplate= (DataTemplate)XamlReader.Parse(builder.ToString()); return cellTemplate; } 

What I tried:

The logical approach for me was to respond to the Mouse event. From the object in which the mouse event was, I would make A. Look at your children to find the text block, or B. Get your parent, then find the child with the text block.

My guess is that if I clicked in white space, I click in the container with my text block. So far, the two things that arise are Border and Rectangle (unless I click on the text itself). A. Returns absolutely nothing but drag and drop. When I do B, I can find text blocks, but they represent each text block in the entire line.

So, what I'm trying to do is get all the text blocks and then go back until I find that the IsMouseOver property is true. It turns out that none of these objects NEVER has IsMouseOver, except for the leading content for the entire line. Therefore, it seems to me that the spaces in the cells do not actually contain a text block.

What I find is that when I click on Border and start looking at the children, I end up with a container that has a rectangle (the rectangle that I click) and a presenter representing the grid line. The host shows all the objects inside the line (therefore, why I get all the text blocks when doing this recursive scan).

Here is the code used to do this to understand what I'm doing. I wrote about 10 different versions of the same recursive code, which are usually trying to find who has a mouse and is associated with a text field.

 private void OnPreviewMouseUp(object sender, MouseButtonEventArgs e) { object original = e.OriginalSource; if (original is TextBlock) { this.valueTextBlock.Text = ((TextBlock)original).Text; } else if (original is FrameworkElement) { var result = GetAllNestedChildren<Border>(VisualTreeHelper.GetParent((DependencyObject)original)).Where(x => x.Name == "border").Where(x => HasAChildWithMouse(x)).ToList(); } else { this.valueTextBlock.Text = string.Empty; } } private bool HasAChildWithMouse(UIElement element) { if (element.IsMouseOver || element.IsMouseDirectlyOver) return true; var childCount = VisualTreeHelper.GetChildrenCount(element); for (int i = 0; i < childCount; ++i) { var child = VisualTreeHelper.GetChild(element, i); if (child is UIElement) if (HasAChildWithMouse((UIElement)child)) return true; } return false; } private IEnumerable<T> GetAllNestedChildren<T>(DependencyObject obj) where T : UIElement { if (obj is T) yield return obj as T; var childCount = VisualTreeHelper.GetChildrenCount(obj); for (int i = 0; i < childCount; ++i) { var child = VisualTreeHelper.GetChild(obj, i); foreach (var nested in GetAllNestedChildren<T>(child)) yield return nested; } } private T GetObjectByTypeParentHasMouse<T>(DependencyObject obj) where T : UIElement { if (obj is T) { if ((VisualTreeHelper.GetParent(obj) as UIElement).IsMouseOver ) { return obj as T; } } var childCount = VisualTreeHelper.GetChildrenCount(obj); for (int i = 0; i < childCount; ++i) { var child = VisualTreeHelper.GetChild(obj, i); var correctType = GetObjectByTypeParentHasMouse<T>(child); if (correctType != null) return correctType; } return null; } private T GetContainedType<T>(DependencyObject obj, bool checkForMouseOver) where T : UIElement { if (obj is T && ((T)obj).IsMouseOver) return obj as T; var childCount = VisualTreeHelper.GetChildrenCount(obj); for (int i = 0; i < childCount; ++i) { var child = VisualTreeHelper.GetChild(obj, i); var correctType = GetContainedType<T>(child, checkForMouseOver); if (correctType != null) return correctType; } return null; } 

Another approach I took was to start with the TextBlock itself, find its parent containing the element and figure out how I can get to the answer. I believe templateparent is ContentPresenter (named = "content"). I find the grid and then the border. A border parent is a content presenter that is a model for representing data for the entire row. The parent of this contentpresenter is the leading column of the table. This is the same as what I looked at in another.

It seems that the objects of the first approach, while they contain a cell, actually do not contain a text block or whole template elements. It seems to me that there is no way to go from the border or rectangle that is clicked back into the actual text box.

"In short, is there any way to make this connection?

(Btw I do not want to abandon this ListView / GridView, because its winnings far outweigh this negative, and I would gladly abandon this idea to save the rest).

+4
source share
1 answer

I think you will succeed either

1) Add a button (switch) to the root of your data template and attach it to the Team and process it on your viewing model or bind to IsChecked / IsPressed and process the changes using data triggers or w / e in a side view.

2) Add an EventTrigger to your data file at some point and handle the PreviewNouseUp / Down events there using simple animations.

0
source

All Articles