天天看點

WPF_15_格式化綁定的資料

WPF_15_格式化綁定的資料

為了得到更人性化的外觀,需要設計如何修剪資料清單和資料字段。

資料轉換

在基本綁定中,資訊從源到目标傳遞過程沒有任何變化。但有時候希望将資訊轉換到更友好的内容再呈現到界面上。WPF提供了兩個工具:

  • 字元串格式化
  • 值轉換器

單個屬性

Binding.StringFormat 屬性針對簡單的,标準的格式化數字和日期而建立的。

<TextBox Text="{Binding Path=UnitCost, StringFormat={}{0:C}}"/>
<TextBox Text="{Binding Path=UnitCost, StringFormat=The value is {0:C}.}"/>
<ListBox DisplayMemberPath="UnitCost" ItemStringFormat="{0:C}"/>
           

值轉換器功能更強大,建立值轉換器需要4個步驟:

  1. 建立一個實作了 IValueConverter 接口的類
  2. 為該類聲明添加 ValueConversion 特性,并指定目标資料類型
  3. 實作 Convert() 方法
  4. 實作 ConvertBack() 方法
[ValueConversion(typeof(decimal), typeof(string))]
public class PriceConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        decimal price = (decimal)value;
        return price.ToString("C", culture);
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string price = value.ToString(cultere);
        decimal result;
        if(Decimal.TryParse(price, NumberStyles.Any, cultere, out result))
            return result;
        return value;
    }
}
           
<!--在Resources中建立轉換器對象,可以用于多個綁定-->
<Window.Resources>
    <local:PriceConverter x:Key="PriceConverter"/>
</Window.Resources>

<TextBox Text="{Binding Path=UnitCost, Converter={StaticResource PriceConverter}}"/>
           

多個屬性

<TextBlock>
    <TextBlock.Text>
        <!--使用 MultiBinding 替換 Binding-->
        <MultiBinding StringFromat="{1}, {0}">
            <Binding Path="FirstName"/>
            <Binding Path="LastName"/>
        </MultiBinding>
    </TextBlcok.Text>
</TextBlock>
           

如果希望完成更複雜的工作,需要使用值轉換器:

<TextBox>
    <TextBox.Text>
        <MultiBinding Converter="{StaticResource ValueInStockConverter}">
            <Binding Path="UnitCost"/>
            <Binding Path="UnitsInStock"/>
        </MultiBinding>
    </TextBox.Text>
</TextBox>
           
public class VallueInStockConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        decimal unitCost = (decimal)values[0];
        int unitsInStock = (int)value[1];
        return unitCost * unitsInStock;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
           

清單控件

ItemsControl 類為封裝清單中的控件定義了基本功能,所有清單控件都繼承自該類。

屬性名 說明
ItemsSource 資料源
DisplayMemberPath 期望資料項顯示的屬性 (更複雜的顯示使用ItemTemplate)
ItemStringFormat 為每個項格式化文本
ItemContainerStyle 通過樣式可以設定封裝每個項的容器的多個屬性。自動建立這些封裝器對象
ItemContainerStyleSelector 為每項的封裝器選擇樣式的StyleSelector對象
AIternationCount 在資料中設定的交替集合數量
ItemTemplate 模闆從綁定的對象提取合适的資料并安排到合适的控件組合中
ItemTemplateSelector 為每個項選擇模闆的 DataTemplateSelector 對象
ItemsPanel 用于包含清單中項的面闆,所有封裝器都添加到這個容器中
GroupStyle 定義應當如何格式化每個分組
GroupStyleSelector 為每個分組選擇樣式的 StyleSelector 對象

清單樣式

當建立清單項時,清單控件會将其向下傳遞 ItemContainerStyle 屬性,每個清單項都将應用該樣式。

<ListBox Name="lstProducts" Margin="5" DisplayMemberPath="ModelName">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Background" Value="LightSteelBlue"/>
            <Setter Property="Margin" Value="5"/>
            <Setter Property="Padding" Value="5"/>
            <!--觸發器使得樣式更加精彩-->
            <style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="DarkRed"/>
                    <Setter Property="Forground" Value="White"/>
                    <Setter Property="BorderBrush" Value="Blcak"/>
                    <Setter Property="BorderThickness" Value="1"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    <ListBox.ItemContainerStyle>
</ListBox>
           

可以讓每個 ListBoxItem 對象在項文本的旁邊顯示單選按鈕或複選框

<Window.Resources>
    <Style x:Key="RadioButtonListStyle" TargetType="{x:Type ListBox}">
        <Setter Property="ItemContainerStyle">
            <Setter.Value>
                <Style TargetType="{x:Type ListBoxItem">
                    <Setter Property="Margin" Value="2"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                <RadioButton Focusable="False" IsChecked="{Binding Path=IsSelected,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}">
                                    <!--ContentPresenter擷取最初在項中顯示的内容-->
                                    <!--可能是文本,也可能是複雜的表示形式-->
                                    <ContentPresenter/>
                                </RadioButton>
                                <!-- 多選框
                                    <CheckBox Focusable="False" IsChecked="{Binding Path=IsSelected, Model=TwoWay,RelativeSource={RelativeSource TemplatedParent}}">
                                        <ContentPresenter/>
                                    </CheckBox>
                                -->
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
           
交替條目樣式

AlternationCount指定序列中項的數量,經過改數量後交替樣式。如果設定為2,第一個ListBoxItem的 AlternationIndex=0,第二個為1,第三個為0,第四個為1……。

<Style.Triggers>
    <Trigger Property="ItemsControl.AlternationIndex" Value="1">
        <Setter Property="Background" Value="LightBlue"/>
    </Trigger>
</Style.Triggers>
           

資料模闆

樣式提供了基本的格式化能力,但不管如何修改ListBoxItem,它都隻是ListBoxItem.資料模闆是一塊定義如何顯示綁定的資料對象的XAML,有兩種類型的控件支援資料模闆:

  • 内容控件通過 ContentTemplate 屬性支援資料模闆
  • 清單控件通過 ItemTemplate 屬性支援資料模闆

分離和重用模闆

與樣式類似,通常也将模闆聲明為視窗或程式的資源。

<Window.Resources>
    <DataTemplate x:Key="ProductDataTemplate">
        <Border Margin="5" BorderThickness="1" BorderBrush="StellBlue" CornerRadius="4"
            Background="{Binding Path=Background, RelativeSource={
                RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}">
            <Grid Margin="3">
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RouDefinition>
                <TextBlock FontWeight="Bold" Text="{Binding Path=ModelNumber}"/>
                <TextBlock Grid.Row="1" Text="{Binding Path=ModelName}"/>
            </Grid>
        </Border>
    </DataTemplate>
</Window.Resources>
           

通過 StaticResource 引用來為清單添加資料模闆:

<ListBox Name="lstProducts" HorizontalContentAlignment="Stretch"
    ItemTemplate="{StaticResource ProductDataTemplate}"/>
           

如果希望在不同類型的控件中自動重用相同的模闆,可以通過設定 DataTemplate.DataType 屬性來确定使用模闆的綁定資料的類型。

<Window.Resources>
    <!--模闆将用于視窗中任何綁定到Product對象的清單控件或内容控件-->
    <DataTemplate DataType="{x:Type local:Product}">
    ...
    </DataTemplate>
</Window.Resources>
           

改變模闆

目前隻能為整個清單使用一個模闆,如果希望采用不同方式靈活展示不同的資料:

  • 使用資料觸發器
  • 使用值轉換器
  • 使用模闆選擇器

模闆選擇器檢查綁定對象并使用提供的邏輯選擇合适的模闆,需要建立繼承自 DataTemplateSelector 的類。

ComboBox控件

與ListBox類不同的是,ComboBox類增加了另外兩個部分:顯示目前選擇項的選擇框和用于選擇項的下拉清單。

ComboBox提供了自動完成輸入功能,當鍵入内容時,WPF使用第一個比對自動完成建議的項填充選擇框中的剩餘内容。可以通過設定 ComboBox.IsTextSearchEnabled 屬性設定為 false 禁用該功能。

如果IsEditable屬性為 true,ComboBox控件不是顯示選擇項的副本,而是顯示選擇項的文本形式表示,WPF簡單調用ToString()方法。可以通過設定 TextSearch.TextPaht 附加屬性來定義選擇框顯示的内容:

<ComboBox IsEditable="True" IsReadOnly="True" TextSearch.TextPath="ModelName">
...
</ComboBox>
           

我的公衆号

WPF_15_格式化綁定的資料
WPF

繼續閱讀