我正在尝试获取设置为 ListView 视图的 GridView 内的“单元格”的文本值。我不想获取 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;
}
我试过的:
对我来说合乎逻辑的方法是对鼠标事件做出反应。从具有鼠标事件的对象中,我将执行 A. 查看其子项以查找文本块,或 B. 获取其父项,然后查找具有文本块的子项。
我的假设是,如果我单击空白区域,我将单击包含我的文本块的容器。到目前为止,出现的两件事是边框和矩形(如果我不单击文本本身)。A. 除了recangle 和边框之外,什么都不返回。当我做 B 时,我可以找到文本块,但它们是整行中的每个文本块。
所以我试图从中做的是获取所有文本块,然后倒退直到我找到哪个具有 IsMouseOver 属性为真。事实证明,除了整行的内容呈现器之外,这些对象都没有 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(命名为 ="content")我找到了网格,然后是边框。边框的父级是内容呈现器,其内容是整行的数据视图模型。此 contentpresenter 的父级是网格列的 Presenter。这与我在另一个中导航到的相同。
看起来第一个方法对象虽然包含单元格,但实际上并不包含文本块或整个单元格模板项。在我看来,没有办法从单击的边框或矩形返回到实际的文本字段。
“长话短说”有没有办法建立这种联系?
(顺便说一句,我不愿意放弃这个 ListView/GridView,因为它的回报远远超过这个负面,我很乐意放弃这个想法以保留其余部分)。