如何绑定到自定义silverlight控件?
我的控制有问题。我希望控件中的标签(lblLabel)显示绑定到Field属性的内容中的元数据。它当前将“字段”显示为标签。如何让它显示“Customer Name:”这是属性CustomerName视图模型上的名称 我的控件XAML如何绑定到自定义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 { 公共
我的控制代码隐藏
使用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