[英]How to format a string in XAML without changing viewmodel's property getter?
我在我的應用程序中有以下界面:
public interface IContactMedium
{
string ContactString { get; set; }
string Type { get; set;}
bool IsValid();
}
此接口用於表示某人的某種聯系的對象。 它可以是電話,電子郵件等ContactString
屬性是實際的聯系人數據(例如,對於電話,它將是電話號碼),並且Type
用於區分,以防一個人有多個(用於手機,一個人可以擁有家庭電話,工作電話,手機等。) IsValid
方法是每種不同類型的接觸媒體的驗證機制。
所以,假設我的應用程序中有兩個對象 - Email
和Phone
- 都實現了界面。 我將在應用程序中創建一個UserControl
,它包含管理此類對象列表的UI。 所以viewmodel看起來像這樣:
public class ContactsCollectionViewModel<T> : ViewModelBase where T : class, IContactMedium
{
private ObservableCollection<T> _itemsCollection;
public ContactCollectionViewModel(ObservableCollection<T> items)
{
ItemsCollection = items;
}
public ObservableCollection<T> ItemsCollection
{
get { return _itemsCollection; }
set
{
if (_itemsCollection != value)
{
_itemsCollection = value;
OnPropertyChanged(() => ItemsCollection);
}
}
}
}
我想在IContactMedium
接口中添加另一個屬性/方法,該屬性/方法在WPF中的Binding中使用時為ContactString
屬性提供正確的格式。 這個想法是綁定到ContactString
的文本框中的格式根據實際存儲在集合中的具體對象而有所不同:
<TextBox x:Name="ContactString"
Text="{Binding ContactString, StringFormat=???}" />
我在網上搜索了一個解決方案,找不到任何東西。 我看到人們建議修改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
可以訪問它?
格式化是否可以由實現接口的對象決定?
在Xaml中,可以提供與特定類相關聯的數據模板。
只需在模板中提供綁定到目標屬性的格式,如下所示:
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type c:Ship}">
<TextBlock Text="{Binding Path=Name, StringFormat=Ship: {0}}"
Foreground="Red" />
</DataTemplate>
<DataTemplate DataType="{x:Type c:Passage}">
<TextBlock Text="{Binding Path=Name, StringFormat=Passage: {0}}"
Foreground="Blue" />
</DataTemplate>
</Grid.Resources>
<ListBox Name="myListBox"
Height="300"
Width="200"
ItemsSource="{Binding OBSCollection}">
</ListBox>
</Grid>
因此,對於我的集合, Ship
和Passage
類實例都遵循ITreeEntity
:
public ObservableCollection<ITreeEntity> OBSCollection ...
當綁定創建一個列表,其中綁定具有特定的字符串格式,如下所示:
請注意,在設置數據時,首先添加船只,然后添加通道。 無論如何,Xaml都沒有訂購它們。
需要從復合集合中列出一個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();
}
}
將其添加為資源
<Window.Resources>
<local:MyConverter x:Key="MyConverter"/>
</Window.Resources>
用它
<TextBox x:Name="ContactString"
Text="{Binding ContactString, Converter{StaticResource MyConverter}}" />
問題是實現接口的每個具體類都有不同的格式規則
格式化是否可以由實現接口的對象決定?
困境是,是否將格式化邏輯添加到業務對象( IContactMedium
實現)或表示層。
如果是業務邏輯,那么是的,您應該將格式代碼添加到業務對象中。
但最有可能的是表示邏輯。 在這種情況下,要么創建DataTemplate foreach實現IContactMedium
,要么創建轉換器。 在轉換器中,您可以根據值類型選擇正確的格式。 如果輸出只是純文本,請使用轉換器。 如果它更純文本,例如格式化文本,則使用datatemplates。
提示:您可以使用單元測試來測試IContactMedium
所有實現是否具有其DataTemplate或轉換器是否涵蓋。
您可以簡單地覆蓋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
會自動獲取格式化的字符串。
<ListBox Name="myListBox"
Height="300"
Width="200"
ItemsSource="{Binding OBSCollection}"/>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.