在我的视图模型中,我已将 DisplayAttributes 添加到属性中,现在希望将 TextBox 控件的 ToolTip 属性绑定到 DisplayAttribute 的 Description 属性。
我发现这个SO问题处理描述的阅读,但无法弄清楚如何使用计算的描述填充工具提示。
这似乎是一种迂回的方法,因为 WPF 不支持此属性,因此您将把属性输入到视图模型中,视图模型将查找它们。 它们可以是任何内部格式。
无论如何,这是您所说的问题的演示。 我们向文本框绑定的类添加一个
Descriptions
属性。 该属性是一个字典,它将属性名称映射到描述(即属性)。 在视图模型的静态构造函数中,我们查找所有属性并填充字典。
一个带有两个文本框的小 XAML 文件:
<Grid >
<StackPanel>
<TextBox Text="{Binding FirstName}" ToolTip="{Binding Descriptions[FirstName]}"/>
<TextBox Text="{Binding LastName}" ToolTip="{Binding Descriptions[LastName]}"/>
</StackPanel>
</Grid>
隐藏代码:
DataContext = new DisplayViewModel();
以及具有两个属性的基本视图模型:
public class DisplayViewModel
{
private static Dictionary<string, string> descriptions;
static DisplayViewModel()
{
descriptions = new Dictionary<string,string>();
foreach (var propertyName in PropertyNames)
{
var property = typeof(DisplayViewModel).GetProperty(propertyName);
var displayAttributes = property.GetCustomAttributes(typeof(DisplayAttribute), true);
var displayAttribute = displayAttributes.First() as DisplayAttribute;
var description = displayAttribute.Name;
descriptions.Add(propertyName, description);
}
}
public DisplayViewModel()
{
FirstName = "Bill";
LastName = "Smith";
}
public static IEnumerable<string> PropertyNames { get { return new[] { "FirstName", "LastName" }; } }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
public IDictionary<string, string> Descriptions { get { return descriptions; } }
}
参加聚会有点晚了,但我发现自己想做类似的事情,并发现我可以实现一个自定义的
MarkupExtension
,我将其直接传递到 ToolTip
绑定:
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
public class ToolTipBinding : MarkupExtension
{
private static readonly ConcurrentDictionary<BindingExpression, string?> _values = [];
public override object? ProvideValue(IServiceProvider serviceProvider)
{
if (serviceProvider.GetService<IProvideValueTarget>() is not IProvideValueTarget targetValueProvider)
{
return null;
}
if (targetValueProvider.TargetObject is not TextBox textBox)
{
return null;
}
if (textBox.GetBindingExpression(TextBox.TextProperty) is not BindingExpression bindingExpression)
{
return null;
}
return _values.GetOrAdd(bindingExpression, GetDescription);
}
private static string? GetDescription(BindingExpression bindingExpression)
{
var dataSourceType = bindingExpression.ResolvedSource.GetType();
var propertyInfo = dataSourceType.GetProperty(bindingExpression.ParentBinding.Path.Path);
if (propertyInfo?.GetCustomAttribute<DisplayAttribute>() is DisplayAttribute displayAttribute)
{
return displayAttribute.Description;
}
return null;
}
}
然后在我的 XAML 中(请注意,
ToolTipBinding
希望我为 Text
属性设置绑定):
<TextBox Text="{Binding ...}" ToolTip="{local:ToolTipBinding}" />
这很大程度上是第一个原型,有一些明显的限制:
ToolTipBinding
假设 TextBox.TextProperty
绑定相当基本 - 需要进一步修改才能处理更复杂的数据绑定GetDescription
实现某种错误处理(而且 ConcurrentDictionary
对此可能有点矫枉过正 - 我在这里使用它是为了简化示例而不是其他任何事情)