WPF_15_ Format bound data

Posted by dreamline on Wed, 19 Jan 2022 20:03:08 +0100

In order to get a more human appearance, you need to design how to trim data lists and data fields.

data conversion

In the basic binding, there is no change in the transfer of information from source to target. But sometimes we want to transform the information into more friendly content and then present it to the interface. WPF provides two tools:

  • String formatting
  • Value converter

Single attribute

Binding. The stringformat property is created for simple, Standard formatted numbers and dates.

<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}"/>

The value converter is more powerful. Creating a value converter requires four steps:

  1. Create a class that implements the IValueConverter interface
  2. Add the ValueConversion attribute to the class declaration and specify the target data type
  3. Implement the Convert() method
  4. Implement the ConvertBack() method
[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;
    }
}
<!--stay Resources Create converter objects in, which can be used for multiple bindings-->
<Window.Resources>
    <local:PriceConverter x:Key="PriceConverter"/>
</Window.Resources>

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

Multiple attributes

<TextBlock>
    <TextBlock.Text>
        <!--use MultiBinding replace Binding-->
        <MultiBinding StringFromat="{1}, {0}">
            <Binding Path="FirstName"/>
            <Binding Path="LastName"/>
        </MultiBinding>
    </TextBlcok.Text>
</TextBlock>

If you want to do more complex work, you need to use a value converter:

<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();
    }
}

List control

The ItemsControl class defines the basic functions for the controls in the encapsulated list, and all list controls inherit from this class.

Attribute nameexplain
ItemsSourcedata source
DisplayMemberPathProperties that the data item is expected to display (more complex displays use ItemTemplate)
ItemStringFormatFormat text for each item
ItemContainerStyleStyles allow you to set multiple properties of the container that encapsulates each item. Automatically create these wrapper objects
ItemContainerStyleSelectorSelect the StyleSelector object of the style for each item's wrapper
AIternationCountThe number of alternate sets set in the data
ItemTemplateThe template extracts the appropriate data from the bound object and arranges it into the appropriate control combination
ItemTemplateSelectorSelect the DataTemplateSelector object of the template for each item
ItemsPanelFor the panel containing the items in the list, all wrappers are added to this container
GroupStyleDefine how each group should be formatted
GroupStyleSelectorSelect the StyleSelector object of the style for each group

List style

ItemContainerStyle

When a list item is created, the list control passes it down to the ItemContainerStyle property, which is applied to each list item.

<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"/>
            <!--Triggers make the style more exciting-->
            <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>

You can have each ListBoxItem object display a radio button or check box next to the item text

<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 Gets the content initially displayed in the item-->
                                    <!--It can be text or a complex representation-->
                                    <ContentPresenter/>
                                </RadioButton>
                                <!-- Checkbox 
                                    <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>
Alternate entry style

AlternationCount specifies the number of items in the sequence, and alternates the style after changing the number. If it is set to 2, the alternationindex of the first ListBoxItem is 0, the second is 1, the third is 0, and the fourth is 1.

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

Data template

Styles provide basic formatting capabilities, but no matter how you modify a ListBoxItem, it's just a ListBoxItem A data template is a XAML that defines how to display bound data objects. There are two types of controls that support data templates:

  • The content control supports data templates through the ContentTemplate property
  • The list control supports data templates through the ItemTemplate property

Separating and reusing templates

Similar to styles, templates are usually declared as resources for windows or programs.

<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>

Add a data template to the list through the StaticResource reference:

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

If you want to automatically reuse the same template in different types of controls, you can set Datatemplate The datatype property to determine the type of binding data that uses the template.

<Window.Resources>
    <!--The template will be used for any binding in the window Product Object's list control or content control-->
    <DataTemplate DataType="{x:Type local:Product}">
    ...
    </DataTemplate>
</Window.Resources>

Change template

At present, only one template can be used for the whole list. If you want to display different data flexibly in different ways:

  • Using data triggers
  • Use value converter
  • Using the template selector

The template selector checks the binding object and uses the logic provided to select the appropriate template. You need to create a class that inherits from DataTemplateSelector.

ComboBox control

Unlike the ListBox class, the ComboBox class adds two other parts: a selection box that displays the current selection and a drop-down list for selecting items.

ComboBox provides autocomplete input. When typing, WPF fills the remaining content in the selection box with the first item matching the autocomplete suggestion. You can set ComboBox Setting the istextsearchenabled property to false disables this feature.

If the IsEditable property is true, the ComboBox control does not display a copy of the selection, but a text representation of the selection. WPF simply calls the ToString() method. You can set textsearch Textpaht additional attributes to define what the selection box displays:

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

My official account

Topics: xml WPF microsoft