WPF 并将 ToolTip 绑定到 DisplayAttribute

问题描述 投票:0回答:2

在我的视图模型中,我已将 DisplayAttributes 添加到属性中,现在希望将 TextBox 控件的 ToolTip 属性绑定到 DisplayAttribute 的 Description 属性。

我发现这个SO问题处理描述的阅读,但无法弄清楚如何使用计算的描述填充工具提示。

wpf binding
2个回答
1
投票

这似乎是一种迂回的方法,因为 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; } }
}

0
投票

参加聚会有点晚了,但我发现自己想做类似的事情,并发现我可以实现一个自定义的

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
    对此可能有点矫枉过正 - 我在这里使用它是为了简化示例而不是其他任何事情)
© www.soinside.com 2019 - 2024. All rights reserved.