如何绑定到自定义silverlight控件?

如何绑定到自定义silverlight控件?,silverlight,binding,controls,metadata,Silverlight,Binding,Controls,Metadata,我的控制有问题。我希望控件中的标签(lblLabel)显示绑定到Field属性的内容中的元数据。它当前将“字段”显示为标签。如何让它显示“Customer Name:”这是属性CustomerName视图模型上的名称 我的控件XAML 我的控制代码隐藏 使用System.Windows 使用System.Windows.Controls 使用System.Windows.Data 使用ApplicationShell.Resources 命名空间应用程序shell.Controls { 公共

我的控制有问题。我希望控件中的标签(lblLabel)显示绑定到Field属性的内容中的元数据。它当前将“字段”显示为标签。如何让它显示“Customer Name:”这是属性CustomerName视图模型上的名称

我的控件XAML


我的控制代码隐藏

使用System.Windows
使用System.Windows.Controls
使用System.Windows.Data
使用ApplicationShell.Resources
命名空间应用程序shell.Controls { 公共部分类RowItem:UserControl { #区域属性 公共对象字段 { 获取{return(string)GetValue(FieldProperty);} set{SetValue(FieldProperty,value);} } #区域依赖属性 public static readonly dependencProperty FieldProperty=dependencProperty.Register(“Field”、typeof(object)、typeof(RowItem)、newpropertyMetadata(null、Field_PropertyChangedCallback)); #端区 #端区 #地区活动 #区域依赖属性 私有静态无效字段\u PropertyChangedCallback(DependencyObject d、DependencyPropertyChangedEventArgs e) { 如果(e.OldValue!=e.NewValue) 返回; 变量控制=(行项)d; control.Field=(object)e.NewValue; } #端区 #端区 #区域构造函数 公共行项目() { 初始化组件(); } #端区 } }
查看模型

命名空间应用程序shell.Web.ViewModel
{
[可序列化]
公共类客户
{
[显示(AutoGenerateField=false,ShortName=“CustomerName\u Short”,Name=“CustomerName\u Long”,ResourceType=typeof(LocaleLibrary))]
公共重写字符串CustomerName{get;set;}
}
}
调用My控件的XAML

此页面datacontext设置为Customers(视图模型)类型的属性


有一种方法可以获取绑定到的属性的显示名称,但遗憾的是,这并不简单,我们必须对所使用的属性路径进行假设

我知道可以自动找到绑定的属性名,但当我查看其源代码时,我发现它是通过自己对绑定路径求值来实现的

这就是我在这里要采用的方法

我修改了
RowItem
用户控件的代码,这就是我想到的:

using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

public partial class RowItem : UserControl
{
    public RowItem()
    {
        InitializeComponent();
        Dispatcher.BeginInvoke(SetFieldLabel);
    }

    public string Field
    {
        get { return (string)GetValue(FieldProperty); }
        set { SetValue(FieldProperty, value); }
    }

    public static readonly DependencyProperty FieldProperty =
        DependencyProperty.Register("Field", typeof(string), typeof(RowItem),
                                    null);

    /// <summary>
    /// Return the display name of the property at the end of the given binding
    /// path from the given source object.
    /// </summary>
    /// <remarks>
    /// <para>
    /// The display name of the property is the name of the property according
    /// to a <see cref="DisplayAttribute"/> set on the property, if such an
    /// attribute is found, otherwise the name of the property.
    /// </para>
    /// <para>
    /// This method supports dot-separated binding paths only.  Binding
    /// expressions such <c>[0]</c> or <c>(...)</c> are not supported and will
    /// cause this method to return null.
    /// </para>
    /// <para>
    /// If no suitable property could be found (due to an intermediate value
    /// of the property-path evaluating to <c>null</c>, or no property with a
    /// given name being found), <c>null</c> is returned.  The final property
    /// in the path can have a <c>null</c> value, as that value is never used.
    /// </para>
    /// </remarks>
    /// <param name="binding">The binding expression.</param>
    /// <param name="source">
    /// The source object at which to start the evaluation.
    /// </param>
    /// <returns>
    /// The display name of the property at the end of the binding, or
    /// <c>null</c> if this could not be determined.
    /// </returns>
    private string GetBindingPropertyDisplayName(BindingExpression binding,
                                                 object source)
    {
        if (binding == null)
        {
            throw new ArgumentNullException("binding");
        }

        string bindingPath = binding.ParentBinding.Path.Path;
        object obj = source;
        PropertyInfo propInfo = null;
        foreach (string propertyName in bindingPath.Split('.'))
        {
            if (obj == null)
            {
                // Null object not at the end of the path.
                return null;
            }

            Type type = obj.GetType();
            propInfo = type.GetProperty(propertyName);
            if (propInfo == null)
            {
                // No property with the given name.
                return null;
            }

            obj = propInfo.GetValue(obj, null);
        }

        DisplayAttribute displayAttr = 
            propInfo.GetCustomAttributes(typeof(DisplayAttribute), false)
            .OfType<DisplayAttribute>()
            .FirstOrDefault();

        if (displayAttr != null)
        {
            return displayAttr.GetName();
        }
        else
        {
            return propInfo.Name;
        }
    }

    private void SetFieldLabel()
    {
        BindingExpression binding = this.GetBindingExpression(FieldProperty);
        string displayName = GetBindingPropertyDisplayName(binding,
                                                           DataContext);
        if (lblLabel != null)
        {
            lblLabel.Content = displayName;
        }
    }
}
(资源集合
Strings.resx
包含一个键,名为
ExampleFieldNameKey
,值为
此值位于资源集合中。resx
。此集合的访问修饰符也设置为Public。)我使用以下XAML测试了对控件的修改,将
DataContext
设置为上述视图模型类的实例:

<StackPanel>
    <local:RowItem Field="{Binding Path=WithDisplay, Mode=TwoWay}" />
    <local:RowItem Field="{Binding Path=WithoutDisplay, Mode=TwoWay}" />
    <local:RowItem Field="{Binding Path=Localised, Mode=TwoWay}" />
    <local:RowItem Field="{Binding Path=This.This.TheVerySame.This.WithDisplay, Mode=TwoWay}" />
</StackPanel>

你好。谢谢你的回复。我不能让它工作。我的“propInfo”变量始终为空,因此我永远无法返回显示名称。我试着设置datacontext,但仍然不起作用。您还可以发送控件的更新XAML吗。谢谢。我没有更改您的RowItem控件的XAML。如果调用
GetProperty()
propInfo
null
,则表示
obj
没有名为
propertyName
的属性。
obj
是否作为开始计算绑定属性路径的对象传入?对于循环中的每个步骤,
obj
上是否存在名为
propertyName
的属性?在这里,调用source时为null,因此obj为null。然后,我尝试设置控件(RowItem)的datacontext,但它仍然为null。我不知道为什么。我一直认为,如果不在控件上指定datacontext,那么它将使用父datacontext。所以底线是它没有设置控件的datacontext。如何修复此问题?如果
source
为null,则
RowItem
DataContext
为null。根据XAML,您的
行项目
位于
子窗口
ChildWindow
s不继承
DataContext
,因为它们没有继承它的父级。您是否正在设置
ChildWindow
DataContext
?确定。问题是,当datacontext为null时,它只运行GetBindingPropertyDisplayName函数。因此,我将其更改为仅在DataContext更改时运行该函数。这是一个很好的例子()。谢谢你的帮助。
<StackPanel>
    <local:RowItem Field="{Binding Path=WithDisplay, Mode=TwoWay}" />
    <local:RowItem Field="{Binding Path=WithoutDisplay, Mode=TwoWay}" />
    <local:RowItem Field="{Binding Path=Localised, Mode=TwoWay}" />
    <local:RowItem Field="{Binding Path=This.This.TheVerySame.This.WithDisplay, Mode=TwoWay}" />
</StackPanel>
This value is in a Display attribute WithoutDisplay This value is in a Resources.resx This value is in a Display attribute