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

当创建列表项时,列表控件会将其向下传递 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>

我的公众号

文章出处:https://www.cnblogs.com/jqwang/p/15818446.html

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
管理员
上一篇:记一次.Net Core程序启动失败的排查过程
下一篇:使用.NET 6开发TodoList应用(填坑1)——实现当前登录用户获取
评论列表

发表评论

评论内容
昵称:
关联文章

WPF_15_格式化数据
数据模式
WPF Command并传参(以DataGrid示例)
C# NPOI导出excel下拉数据
WPF 双向到非公开 set 方法属性在 NET 45 和 NET Core 行为不同
使用.NET 6开发TodoList应用(26)——实现Configuration和Option强类型
YESWEB开发框架,账套域名
从一次解决Nancy参数“bug”开始发布自己第一个nuget包(下篇)
支付宝支付报错:40003,三方应用未服务商账号
winform对象数据
从一次解决Nancy参数“bug”开始发布自己第一个nuget包(上篇)
C# 值得永久收藏WPF项目实战(经典)
OCR识别:abbyy finereader 15
WPF 组织机构摄像机树 全量加载 大数据量 分页加载摄像机节点
走进WPF之MVVM完整案例
WPF 引用第三方库控件在设计器加上设计时数据和属性
[WPF] 实现 WPF Inner Shadow
WPF程序级资源
JSON.stringify 输出格式化文本
使用.NET 6开发TodoList应用(15)——实现查询搜索

联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码