背水一戰 Windows 10 (20) - 綁定: DataContextChanged, UpdateSourceTrigger, 對綁定的數據做自定義轉換


[源碼下載]


背水一戰 Windows 10 (20) - 綁定: DataContextChanged, UpdateSourceTrigger, 對綁定的數據做自定義轉換



作者:webabcd


介紹
背水一戰 Windows 10 之 綁定

  • DataContextChanged - FrameworkElement 的 DataContext 發生變化時觸發的事件
  • UpdateSourceTrigger - 數據更新的觸發方式
  • 對綁定的數據做自定義轉換



示例
1、演示 DataContextChanged 的用法
Bind/DataContextChanged.xaml

<Page
    x:Class="Windows10.Bind.DataContextChanged"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.Bind"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">

        <StackPanel Margin="10 0 10 10">

            <TextBlock Name="lblMsg" Margin="5" />

            <Button x:Name="btnChange" Content="改變 listBox 的數據上下文" Click="btnChange_Click" Margin="5" />

            <ListBox x:Name="listBox" ItemsSource="{Binding}" DataContextChanged="listBox_DataContextChanged" Background="Orange" Margin="5" />

        </StackPanel>
    </Grid>
</Page>

Bind/DataContextChanged.xaml.cs

/*
 * DataContextChanged - FrameworkElement 的 DataContext 發生變化時觸發的事件
 */

using System;
using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Windows10.Bind
{
    public sealed partial class DataContextChanged : Page
    {
        public DataContextChanged()
        {
            this.InitializeComponent();

            this.Loaded += DataContextChanged_Loaded;
        }

        private void DataContextChanged_Loaded(object sender, RoutedEventArgs e)
        {
            // 指定數據上下文
            listBox.DataContext = new List<string> { "a", "b", "c" };
        }

        private void btnChange_Click(object sender, RoutedEventArgs e)
        {
            // 修改數據上下文
            listBox.DataContext = new List<string> { "a", "b", new Random().Next(0, 1000).ToString().PadLeft(3, '0') };
        }

        private void listBox_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
        {
            /*
             * FrameworkElement.DataContextChanged - 數據上下文發生改變后觸發的事件
             */

            // 數據上下文發生改變后
            lblMsg.Text = "數據上下文發生改變:" + DateTime.Now.ToString("hh:mm:ss");

        }
    }
}


2、演示 UpdateSourceTrigger 的用法
Bind/UpdateSourceTrigger.xaml

<Page
    x:Class="Windows10.Bind.UpdateSourceTrigger"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.Bind"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">

        <StackPanel Margin="10 0 10 10">

            <TextBlock Name="lblMsg" Foreground="Orange" Margin="5" />

            <!--
                UpdateSourceTrigger - 數據更新的觸發方式
                    Default - 失去焦點后觸發
                    PropertyChanged - 屬性值發生改變后觸發
                    Explicit - 需要通過 BindingExpression.UpdateSource() 顯示觸發
            -->

            <TextBox Text="{Binding Text, Mode=TwoWay, ElementName=lblMsg, UpdateSourceTrigger=Default}" Margin="5" />
            <TextBox Text="{Binding Text, Mode=TwoWay, ElementName=lblMsg, UpdateSourceTrigger=PropertyChanged}" Margin="5" />
            <TextBox Name="txtExplicit" Text="{Binding Text, Mode=TwoWay, ElementName=lblMsg, UpdateSourceTrigger=Explicit}" Margin="5" />

            <Button Name="btnBinding" Content="顯示觸發更新" Click="btnBinding_Click" Margin="5" />

        </StackPanel>
    </Grid>
</Page>

Bind/UpdateSourceTrigger.xaml.cs

/*
 * UpdateSourceTrigger - 數據更新的觸發方式
 *     Default - 失去焦點后觸發
 *     PropertyChanged - 屬性值發生改變后觸發
 *     Explicit - 需要通過 BindingExpression.UpdateSource() 顯示觸發
 *     
 *     
 * BindingExpression - 綁定信息,可以通過 FrameworkElement 的 GetBindingExpression() 方法獲取指定屬性的綁定信息
 *     DataItem - 獲取綁定的源對象
 *     ParentBinding - 獲取綁定的 Binding 對象(Binding 對象里包括 ElementName, Path, Mode 等綁定信息)
 *     UpdateSource() - 將當前值發送到 TwoWay 綁定的源對象的綁定的屬性中
 */

using System;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;

namespace Windows10.Bind
{
    public sealed partial class UpdateSourceTrigger : Page
    {
        public UpdateSourceTrigger()
        {
            this.InitializeComponent();
        }

        private async void btnBinding_Click(object sender, RoutedEventArgs e)
        {
            // 顯示觸發 txtExplicit 的數據更新
            BindingExpression be = txtExplicit.GetBindingExpression(TextBox.TextProperty);
            be.UpdateSource();

            // 獲取綁定的相關信息
            Binding binding = be.ParentBinding;
            TextBlock textBlock = be.DataItem as TextBlock;
            MessageDialog messageDialog = new MessageDialog($"BindingExpression.DataItem:{textBlock.Name}, Binding.Mode:{binding.Mode}");
            await messageDialog.ShowAsync();
        }
    }
}


3、演示如何對綁定的數據做自定義轉換
Bind/BindingConverter.xaml

<Page
    x:Class="Windows10.Bind.BindingConverter"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.Bind"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="10 0 10 10">

            <!--
                配置 IValueConverter 資源
            -->
            <StackPanel.Resources>
                <local:IntegerLetterConverter x:Key="IntegerLetterConverter"/>
                <local:FormatConverter x:Key="FormatConverter"/>
                <x:String x:Key="FormatString">格式化字符串 {0}</x:String>
            </StackPanel.Resources>


            <Slider Name="slider1" Minimum="97" Maximum="122" Value="1" Width="300" Background="White" HorizontalAlignment="Left" Margin="5" />
            <!--
                演示如何使用 Binding 的 Converter, ConverterParameter, ConverterLanguage
                注:ConverterParameter 和 ConverterLanguage 不支持綁定,只能配置為一個靜態的值(但是在 C# 端可以實現一些在 xaml 中無法實現的特性,詳見后面的例子)
            -->
            <TextBox Name="textBox1" Width="300" HorizontalAlignment="Left" Margin="5"
                     Text="{Binding ElementName=slider1, Path=Value, Mode=TwoWay,
                                    Converter={StaticResource IntegerLetterConverter},
                                    ConverterParameter=param, 
                                    ConverterLanguage=zh}" />


            <Slider Name="slider2" Minimum="97" Maximum="122" Value="1" Width="300" Background="White" HorizontalAlignment="Left" Margin="5" />
            <!--
                在 C# 端使用 Binding 的 Converter, ConverterParameter, ConverterLanguage
            -->
            <TextBox Name="textBox2" Width="300" HorizontalAlignment="Left" Margin="5" />
            <TextBlock Name="lblMsg" Margin="5" TextWrapping="Wrap" />


            <!--
                演示如何在 ConverterParameter 中通過 {0} 格式化字符串 
            -->
            <TextBlock Name="textBlock1" Text="我是“textBlock1”" Margin="5" />
            <TextBlock Name="textBlock2" Margin="5" Text="{Binding ElementName=textBlock1, Path=Text,
                                                                   Converter={StaticResource FormatConverter},
                                                                   ConverterParameter={StaticResource FormatString}}" />


        </StackPanel>
    </Grid>
</Page>

Bind/BindingConverter.xaml.cs

/*
 * 演示如何對綁定的數據做自定義轉換
 */

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;

namespace Windows10.Bind
{
    public sealed partial class BindingConverter : Page
    {
        public BindingConverter()
        {
            this.InitializeComponent();

            this.Loaded += BindingConverter_Loaded;
        }

        private void BindingConverter_Loaded(object sender, RoutedEventArgs e)
        {
            // 實例化 Binding 對象
            Binding binding = new Binding()
            {
                ElementName = nameof(slider2),
                Path = new PropertyPath(nameof(Slider.Value)),
                Mode = BindingMode.TwoWay, // 默認是 OneWay 的
                Converter = new IntegerLetterConverter(),
                ConverterParameter = lblMsg, // 將 ConverterParameter 設置為一個指定的控件,這個在 xaml 中實現不了,但是可以在 C# 端實現
                ConverterLanguage = "zh"
            };

            // 將目標對象的目標屬性與指定的 Binding 對象關聯
            BindingOperations.SetBinding(textBox2, TextBox.TextProperty, binding);
        }
    }



    // 自定義一個實現了 IValueConverter 接口的類,用於對綁定的數據做自定義轉換
    public sealed class IntegerLetterConverter : IValueConverter
    {
        /// <summary>
        /// 正向轉換器。將值從數據源傳給綁定目標時,數據綁定引擎會調用此方法
        /// </summary>
        /// <param name="value">轉換之前的值</param>
        /// <param name="targetType">轉換之后的數據類型</param>
        /// <param name="parameter">轉換器所使用的參數(它是通過 Binding 的 ConverterParameter 傳遞過來的)</param>
        /// <param name="language">轉換器所使用的區域信息(它是通過 Binding 的 ConverterLanguage 傳遞過來的)</param>
        /// <returns>轉換后的值</returns>
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if (parameter != null && parameter.GetType() == typeof(TextBlock))
            {
                ((TextBlock)parameter).Text = $"value: {value}, targetType: {targetType}, parameter: {parameter}, language: {language}";
            }

            int v = (int)(double)value;
            return (char)v;
        }

        /// <summary>
        /// 反向轉換器。將值從綁定目標傳給數據源時,數據綁定引擎會調用此方法
        /// </summary>
        /// <param name="value">轉換之前的值</param>
        /// <param name="targetType">轉換之后的數據類型</param>
        /// <param name="parameter">轉換器所使用的參數(它是通過 Binding 的 ConverterParameter 傳遞過來的)</param>
        /// <param name="language">轉換器所使用的區域信息(它是通過 Binding 的 ConverterLanguage 傳遞過來的)</param>
        /// <returns>轉換后的值</returns>
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            if (parameter != null && parameter.GetType() == typeof(TextBlock))
            {
                ((TextBlock)parameter).Text = $"value: {value}, targetType: {targetType}, parameter: {parameter}, language: {language}";
            }

            int v = ((string)value).ToCharArray()[0];
            return v;
        }
    }


    // 自定義一個實現了 IValueConverter 接口的類,用於格式化字符串
    public sealed class FormatConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            string format = (string)parameter;
            return string.Format(format, value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
}



OK
[源碼下載]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM