簡體   English   中英

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

[英]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方法是每種不同類型的接觸媒體的驗證機制。

所以,假設我的應用程序中有兩個對象 - EmailPhone - 都實現了界面。 我將在應用程序中創建一個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>

因此,對於我的集合, ShipPassage類實例都遵循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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM