当用鼠标单击时,如何获得ListView (GridView)单元格的内容?

本文关键字:单元格 GridView ListView 单击 鼠标 何获得 | 更新日期: 2023-09-27 17:49:25

我试图获得GridView内部的"单元格"的文本值,该值被设置为ListView的视图。我不想获得ListView的SelectedItem,因为它只是返回我的整个视图模型(但不是单元格引用的属性)。

我能够通过响应直接鼠标事件(上下或其他)获得文本值,如果值是一个文本块,显然我可以使用文本。这工作得很好,到目前为止,这是我唯一的解决方案,尽管它目前有限。

我想更进一步,能够在单元格区域的任何地方单击,导航以找到适当的文本块,然后使用该值。我已经尝试了50万种方法来做到这一点,但似乎合乎逻辑的方法似乎并不像它应该的那样有效。

设置:

我有一个动态GridView,它根据我传递给它的数据模型创建自己的列和绑定。我使用编程式单元格模板(如下所示)对单元格进行单独控制,特别是这样我可以添加一个"边界",使其实际上分离出每个单元格。我已经命名了这些对象,这样当我在VisualTree中导航时就可以更容易地访问它们。

下面是模板代码。(请注意,内容呈现者最初是一个文本块本身,但为了以后的灵活性,这被改变了)
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 try:

对我来说合乎逻辑的方法是对鼠标事件作出反应。对于具有鼠标事件的对象,我将执行任何一种操作a .查看它的子元素来找到一个文本块,或者B.获取父节点,然后用textblock寻找子节点。

我的假设是,如果我点击空白,我点击在一个容器有我的文本块。到目前为止,出现的两个东西是边框和矩形(如果我不点击文本本身)。除了矩形和边框之外,什么都不返回。当我做B时,我可以找到文本块,但它们是整行中的每一个文本块。

我要做的是获取所有的textblock,然后返回直到我找到哪个有一个IsMouseOver属性为真。事实证明,除了整行的内容呈现器之外,这些对象都没有IsMouseOver。因此,这似乎表明,在单元格中的空白实际上不包含文本块。

我发现,当我单击Border并开始查看子元素时,我最终会看到一个具有矩形(我单击的矩形)和网格行视图呈现器的容器。演示者显示了行内的所有对象(因此,当我执行此递归扫描时,我将获得所有文本块)。

下面是一些用来做这件事的代码,以便了解我在做什么。我已经编写了大约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;
    }

我采取的另一种方法是从TextBlock本身开始,找到它的包含父元素,并找出如何导航到答案。我发现templatparent是ContentPresenter (named ="content"),我找到了网格,然后是边框。边框的父元素是一个内容呈现者,其内容是整行的数据视图模型。这个contentpresenter的父类是网格列的presenter。这和我之前导航到的那个是一样的

似乎第一个方法对象虽然包含单元格,但实际上并不包含文本块或整个单元格模板项。在我看来,没有办法从被点击的边框或矩形返回到实际的文本字段。

"长话短说"是否有任何方法使这种联系?

(顺便说一句,我不愿意放弃这个ListView/GridView,因为它的好处远远大于它的坏处,我很乐意放弃这个想法来保留其余的)

当用鼠标单击时,如何获得ListView (GridView)单元格的内容?

我想你应该可以

1)添加某种(切换)按钮到你的数据模板的根,或者绑定到Command和处理它在你的视图模型或绑定到IsChecked/IsPressed和处理变化通过数据触发器或w/e在视图端。

2)在你的数据模板中添加EventTrigger,并通过简单的动画处理PreviewNouseUp/Down事件。