Run*_*sen 50 c# data-binding wpf
说我有这样的界面:
public interface ISomeInterface
{
...
}
Run Code Online (Sandbox Code Playgroud)
我还有几个实现这个接口的类;
public class SomeClass : ISomeInterface
{
...
}
Run Code Online (Sandbox Code Playgroud)
现在我有一个WPF ListBox列出了ISomeInterface的项目,使用自定义DataTemplate.
数据绑定引擎显然不会(我已经弄明白)允许我绑定到接口属性 - 它看到该对象是一个SomeClass对象,并且数据只显示SomeClass应该碰巧有绑定属性可用非接口属性.
我怎么能告诉DataTemplate好像每个对象都是一个ISomeInterface,而不是SomeClass等?
谢谢!
小智 62
为了绑定到显式实现的接口成员,您需要做的就是使用括号.例如:
隐:
{Binding Path=MyValue}
Run Code Online (Sandbox Code Playgroud)
明确:
{Binding Path=(mynamespacealias:IMyInterface.MyValue)}
Run Code Online (Sandbox Code Playgroud)
Moh*_*han 19
Beatriz Costa-MSFT的微软论坛的答案值得一读(相当古老):
数据绑定团队讨论了不久前添加对接口的支持,但最终没有实现它,因为我们无法为它提供一个好的设计.问题是接口没有像对象类型那样的层次结构.考虑您的数据源同时实现方案
IMyInterface1
,并IMyInterface2
与您在资源这两个接口的DataTemplates:它的DataTemplate你认为我们应该拿起?在对对象类型进行隐式数据模板化时,我们首先尝试查找
DataTemplate
确切类型,然后查找其父类,祖父类等.我们可以应用非常明确的类型顺序.当我们谈到添加对接口的支持时,我们考虑使用反射来找出所有接口并将它们添加到类型列表的末尾.我们遇到的问题是当类型实现多个接口时定义接口的顺序.我们必须记住的另一件事是反射并不便宜,这会减少我们对这种情况的影响.
那么解决方案是什么?您无法在XAML中完成所有操作,但您可以使用一些代码轻松完成.该
ItemTemplateSelector
属性ItemsControl
可用于选择DataTemplate
要用于每个项目的项目.在SelectTemplate
模板选择器的方法中,您将接收要模板化的项目作为参数.在这里,您可以检查它实现的接口,并返回DataTemplate
与之匹配的接口.
use*_*116 13
简短的回答是DataTemplate不支持接口(考虑多重继承,显式v.隐式等).我们倾向于解决这个问题的方法是扩展基类以允许DataTemplate专门化/泛化.这意味着一个体面但不一定是最佳的解决方案是:
public abstract class SomeClassBase
{
}
public class SomeClass : SomeClassBase
{
}
<DataTemplate DataType="{x:Type local:SomeClassBase}">
<!-- ... -->
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)
你有另一种选择.在DataTemplate上设置一个Key并在ItemTemplate中引用该键.像这样:
<DataTemplate DataType="{x:Type documents:ISpecificOutcome}"
x:Key="SpecificOutcomesTemplate">
<Label Content="{Binding Name}"
ToolTip="{Binding Description}" />
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)
然后按键使用它来引用模板,如下所示:
<ListBox ItemsSource="{Binding Path=SpecificOutcomes}"
ItemTemplate="{StaticResource SpecificOutcomesTemplate}"
>
</ListBox>
Run Code Online (Sandbox Code Playgroud)
dummyboy建议的答案是最好的答案(它应该被投票到顶级imo).它确实存在设计者不喜欢它的问题(给出错误"Object null不能用作PropertyPath的访问器参数)但是有一个很好的解决方法.解决方法是在datatemplate中定义项目然后将模板设置为标签或其他内容控件.例如,我试图添加这样的图像
<Image Width="120" Height="120" HorizontalAlignment="Center" Source="{Binding Path=(starbug:IPhotoItem.PhotoSmall)}" Name="mainImage"></Image>
Run Code Online (Sandbox Code Playgroud)
但它一直给我同样的错误.解决方案是创建标签并使用数据模板来显示我的内容
<Label Content="{Binding}" HorizontalAlignment="Center" MouseDoubleClick="Label_MouseDoubleClick">
<Label.ContentTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Path=(starbug:IPhotoItem.PhotoSmall)}" Width="120" Height="120" Stretch="Uniform" ></Image>
</StackPanel>
</DataTemplate>
</Label.ContentTemplate>
</Label>
Run Code Online (Sandbox Code Playgroud)
这有其缺点,但它似乎对我很好.
注意:如果接口属性位于路径内,您也可以使用更复杂的多部分路径:
<TextBlock>
<TextBlock.Text>
<Binding Path="Packages[0].(myNamespace:IShippingPackage.ShippingMethod).CarrierServiceCode"/>
</TextBlock.Text>
</TextBlock>
Run Code Online (Sandbox Code Playgroud)
或者直接使用Binding
指令。
<TextBlock Text="{Binding Path=Packages[0].(myNamespace:IShippingPackage.ShippingMethod).CarrierServiceCode}"/>
Run Code Online (Sandbox Code Playgroud)
或者,当使用接口的多个属性时,您可以在本地重新定义 DataContext 以使代码更具可读性。
<StackPanel DataContext={Binding Path=Packages[0].(myNamespace:IShippingPackage.ShippingMethod)}">
<TextBlock Text="{Binding CarrierName}"/>
<TextBlock Text="{Binding CarrierServiceCode}"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
)}
提示:请注意路径表达式末尾是否意外出现。我不断犯愚蠢的复制/粘贴错误。
Path="(myNameSpace:IShippingPackage.ShippingMethod)}"
Path=
发现如果我不明确使用Path=
那么它可能无法解析绑定。通常我会写这样的东西:
Text="{Binding FirstName}"
Run Code Online (Sandbox Code Playgroud)
代替
Text="{Binding Path=FirstName}"
Run Code Online (Sandbox Code Playgroud)
但随着更复杂的接口绑定,我发现Path=
需要避免此异常:
System.ArgumentNullException: Key cannot be null.
Parameter name: key
at System.Collections.Specialized.ListDictionary.get_Item(Object key)
at System.Collections.Specialized.HybridDictionary.get_Item(Object key)
at System.ComponentModel.PropertyChangedEventManager.RemoveListener(INotifyPropertyChanged source, String propertyName, IWeakEventListener listener, EventHandler`1 handler)
at System.ComponentModel.PropertyChangedEventManager.RemoveHandler(INotifyPropertyChanged source, EventHandler`1 handler, String propertyName)
at MS.Internal.Data.PropertyPathWorker.ReplaceItem(Int32 k, Object newO, Object parent)
at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)
Run Code Online (Sandbox Code Playgroud)
即不要这样做:
<TextBlock Text="{Binding Packages[0].(myNamespace:IShippingPackage.ShippingMethod).CarrierServiceCode}"/>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
21376 次 |
最近记录: |