简体   繁体   English

如何使用鼠标单击获取ListView(GridView)单元格的内容

[英]How does one get a ListView (GridView) cell's contents when clicked with a mouse

I am trying to get the text value of a "cell" inside of a GridView that is set as the view of a ListView. 我试图获取GridView中的“单元格”的文本值,该GridView被设置为ListView的视图。 I do not want to get the SelectedItem of the ListView as that just returns my entire View Model (but not which property the cell refers to). 我不想获取ListView的SelectedItem,因为它只返回我的整个视图模型(但不是单元格引用的属性)。

I am able to get the text value by responding to direct mouse events (up down or whatever) and if the value is a textblock, obviously I can use the text. 我可以通过响应直接鼠标事件(向上或其他)来获取文本值,如果值是文本块,显然我可以使用文本。 This works great and as of right now this is my only solution, although its currently limited. 这很有效,截至目前,这是我唯一的解决方案,尽管目前有限。

I would like to take it a step further and be able to click anywhere with in the cell area, navigate around to find the appropriate textblock and then use that value. 我想更进一步,能够单击单元格区域中的任意位置,导航以查找相应的文本块,然后使用该值。 I have tried a half million ways to do this but what seems logical doesn't seem to quite work out like it should. 我已经尝试了五十万种方法来做到这一点,但看似合乎逻辑的东西似乎并没有像它应该的那样完美。

Setup: 设定:

I have a dynamic GridView that creates its own columns and bindings based on data models that I pass to it. 我有一个动态GridView,它根据我传递给它的数据模型创建自己的列和绑定。 I am using a programmatic cell template (shown below) to have individual control over the cells, particularly so I can add a "border" to it making it actually separate out each cell. 我正在使用程序化细胞模板(如下所示)对细胞进行单独控制,特别是因此我可以为其添加“边界”,使其实际上分离出每个细胞。 I have named the objects so I can access them easier when I'm navigating around the VisualTree. 我已经命名了这些对象,因此当我在VisualTree中导航时,我可以更轻松地访问它们。

Here is the Template Code. 这是模板代码。 (Note that the content presenter originally was a textblock itself, 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 have Tried: 我试过的:

The logical approach for me was to react to a Mouse event. 对我来说,合乎逻辑的方法是对鼠标事件作出反应。 From the object that had the mouse event I would do either A. Look at its children to find a textblock, or B. Get its parent then look for child with a textblock. 从具有鼠标事件的对象开始,我会做A.要查看其子项以查找文本块,或者B.获取其父项然后查找带有文本块的子项。

My assumption is that if I click in white space I'm clicking in a container that has my textblock. 我的假设是,如果我点击白色空间,我点击一个包含我的文本块的容器。 So far the two things that come up are a Border and a Rectangle (if I don't click the text itself). 到目前为止,出现的两件事是边框和矩形(如果我不单击文本本身)。 A. Returns absolutely nothing except for the recangle and the border. A.除了重复和边框外,绝对没有任何回报。 When I do B i can find textblocks but they are every single text block in the entire row. 当我做B时,我可以找到文本块,但它们是整行中的每个文本块。

So what I try to do from that is get all textblocks, then go backwards till I find which one has a IsMouseOver property as true. 所以我尝试做的就是获取所有文本块,然后返回,直到找到哪个具有IsMouseOver属性为true。 It turns out none of these objects EVER have a IsMouseOver except the content presenter for the entire row. 事实证明,除了整行的内容演示者之外,这些对象中没有一个具有IsMouseOver。 So this seems to indicate to me is that the whitespace in the cells does not actually contain the textblock. 所以这似乎向我表明,单元格中的空格实际上并不包含文本块。

What I find is that when I click on the Border and start looking at children, I eventually get to a container that has a rectangle (the rectangle I click) and a grid row view presenter. 我发现当我点击边框并开始查看孩子时,我最终会找到一个容器,它有一个矩形(我点击的矩形)和一个网格行视图展示器。 The presenter shows all of the objects inside the row (hence why i would get all textblocks when i do this recursive scan). 演示者显示行内的所有对象(因此,当我执行此递归扫描时,为什么我会获得所有文本块)。

Here is some of the code used to do this to get an idea of what i'm doing. 以下是一些代码,用于了解我正在做的事情。 I have written about 10 different versions of this same recursive code generally attempting to find who has the Mouse over it and is related to a textbox. 我已经写了大约10个不同版本的这个相同的递归代码,通常试图找到谁有鼠标在它上面并与文本框相关。

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;
    }

The other approach I took was to start with the TextBlock itself, find its containing parent and find out how i can navigate to the answer. 我采取的另一种方法是从TextBlock本身开始,找到它的包含父项,并找出我如何导航到答案。 I find the templateparent is the ContentPresenter (named ="content") I find the grid, and then the border. 我发现templateparent是ContentPresenter(named =“content”)我找到了网格,然后是边框。 The parent of the border is a content presenter whos content is the data view model for the entire row. 边框的父级是内容演示者,其内容是整行的数据视图模型。 The parent of this contentpresenter is the grid column's presenter. 此contentpresenter的父级是网格列的演示者。 This is the same one that i was navigating up to in the other one. 这与我在另一个中导航的那个相同。

It would appear that the first approach objects while are contain the cell do not actually contain the textblock or the entire cell templated items. 看来第一个方法对象虽然包含单元格,但实际上并不包含文本块或整个单元模板化项目。 It would appear to me there is no way to go from the Border or Rectangle that is clicked, back to the actual text field. 在我看来,没有办法从点击的边框或矩形返回到实际的文本字段。

"Long story short" is there ANY way to make this connection? “长话短说”有没有办法建立这种联系?

(Btw I am not willing to give up this ListView/GridView because its payoffs far outweigh this negative and I'd gladly give up on this idea to keep the rest). (顺便说一下,我不愿意放弃这个ListView / GridView,因为它的收益远大于这个负面因素,我很乐意放弃这个想法来保留其余的)。

I think you sjould be able to either 我想你也应该能够

1) Add some kind of (toggle)button to the root of your data template, and either bind to Command and handle it on your viewmodel or bind to IsChecked/IsPressed and handle changes via data triggers or w/e on the view side. 1)将某种(切换)按钮添加到数据模板的根目录,然后绑定到Command并在viewmodel上处理它或绑定到IsChecked / IsPressed并通过数据触发器处理更改或在视图侧处理w / e。

2) Add EventTrigger to your datatemplate at some point, and handle PreviewNouseUp/Down events there via simple animations. 2)在某个时刻将EventTrigger添加到datatemplate,并通过简单的动画处理PreviewNouseUp / Down事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM