如何在不更改viewmodel的属性getter的情况下格式化XAML中的字符串?

我在我的应用程序中有以下界面:

public interface IContactMedium { string ContactString { get; set; } string Type { get; set;} bool IsValid(); } 

此接口用于表示某人的某种联系的对象。 它可以是电话,电子邮件等ContactString属性是实际的联系人数据(例如,对于电话,它将是电话号码),并且Type用于区分,以防一个人有多个(用于手机,一个人可以拥有家庭电话,工作电话,手机等。) IsValid方法是每种不同类型的接触媒体的validation机制。

所以,假设我的应用程序中有两个对象 – EmailPhone – 都实现了界面。 我将在应用程序中创建一个UserControl ,它包含一个管理此类对象列表的UI。 所以viewmodel看起来像这样:

 public class ContactsCollectionViewModel : ViewModelBase where T : class, IContactMedium { private ObservableCollection _itemsCollection; public ContactCollectionViewModel(ObservableCollection items) { ItemsCollection = items; } public ObservableCollection ItemsCollection { get { return _itemsCollection; } set { if (_itemsCollection != value) { _itemsCollection = value; OnPropertyChanged(() => ItemsCollection); } } } } 

我想在IContactMedium接口中添加另一个属性/方法,该属性/方法在WPF中的Binding中使用时为ContactString属性提供正确的格式。 这个想法是绑定到ContactString的文本框中的格式根据实际存储在集合中的具体对象而有所不同:

  

我在网上搜索了一个解决方案,找不到任何东西。 我看到人们建议修改ContactString属性,以便getter返回格式化的值。 因此,对于Phone对象,例如,属性将如下所示:

 public string ContactString { get { return string.Format("({0}) {1}-{2}", _contactString.Substring(0,3), _contactString.Substring(4,3), _contactString.Substring(7,3)); } set { _contactString = value; } } 

但是,这对我来说不是一个好的解决方案。 该信息不仅由UI使用。 它还被发送到应用程序的其他部分,包括数据库,需要原始格式的电话号码:##########。

有没有办法为XAML提供格式化程序以在绑定的StringFormat属性中使用? 格式化是否可以由实现接口的对象决定? 如果是,它需要什么类型,以及如何使XAML中的Binding可以访问它?

问题是实现接口的每个具体类都有不同的格式规则

格式化是否可以由实现接口的对象决定?

困境是,是否将格式化逻辑添加到业务对象( IContactMedium实现)或表示层。

如果是业务逻辑,那么是的,您应该将格式代码添加到业务对象中。

但最有可能的是表示逻辑。 在这种情况下,要么创建DataTemplate foreach实现IContactMedium ,要么创建转换器。 在转换器中,您可以根据值类型选择正确的格式。 如果输出只是纯文本,请使用转换器。 如果它更纯文本,例如格式化文本,则使用datatemplates。

提示:您可以使用unit testing来测试IContactMedium所有实现是否具有其DataTemplate或转换器是否涵盖。

格式化是否可以由实现接口的对象决定?

在Xaml中,可以提供与特定类相关联的数据模板。

只需在模板中提供绑定到目标属性的格式,如下所示:

             

因此,对于我的集合, ShipPassage类实例都遵循ITreeEntity

  public ObservableCollection OBSCollection ... 

当绑定创建一个列表,其中绑定具有特定的字符串格式,如下所示:

在此处输入图像描述

请注意,在设置数据时,首先添加船只,然后添加通道。 无论如何,Xaml都没有订购它们。


需要从复合集合中列出一个ListBox中的不同类型对象吗? 在这里查看我的答案:

  • 复合集合ListBox答案
  • 列表框和模板的基本示例

你可以使用转换器。 保持您的财产简单。

 public string ContactString { get; set; } 

实现转换器

 class MyConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { contactString = value as string; if(contactString == null) { throw new InvalidArgumentException(); } return string.Format("({0}) {1}-{2}", contactString.Substring(0,3), contactString.Substring(4,3), contactString.Substring(7,3)); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } 

将其添加为资源

    

用它

  

您可以简单地覆盖ToString()方法。 默认情况下, ListBox将使用对象的ToString()方法作为项目的显示文本。

 public override string ToString() { return string.Format("({0}) {1}-{2}", _contactString.Substring(0,3), _contactString.Substring(4,3), _contactString.Substring(7,3)); } 

这意味着您不必在ListBox执行任何奇特的操作,例如定义DataTemplate ,因为ListBox将自动拾取格式化的字符串。