首页 文章

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

提问于
浏览
4

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

我可以通过响应直接鼠标事件(向上或其他)来获取文本值,如果值是文本块,显然我可以使用文本 . 这很有效,截至目前,这是我唯一的解决方案,尽管目前有限 .

我想更进一步,能够单击单元格区域中的任意位置,导航以查找相应的文本块,然后使用该值 . 我已经尝试了五十万种方法来做到这一点,但看似合乎逻辑的东西似乎并没有像它应该的那样完美 .

设置:

我有一个动态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; 
    }

我试过的:

对我来说,合乎逻辑的方法是对鼠标事件作出反应 . 从具有鼠标事件的对象开始,我会做A.要查看其子项以查找文本块,或者B.获取其父项然后查找带有文本块的子项 .

我的假设是,如果我点击白色空间,我点击一个包含我的文本块的容器 . 到目前为止,出现的两件事是边框和矩形(如果我不单击文本本身) . A.除了重复和边框外,绝对没有任何回报 . 当我做B时,我可以找到文本块,但它们是整行中的每个文本块 .

所以我尝试做的就是获取所有文本块,然后返回,直到找到哪个具有IsMouseOver属性为true . 事实证明,除了整行的内容演示者之外,这些对象中没有一个具有IsMouseOver . 所以这似乎向我表明,单元格中的空格实际上并不包含文本块 .

我发现当我点击边框并开始查看孩子时,我最终会找到一个容器,它有一个矩形(我点击的矩形)和一个网格行视图展示器 . 演示者显示行内的所有对象(因此,当我执行此递归扫描时,为什么我会获得所有文本块) .

以下是一些代码,用于了解我正在做的事情 . 我已经写了大约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本身开始,找到它的包含父项,并找出我如何导航到答案 . 我发现templateparent是ContentPresenter(named =“content”)我找到了网格,然后是边框 . 边框的父级是内容演示者,其内容是整行的数据视图模型 . 此contentpresenter的父级是网格列的演示者 . 这与我在另一个中导航的那个相同 .

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

“长话短说”有没有办法 Build 这种联系?

(顺便说一下,我不愿意放弃这个ListView / GridView,因为它的收益远大于这个负面因素,我很乐意放弃这个想法来保留其余部分) .

1 回答

  • 0

    我想你也应该能够

    1)将某种(切换)按钮添加到数据模板的根目录,然后绑定到Command并在viewmodel上处理它或绑定到IsChecked / IsPressed并通过数据触发器处理更改或在视图侧处理w / e .

    2)在某个时刻将EventTrigger添加到datatemplate,并通过简单的动画处理PreviewNouseUp / Down事件 .

相关问题