在Silverlight中,如果第一个属性为空,如何绑定到第二个属性?

3

我有一个类,其中对象的名称可以为null。

public class Thing
{
    /// <summary>
    /// The identifier of the thing
    /// </summary>
    /// <remarks>
    /// This will never be null.
    /// </remarks>
    public string Identifier { get; set; }
    /// <summary>
    /// The name of the thing
    /// </summary>
    /// <remarks>
    /// This MAY be null. When it isn't, it is more descriptive than Identifier.
    /// </remarks>
    public string Name { get; set; }
}

在Silverlight ListBox中,我使用一个DataTemplate,其中将名称绑定到TextBlock:
<DataTemplate x:Key="ThingTemplate">
    <Grid>
        <TextBlock TextWrapping="Wrap" Text="{Binding Name}" />
    </Grid>
</DataTemplate>

然而,如果名称为空,则显然看起来不是很好。理想情况下,我希望使用与以下等效的内容:

string textBlockContent = thing.Name != null ? thing.Name : thing.Identifier;

但我无法更改我的模型对象。有没有好的方法来解决这个问题?

我考虑使用转换器,但似乎我必须将转换器绑定到对象本身,而不是名称属性。这样也可以,但当名称或标识符更改时,我该如何重新绑定?IValueConverter似乎没有任何方法可以强制重新转换,如果我手动监听我的对象的INotifyPropertyChanged事件。

有关最佳方法的任何想法吗?


可能是Equiv. to Coalesce() in XAML Binding?的重复问题。 - Justin Niessner
据我所知,如果不改变代码,你无法做到这一点。如果你找到了一种仅使用XAML的方法,那么很可能会被认为是一种hack。 - qJake
@Nawaz:Silverlight。我在标题中添加了“Silverlight”以使其更明确。 - Bryan
@Gabe:我已经为应用程序的其他部分创建了包装器,这可能是解决问题的方法。我的ViewModel具有ObservableCollection<Db.Thing>,我可能需要将其更改为ObservableCollection<ThingWrapper>。这有点麻烦,因为当我获取数据时,我必须将其全部包装起来,但这是可行的。如果MultiBinding是内置的,那就是我要走的路,但由于它不是,包装可能是我最好的选择。 - Bryan
@Bryan:在Silverlight 5中,您将能够创建像MultiBinding这样的绑定扩展。 - Gabe
显示剩余2条评论
4个回答

3

您可以更改绑定方式,直接将其绑定到您的Thing实例:

<DataTemplate x:Key="ThingTemplate">
    <Grid>
        <TextBlock TextWrapping="Wrap" Text="{Binding .,Converter={StaticResource ConvertMyThingy}" />
    </Grid>
</DataTemplate>

然后使用一个转换器,从传递的Thing实例返回InstanceName

public class ConvertMyThingyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var thing= value as Thing;
        if(thing == null)
           return String.Empty;
        return thing.Name ?? thing.Identifier;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这是一个很好的、简单的处理方法,虽然它不能重复使用于其他类型,因为它需要每种类型(或至少接口)的自定义转换器。 - Reed Copsey
@xor:在我的模型中,我在应用程序的其他地方绑定了两个TextBox到Identifier和Name。当其中一个发生更改时,列表框中的值需要更改。 - Bryan

2

0

Converter 不绑定到 NameObject,它绑定到 Text 属性绑定。因此,每次将值分配给 Text 时,它都会被调用。在 Converter 内部,您可以选择 Text 属性的外观。

可能的解决方案之一是创建一个名为 NameAndIdentifier 的字符串特殊属性,该属性可以根据模型的 NameIdentifier 属性从 Converter 中进行赋值。


0
你需要在你的ViewModel/Presenter(或者你想叫它什么都可以)中创建一个自定义的显示属性。基本上,你上面发布的代码必须被修改,并添加以下内容:
public readonly string DisplayName
{
    get
    {
        return Name ?? Identifier;
    }
}
据我所知,任何其他方法都会是一种hack。

你应该使用 ?? 运算符:return Name ?? Identifier;。这通常是最好的解决方案,尽管这个问题已经无意义了,因为 OP 已经说他不能更改模型。 - dlev
1
值得一提的是,如果其他人看到这个问题,他们可以编辑他们的模型。关于“??”运算符的好点子,我总是会忘记它。 ;) - qJake

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接