Silverlight数据绑定,避免缺少属性的BindingExpression路径错误,而是隐藏控件

Silverlight数据绑定,避免缺少属性的BindingExpression路径错误,而是隐藏控件,silverlight,data-binding,silverlight-4.0,Silverlight,Data Binding,Silverlight 4.0,想象一下以下简单的模型(为了简单起见,举个例子;事实上,我们这里有MVVM,但这并不重要): 现在我们有了一个SilverlightUserControl,它包含以下控件(同样,这只是一个示例,从核心到核心): 如果设置为StackOverflowUser,则一切正常。如果设置为User,我将得到一个“BindingExpression路径错误”,因为User模型中缺少属性Reputation。我完全理解 有没有办法避免这种情况 异常和2)控制 控件的可见性,折叠 绑定属性不可用时 当然,我们更

想象一下以下简单的模型(为了简单起见,举个例子;事实上,我们这里有MVVM,但这并不重要):

现在我们有了一个Silverlight
UserControl
,它包含以下
控件(同样,这只是一个示例,从核心到核心):

如果设置为
StackOverflowUser
,则一切正常。如果设置为
User
,我将得到一个“BindingExpression路径错误”,因为
User
模型中缺少属性
Reputation
。我完全理解

有没有办法避免这种情况 异常
和2)控制 控件的可见性,折叠 绑定属性不可用时

当然,我们更喜欢优雅的解决方案,通过调整绑定表达式和/或使用转换器等解决问题,并尽可能避免大量代码落后

提前感谢您的帮助和建议,
致以最良好的祝愿


Thomas

不幸的是,Silverlight在数据模板方面的多态性行为有限,我只能想到一个解决方法:

也为用户类提供属性声誉,但使其毫无意义,例如-1。然后将样式应用于信誉文本块:

  <Page.Resources>
    <Style Key="Reputation">
      <Style.Triggers>
        <DataTrigger Binding="{Binding Path=Reputation} Value="-1">
          <Setter Property="Visibility" Value="Invisible" />
        </DataTrigger>    
      </Style.Triggers>
    </Style>
  </Page.Resources>

...

  <TextBlock Text="Reputation:" Style="{StaticResource Reputation}">
  <TextBlock Text="{Binding Path=Reputation}" Style="{StaticResource Reputation}">


但是你看,没有优雅的方法,很遗憾,DataTemplate在Silverlight中没有DataType属性。

你提到你正在使用MVVM。这是准备视图时viewmodel到形状模型数据的值。viewmodel可以具有用户名和信誉的可访问属性(甚至可能还有另一个绑定可见性的bool)。viewmodel将包含关于如何从任一模型(User或StackOverflowUser)填充这些属性的所有逻辑。视图不知道用户或StackOverflowUser对象,只知道viewmodel。

我终于解决了问题。一位同事最终实现了一个解决方案,包括WPFs DataTemplates数据类型属性(或者通常是DataTemplateSelector)的解决方案。它不是很漂亮(我想,没有解决办法),但它是有效的。不幸的是,我不能发布任何代码片段,因为它的源代码是封闭的。但后来我发现了一些链接,提供了一个非常类似的解决方案,比如这个:。如果你有类似的问题,这也会帮助你。或者是关于这个问题的更多想法

实际的解决办法是遵循奥桑的暗示。不幸的是,他的解决方案不起作用,所以我不想将他的评论标记为可接受的答案,但我至少投了赞成票

谢谢

致以最良好的祝愿


托马斯

我知道这已经得到了回答,但我仍然认为这篇文章是值得的。使用反射,您可以在ViewModel中拥有一个属性,该属性可以轻松地处理只有在某些情况下才具有该属性的对象的数据。不过,反思的代价可能会很高,所以在你的决定中权衡一下

public int? Reputation
    {
        get
        {
            var prop = Dto.GetType().GetProperty("Reputation");
            return (prop != null)? (int)prop.GetValue(Dto, null) : null;
        }
        set
        {
            var prop = Dto.GetType().GetProperty("Reputation");
            if(prop !=null) prop.SetValue(Dto,value, null);
        }
    }

谢谢你的建议!将属性从继承添加(移动)到基类会破坏整个业务对象模型。。。还尝试使第二个示例正常工作,并在“Microsoft.Expression.Interactions”库(来自Blend)中找到“DataTriggers”,但无法使“Style.Triggers”正常工作,不过…啊,我再次使用了Silverlight中不可用的WPF功能。。我很抱歉。我想你需要做一些代码隐藏,虽然它是丑陋的。您是否尝试设置绑定的FallbackValue属性?也许它不会在类用户上引发异常。当设置FallbackValue时,它将用于显示fallback值,但仍然会产生此绑定错误。如果您想要控制可见性,事情会变得更加困难:例如,您可以将回退值设置为“Collapsed”,但如果属性值为null,也会发生这种情况。但事实上,一个“null”属性和一个不存在的属性之间有一点区别,用这种方法很难找到它。。。顺便说一句,我感谢你的建议和努力,奥桑竖起大拇指,这是我今天早上开始评估的内容。。。对于ViewModel,它仍然意味着一些丑陋的代码,因为您必须检查所有支持的类型(如果我找到一个优雅的解决方案,我将发布它),但至少您可以将问题从XAML转移到代码中,从而获得对它的更多控制。
this.DataContext = new User { Username = "john.doe" };
  <Page.Resources>
    <Style Key="Reputation">
      <Style.Triggers>
        <DataTrigger Binding="{Binding Path=Reputation} Value="-1">
          <Setter Property="Visibility" Value="Invisible" />
        </DataTrigger>    
      </Style.Triggers>
    </Style>
  </Page.Resources>

...

  <TextBlock Text="Reputation:" Style="{StaticResource Reputation}">
  <TextBlock Text="{Binding Path=Reputation}" Style="{StaticResource Reputation}">
<Style Key="ReputationContent">
  <Style.Triggers>
    <DataTrigger Binding="{Binding Path=Type} Value="StackOverflow">
      <Setter Property="Visibility" Value="Invisible" />
      <Setter Property="Text" Value="{Binding Path=Reputation}" />
    </DataTrigger>    
  </Style.Triggers>
</Style>
public int? Reputation
    {
        get
        {
            var prop = Dto.GetType().GetProperty("Reputation");
            return (prop != null)? (int)prop.GetValue(Dto, null) : null;
        }
        set
        {
            var prop = Dto.GetType().GetProperty("Reputation");
            if(prop !=null) prop.SetValue(Dto,value, null);
        }
    }