74、数据绑定中的值转换器与数据模板应用

数据绑定中的值转换器与数据模板应用

1. 数据绑定基础与值转换器概述

在数据绑定中, Binding.StringFormat 属性可用于简单的数字和日期格式化。但在许多场景下,需要更强大的工具——值转换器类。值转换器的作用是在源数据显示在目标之前进行转换,对于双向绑定,还会在新的目标值应用回源之前进行转换。

值转换器有多种用途:
- 格式化数据为字符串表示 :例如将数字转换为货币字符串。
- 创建特定类型的对象 :如将二进制数据转换为 BitmapImage 对象。
- 基于绑定数据有条件地更改元素属性 :例如根据价格范围更改元素的背景颜色。

2. 使用值转换器格式化字符串

以货币格式化为例,若想了解值转换器的工作原理,可回顾之前的示例。使用值转换器不仅能实现与 Binding.StringFormat 相同的功能,还能进行更多操作,如对值进行四舍五入、使用数字名称或添加经销商加价等,同时可定制反向转换的方式。

创建值转换器需以下三个步骤:
1. 创建一个实现 IValueConverter (来自 System.Windows.Data 命名空间)的类,并将其放在 Silverlight 项目中。
2. 实现 Convert() 方法,将数据从原始格式转换为显示格式。
3. 实现 ConvertBack() 方法,进行反向转换,将显示格式的值转换为原始格式。

以下是处理价格值(如 Product.UnitCost 属性)的值转换器的完整代码:

Public Class PriceConverter
    Implements IValueConverter

    Public Function Convert(ByVal value As Object, ByVal targetType As Type, _
      ByVal parameter As Object, ByVal culture As CultureInfo) As Object _
      Implements IValueConverter.Convert

        Dim price As Double = CDbl(value)
        Return price.ToString("C", culture)
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, _
      ByVal parameter As Object, ByVal culture As CultureInfo) As Object _
      Implements IValueConverter.ConvertBack

        Dim price As String = value.ToString()
        Dim result As Double
        If Double.TryParse(price, NumberStyles.Any, culture, result) Then
            Return result
        End If
        Return value
    End Function
End Class

要使用此转换器,需按以下操作步骤进行:
1. 将项目命名空间映射到可在标记中使用的 XML 命名空间前缀,例如:

xmlns:local="clr-namespace:DataBinding"

通常将此属性添加到 <UserControl> 开始标记的顶部。
2. 在页面的 Resources 集合中创建 PriceConverter 类的实例:

<UserControl.Resources>
  <local:PriceConverter x:Key="PriceConverter"></local:PriceConverter>
</UserControl.Resources>
  1. 在绑定中使用 StaticResource 引用指向该转换器:
<TextBox Margin="5" Grid.Row="2" Grid.Column="1" 
 Text="{Binding UnitCost, Mode=TwoWay, Converter={StaticResource PriceConverter}}"> 
</TextBox>
3. 使用值转换器创建对象

当需要弥合数据存储方式与页面显示方式之间的差距时,值转换器不可或缺。例如,若图片数据以字节数组形式存储在数据库字段中,可使用值转换器将二进制数据转换为 BitmapImage 对象。

Store 数据库的 Products 表中的 ProductImage 字段存储了关联产品图像的文件名,但不包含完整的 URI。值转换器的任务是根据该字段和所需的网站创建指向图像文件的 URI。

以下是实现此转换的 ImagePathConverter 类的完整代码:

Public Class ImagePathConverter
    Implements IValueConverter

    Private _rootUri As String
    Public Property RootUri() As String
        Get
            Return _rootUri
        End Get
        Set(ByVal value As String)
            _rootUri = value
        End Set
    End Property

    Public Sub New()
        Dim uri As String = HtmlPage.Document.DocumentUri.ToString()

        ' Remove the web page from the current URI to get the root URI.
        RootUri = uri.Remove(uri.LastIndexOf("/"c), _
          uri.Length - uri.LastIndexOf("/"c))
    End Sub

    Public Function Convert(ByVal value As Object, ByVal targetType As Type, _
      ByVal parameter As Object, ByVal culture As CultureInfo) As Object _
      Implements IValueConverter.Convert

        Dim imagePath As String = RootUri & "/" & CStr(value)
        Return New BitmapImage(New Uri(imagePath))
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, _
      ByVal parameter As Object, ByVal culture As CultureInfo) As Object _
      Implements IValueConverter.ConvertBack
        ' Images aren't editable, so there's no need to support ConvertBack.
        Throw New NotSupportedException()
    End Function
End Class

使用此转换器的操作步骤如下:
1. 将其添加到 Resources 中:

<UserControl.Resources>
  <local:ImagePathConverter x:Key="ImagePathConverter"></local:ImagePathConverter>
</UserControl.Resources>
  1. 创建使用该值转换器的绑定表达式:
<Image Margin="5" Grid.Row="2" Grid.Column="1" Stretch="None" 
 HorizontalAlignment="Left" Source= 
 "{Binding ProductImagePath, Converter={StaticResource ImagePathConverter}}"> 
</Image>
4. 应用条件格式

有些值转换器并非用于格式化数据以进行展示,而是基于数据规则格式化元素的其他外观相关方面。例如,可创建一个值转换器,根据价格范围更改元素的背景颜色,以标记高价商品。

以下是实现此功能的 PriceToBackgroundConverter 类的完整代码:

Public Class PriceToBackgroundConverter
    Implements IValueConverter

    Private _minimumPriceToHighlight As Double
    Public Property MinimumPriceToHighlight() As Double
        Get
            Return _minimumPriceToHighlight
        End Get
        Set(ByVal value As Double)
            _minimumPriceToHighlight = value
        End Set
    End Property

    Private _highlightBrush As Brush
    Public Property HighlightBrush() As Brush
        Get
            Return _highlightBrush
        End Get
        Set(ByVal value As Brush)
            _highlightBrush = value
        End Set
    End Property

    Private _defaultBrush As Brush
    Public Property DefaultBrush() As Brush
        Get
            Return _defaultBrush
        End Get
        Set(ByVal value As Brush)
            _defaultBrush = value
        End Set
    End Property

    Public Function Convert(ByVal value As Object, ByVal targetType As Type, _
      ByVal parameter As Object, ByVal culture As CultureInfo) As Object _
      Implements IValueConverter.Convert

        Dim price As Double = CDbl(value)
        If price >= MinimumPriceToHighlight Then
            Return HighlightBrush
        Else
            Return DefaultBrush
        End If
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, _
      ByVal parameter As Object, ByVal culture As CultureInfo) As Object _
      Implements IValueConverter.ConvertBack

        Throw New NotSupportedException()
    End Function
End Class

使用此转换器的操作步骤如下:
1. 在 XAML 中配置转换器的属性:

<local:PriceToBackgroundConverter x:Key="PriceToBackgroundConverter" 
  DefaultBrush="{x:Null}" HighlightBrush="Orange" MinimumPriceToHighlight="50"> 
</local:PriceToBackgroundConverter>
  1. 使用该转换器设置元素的背景:
<Border Background= 
 "{Binding UnitCost, Converter={StaticResource PriceToBackgroundConverter}}" 
 ... > 

也可通过 ConverterParameter 属性传递单个对象到转换器,例如传递最低价格:

<Border Background= 
 "{Binding UnitCost, Converter={StaticResource PriceToBackgroundConverter}, 
ConverterParameter=50}" 
 ... > 

同时,可重写 Convert() 方法以使用该参数:

Public Function Convert(ByVal value As Object, ByVal targetType As Type, _
  ByVal parameter As Object, ByVal culture As CultureInfo) As Object _
  Implements IValueConverter.Convert

    Dim price As Double = CDbl(value)
    If price >= Double.Parse(parameter) Then
        Return HighlightBrush
    Else
        Return DefaultBrush
    End If
End Function
5. 数据模板

数据模板是一段 XAML 标记,用于定义绑定数据对象的显示方式。有两种类型的控件支持数据模板:
- 内容控件 :通过 ContentTemplate 属性支持数据模板,用于显示 Content 属性中的内容。
- 列表控件 :(派生自 ItemsControl )通过 ItemTemplate 属性支持数据模板,用于显示 ItemsSource 集合中的每个项。

数据模板是普通的 XAML 标记块,可包含任意元素组合,且应包含一个或多个数据绑定表达式以提取要显示的信息。

以列表框为例,不使用模板的列表框如下:

<ListBox Name="lstProducts" DisplayMemberPath="ModelName"></ListBox>

使用数据模板实现相同效果的列表框如下:

<ListBox Name="lstProducts">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding ModelName}"></TextBlock>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

若想更有创意地展示数据,可使用更复杂的模板,例如将每个项包装在圆角边框中,显示两条信息,并使用粗体格式突出显示型号编号:

<ListBox Name="lstProducts" HorizontalContentAlignment="Stretch" 
 SelectionChanged="lstProducts_SelectionChanged">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <Border Margin="5" BorderThickness="1" BorderBrush="SteelBlue" 
       CornerRadius="4">
        <Grid Margin="3">
          <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
          </Grid.RowDefinitions>
          <TextBlock FontWeight="Bold" 
           Text="{Binding ModelNumber}"></TextBlock>
          <TextBlock Grid.Row="1" 
           Text="{Binding ModelName}"></TextBlock>
        </Grid>
      </Border>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>
6. 分离和重用模板

与样式类似,模板通常作为页面或应用程序资源声明,而非在使用它们的列表中定义。这样做更清晰,尤其是在使用长而复杂的模板或在同一控件中使用多个模板时,还能在不同的列表或内容控件中重用模板。

操作步骤如下:
1. 在资源集合中定义数据模板并赋予键名,例如提取前面示例中的模板:

<UserControl.Resources>
  <DataTemplate x:Key="ProductDataTemplate">
    <Border Margin="5" BorderThickness="1" BorderBrush="SteelBlue" 
     CornerRadius="4">
      <Grid Margin="3">
        <Grid.RowDefinitions>
          <RowDefinition></RowDefinition>
          <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock FontWeight="Bold" 
         Text="{Binding ModelNumber}"></TextBlock>
      </Grid>
    </Border>
  </DataTemplate>
</UserControl.Resources>

通过以上介绍,我们了解了值转换器和数据模板在数据绑定中的重要作用及具体应用方式,合理使用它们能让数据展示更加灵活和美观。

数据绑定中的值转换器与数据模板应用

7. 值转换器与数据模板的优势总结

值转换器和数据模板在数据展示和处理方面具有显著优势,以下为您详细总结:
| 特性 | 优势描述 |
| — | — |
| 值转换器 | - 提供强大的格式化能力,可实现数字、日期等的多样化格式化,如货币格式化、数字名称转换等。
- 灵活处理数据类型转换,能将二进制数据转换为图像对象,适应不同的数据存储和显示需求。
- 支持条件格式化,可根据数据规则改变元素的外观属性,如背景颜色,增强数据的可读性和可视化效果。 |
| 数据模板 | - 高度定制化数据显示方式,可根据需求组合各种元素和绑定表达式,使数据展示更加丰富和个性化。
- 分离数据和显示逻辑,提高代码的可维护性和可扩展性,便于在不同场景下重用模板。 |

8. 实际应用场景分析

为了更好地理解值转换器和数据模板的实际应用,下面通过几个常见场景进行分析:
- 电商产品展示 :在电商应用中,产品列表需要展示产品的名称、价格、图片等信息。可以使用数据模板将这些信息组合展示,同时使用值转换器对价格进行货币格式化,对图片路径进行处理。

<ListBox Name="lstProducts">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal">
        <Image Source="{Binding ProductImagePath, Converter={StaticResource ImagePathConverter}}" Width="50" Height="50"/>
        <StackPanel>
          <TextBlock Text="{Binding ModelName}"/>
          <TextBlock Text="{Binding UnitCost, Converter={StaticResource PriceConverter}}"/>
        </StackPanel>
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>
  • 数据报表 :在生成数据报表时,可能需要根据数据的大小或范围对单元格进行颜色标记。可以使用值转换器实现条件格式化,突出显示关键数据。
<DataGrid ItemsSource="{Binding DataList}">
  <DataGrid.Columns>
    <DataGridTextColumn Header="数值" Binding="{Binding Value, Converter={StaticResource PriceToBackgroundConverter}}"/>
  </DataGrid.Columns>
</DataGrid>
9. 优化建议

在使用值转换器和数据模板时,为了提高性能和代码质量,可参考以下优化建议:
- 值转换器
- 缓存转换结果:对于一些频繁使用且转换结果不变的数据,可将转换结果进行缓存,避免重复转换。
- 异常处理:在 Convert ConvertBack 方法中添加适当的异常处理,确保程序的健壮性。
- 数据模板
- 避免过度嵌套:复杂的嵌套结构会增加渲染时间,尽量保持模板结构简洁。
- 合理使用绑定:避免不必要的绑定,减少数据更新时的性能开销。

10. 总结与展望

值转换器和数据模板是数据绑定中非常强大的工具,它们为数据的展示和处理提供了极大的灵活性和可定制性。通过合理使用值转换器和数据模板,可以使应用程序的数据展示更加美观、直观,同时提高代码的可维护性和可扩展性。

未来,随着技术的不断发展,值转换器和数据模板可能会有更多的应用场景和优化方式。例如,结合人工智能和机器学习技术,实现更智能的数据格式化和展示;进一步优化性能,减少渲染时间,提升用户体验。

总之,掌握值转换器和数据模板的使用方法,对于开发高质量的数据驱动应用程序至关重要。希望本文能帮助您更好地理解和应用这些技术,在实际项目中取得更好的效果。

11. 操作流程总结

为了方便您快速回顾和应用上述技术,以下是值转换器和数据模板使用的操作流程总结:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B{选择操作类型}:::decision
    B -->|值转换器| C(创建实现 IValueConverter 的类):::process
    C --> D(实现 Convert 和 ConvertBack 方法):::process
    D --> E(在 XAML 中映射命名空间):::process
    E --> F(在 Resources 中创建转换器实例):::process
    F --> G(在绑定中引用转换器):::process
    B -->|数据模板| H(确定支持模板的控件类型):::process
    H --> I(编写 XAML 模板代码):::process
    I --> J(在控件中设置模板属性):::process
    G --> K([结束]):::startend
    J --> K

通过以上流程,您可以清晰地了解值转换器和数据模板的使用步骤,在实际开发中更加高效地应用这些技术。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值