zoukankan      html  css  js  c++  java
  • 背水一战 Windows 10 (21)

    [源码下载]


    背水一战 Windows 10 (21) - 绑定: x:Bind 绑定, x:Bind 绑定之 x:Phase, 使用绑定过程中的一些技巧



    作者:webabcd


    介绍
    背水一战 Windows 10 之 绑定

    • x:Bind 绑定
    • x:Bind 绑定之 x:Phase
    • 使用绑定过程中的一些技巧



    示例
    1、演示 x:Bind 绑定的相关知识点
    Bind/BindDemo.xaml

    <Page
        x:Class="Windows10.Bind.BindDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Windows10.Bind"
        xmlns:common="using:Windows10.Common"
        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">
    
                <!--
                    关于 x:Bind 的相关说明:
                    1、Binding 是在运行时(RunTime)绑定;而 x:Bind 是在编译时(BuildTime)绑定(其会在编译时自动生成一些辅助代码,参见对应的 g.cs 代码),所以 x:Bind 的效率要高
                    2、x:Bind 是强类型绑定,类型必须比配;Binding 在绑定时如果类型不必配,会做自动转换
                    3、x:Bind 只具有 Binding 的一部分功能,如下: Path, Mode. FallbackValue, TargetNullValue, Converter, ConverterParameter, ConverterLanguage
                    4、x:Bind 的 Mode 的默认值是 OneTime;Binding 的 Mode 的默认值是 OneWay
                    5、x:Bind 的数据上下文是其所属的 Page 或 UserControl, 不能为 x:Bind 指定其他的数据上下文
                    6、x:Bind 在 DataTemplate 中使用时,必须指定 DataTemplate 的 DataType;而 Binding 则不必
                    7、x:Bind 只能在 xaml 中使用,无法在 CodeBehind 中使用
                    8、x:Bind 支持事件绑定到方法
                    9、仔细看看上面的说明,x:Bind 与 Binding 的大部分不同的本质原因是,他们一个是编译时绑定,一个是运行时绑定
                -->
                
                <!--绑定到属性-->
                <TextBlock Name="textBlock" Text="{x:Bind Path=CurrentEmployee.Name, Mode=OneWay}" Margin="5" />
    
                <!--事件绑定到方法,无参数-->
                <Button Content="修改 CurrentEmployee 的 MyName" Click="{x:Bind EventBindNoArgs}" Margin="5" />
    
                <!--事件绑定到方法,参数与对应的事件的参数相同-->
                <Button Content="修改 CurrentEmployee 的 MyName" Click="{x:Bind EventBindRegularArgs}" Margin="5" />
    
                <!--事件绑定到方法,参数与对应的事件的参数相同,但是其中的事件参数为 object 类型-->
                <Button Content="修改 CurrentEmployee 的 MyName" Click="{x:Bind EventBindBaseArgs}" Margin="5" />
    
                <!--事件绑定到方法,也可以绑定到指定对象中的指定方法-->
                <Button Content="修改 CurrentEmployee 的 MyName" Click="{x:Bind CurrentEmployee.ChangeName}" Margin="5" />
    
                <!--在 DataTemplate 中使用 x:Bind 的注意事项:必须要指定 DataTemplate 的 DataType-->
                <ListView x:Name="listView" ItemsSource="{x:Bind AllEmployees}" Margin="5">
                    <ListView.ItemTemplate>
                        <DataTemplate x:DataType="common:Employee">
                            <TextBlock Text="{x:Bind Name}" />
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
    
                <!--可以与索引器绑定-->
                <TextBlock Name="textBlock2" Text="{x:Bind Path=AllEmployees[0].Name, Mode=OneWay}" Margin="5" />
    
                <!--可以与 Element 绑定-->
                <TextBlock Name="textBlock3" Text="{x:Bind textBlock2.Text, Mode=OneWay}" Margin="5" />
    
            </StackPanel>
        </Grid>
    </Page>

    Bind/BindDemo.xaml.cs

    /*
     * 演示 x:Bind 绑定的相关知识点
     */
    
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows10.Common;
    
    namespace Windows10.Bind
    {
        // x:Bind 的数据上下文就是它所属的 Page 或 UserControl
        public sealed partial class BindDemo : Page
        {
            public BindDemo()
            {
                this.InitializeComponent();
            }
    
            // 事件绑定到方法,无参数
            private void EventBindNoArgs()
            {
                CurrentEmployee.Name = "wanglei" + new Random().Next(1000, 10000).ToString();
            }
    
            // 事件绑定到方法,参数与对应的事件的参数相同
            private void EventBindRegularArgs(object sender, RoutedEventArgs e)
            {
                CurrentEmployee.Name = "wanglei" + new Random().Next(1000, 10000).ToString();
            }
    
            // 事件绑定到方法,参数与对应的事件的参数相同,但是其中的事件参数为 object 类型
            private void EventBindBaseArgs(object sender, object e)
            {
                CurrentEmployee.Name = "wanglei" + new Random().Next(1000, 10000).ToString();
            }
    
            public Employee CurrentEmployee { get; set; } = new Employee() { Name = "wanglei", Age = 36, IsMale = true };
    
            public ObservableCollection<Employee> AllEmployees { get; set; } = TestData.GetEmployees(5);
        }
    }


    2、演示 x:Bind 绑定之 x:Phase 的相关知识点
    Bind/PhaseDemo.xaml

    <Page
        x:Class="Windows10.Bind.PhaseDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Windows10.Bind"
        xmlns:common="using:Windows10.Common"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Page.Resources>
    
            <!--
                关于 x:Phase 的相关说明:
                1、x:Phase 可以实现元素的分阶段显示,用于避免绘制大量数据时的卡顿
                2、ListView 和 GridView 均继承自 ListViewBase
                3、在 windows 8.1 及以后版本中,ListViewBase 是支持 UI 虚拟化的
                4、x:Phase 只适用于 ListViewBase 中的 DataTemplate 里的元素
                5、x:Phase 属于 x:Bind 的一项功能,所以其必须在指定了 x:Bind 的元素中使用才有效
                6、x:Phase 的作用是解决如下问题:当 ListViewBase 滚动时,如果一屏的 item 多,且每个 item 中的 element 也多,那么绘制时会占用大量的资源以至卡顿
                7、在 windows 8.1 及以后版本中,我们可以通过 ContainerContentChanging 事件手动控制列表项的呈现,而 x:Phase 的原理其实就是在编译时自动生成这种手动控制代码(参见对应的 g.cs 代码)
                   关于如何手动控制列表项的呈现,请参见 /Controls/CollectionControl/ListViewBaseDemo/ListViewBaseDemo4.xaml
            -->
            
            <DataTemplate x:Key="PhasedFileTemplate" x:DataType="common:Employee">
                <StackPanel Width="200" Margin="10" Background="Blue">
                    <TextBlock Margin="5" Text="{x:Bind Name}" Foreground="Red" x:Phase="9" />
                    <TextBlock Margin="5" Text="{x:Bind Name}" Foreground="White" />
                    <TextBlock Margin="5" Text="{x:Bind Name}" Foreground="Green" x:Phase="1" />
                    <TextBlock Margin="5" Text="{x:Bind Name}" Foreground="Orange" x:Phase="2" />
                    <TextBlock Margin="5" Text="{x:Bind Name}" Foreground="Orange" x:Phase="2" />
                </StackPanel>
            </DataTemplate>
    
        </Page.Resources>
    
        <Grid Background="Transparent">
    
            <!--
                ShowsScrollingPlaceholders="false" - 不显示占位符
                ContainerContentChanging - 项容器的内容发生变化时触发的事件(在本例中,其用于人为减慢每阶段的显示速度,以便演示)
            
                关于 ShowsScrollingPlaceholders, ContainerContentChanging 的详细说明请参见 ListView, GridView 部分
            -->
            <GridView Name="gridView" Margin="10 0 10 10" ShowsScrollingPlaceholders="false" ContainerContentChanging="gridView_ContainerContentChanging"
                      ItemsSource="{x:Bind AllEmployees}" ItemTemplate="{StaticResource PhasedFileTemplate}" />
    
        </Grid>
    </Page>

    Bind/PhaseDemo.xaml.cs

    /*
     * 演示 x:Bind 绑定之 x:Phase 的相关知识点
     */
    
    using System.Collections.ObjectModel;
    using System.Threading;
    using Windows.UI.Xaml.Controls;
    using Windows10.Common;
    
    namespace Windows10.Bind
    {
        public sealed partial class PhaseDemo : Page
        {
            public PhaseDemo()
            {
                this.InitializeComponent();
            }
    
            // 用于人为减慢每阶段的显示速度,以便演示
            private void gridView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
            {
                AutoResetEvent h = new AutoResetEvent(false);
                h.WaitOne(1);
    
                uint phase = args.Phase;
                if (phase < 10)
                    args.RegisterUpdateCallback(gridView_ContainerContentChanging);
            }
    
            // 数据源
            public ObservableCollection<Employee> AllEmployees { get; set; } = TestData.GetEmployees(1000);
        }
    }


    3、演示使用绑定过程中的一些技巧
    Bind/Tips.xaml

    <Page
        x:Class="Windows10.Bind.Tips"
        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"
        
        xmlns:common="using:Windows10.Common"
        Background="Red">
    
        <Page.Resources>
            <common:NullableBooleanToBooleanConverter x:Key="NullableBooleanToBooleanConverter" />
        </Page.Resources>
        
        <Grid Background="Transparent">
            <StackPanel Margin="10 0 10 10">
    
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    
                    <!--绑定附加属性,注意要用括号括起来-->
                    <TextBox Name="textBox1" Margin="5" Text="{Binding Path=(Grid.Row), RelativeSource={RelativeSource Self}}" Grid.Row="0" />
    
                    <!--使用绑定时,可以在 Binding 或 x:Bind 后直接加 Path 的值,而不用写“Path=”-->
                    <TextBox Name="textBox2" Margin="5" Text="{Binding (Grid.Row), RelativeSource={RelativeSource Self}}" Grid.Row="1" />
    
                    <!--在 CodeBehind 端绑定附加属性-->
                    <TextBox Name="textBox3" Margin="5" Grid.Row="2" />
                </Grid>
    
                <!--绑定自定义附加属性(在 CodeBehind 端绑定自定义附加属性暂时没有成功)-->
                <TextBox Name="textBox4" Margin="5" local:MyAttachedProperty.SubTitle="custom attached property" Text="{Binding (local:MyAttachedProperty.SubTitle), RelativeSource={RelativeSource Self}}" />
    
                <!--绑定指定对象的指定属性-->
                <TextBox Name="textBox5" Margin="5" Text="{Binding Margin.Top, RelativeSource={RelativeSource Self}}" />
                
                <!--
                    Background 是 Brush 类型
                    SolidColorBrush 继承自 Brush
                    Background.(SolidColorBrush.Color) 的意思就是将 Background 的 Brush 类型转换为 SolidColorBrush 类型并取其 Color 属性
                -->
                <TextBox Name="textBox6" Margin="5" Text="{x:Bind Background.(SolidColorBrush.Color)}" />
    
                <!--
                    x:Bind 没有 ElementName,那如何与其他元素绑定呢,像下面这样即可
                -->
                <TextBox Name="textBox7" Margin="5" Text="{x:Bind textBox6.Text}" />
    
                <!--
                    x:Bind 如何绑定到其他元素的附加属性呢,像下面这样即可
                -->
                <TextBox Name="textBox8" Margin="5" Text="{x:Bind textBox2.(Grid.Row)}" />
    
                <!--
                    x:Bind 如何绑定到其他元素的自定义附加属性呢,像下面这样即可
                -->
                <TextBox Name="textBox9" Margin="5" Text="{x:Bind textBox4.(local:MyAttachedProperty.SubTitle)}" />
    
                <!--
                    在本例中 CurrentEmployee 是 object 类型,要将他转换为 Employee 类型,然后再使用其属性,写法如下
                -->
                <TextBox Name="textBox10" Margin="5" Text="{x:Bind CurrentEmployee.(common:Employee.Name)}" />
    
                <!--
                    Binding 也可以这么写(x:Bind 不支持这么写)
                -->
                <TextBox Name="textBox11" Margin="5">
                    <TextBox.Text>
                        <Binding Path="Text" ElementName="textBox6" />
                    </TextBox.Text>
                </TextBox>
    
                <!--
                    下面的示例用于演示如何绑定到 DataContext 对象的某个属性
                -->
                <TextBox Name="textBox12" DataContext="{x:Bind CurrentEmployee}" Text="{Binding Name}" Margin="5" />
                
                <!--
                    下面的示例用于演示如何直接绑定到 DataContext 对象(而不是绑定 DataContext 对象的某个属性)
                -->
                <TextBox Name="textBox13" DataContext="{x:Bind MyName}" Text="{Binding}" Margin="5" />
    
                <!--
                    Binding 绑定时,如果数据类型不一致,会尝试自动转换,比如此例:bool? 会被自动自动转换为 bool
                -->
                <TextBox Name="textBox14" Text="我是 textBox14" IsReadOnly="{Binding IsChecked, ElementName=chk1}" Margin="5" />
                <CheckBox Name="chk1" Content="textBox14 IsReadOnly" IsChecked="True" Margin="5 0 0 0" />
    
                <!--
                    x:Bind 是编译时的强类型绑定,如果数据类型不一致,不会自动转换,比如此例:要通过 Converter 把 bool? 转换为 bool
                -->
                <TextBox Name="textBox15" Text="我是 textBox15" IsReadOnly="{x:Bind chk2.IsChecked, Mode=TwoWay, Converter={StaticResource NullableBooleanToBooleanConverter}}" Margin="5" />
                <CheckBox Name="chk2" Content="textBox15 IsReadOnly" IsChecked="True" Margin="5 0 0 0" />
    
                <!--
                    再看看绑定此种路径时的写法,要理解
                -->
                <Rectangle Name="rectangle1" Height="20" Fill="Orange" Margin="5" />
                <TextBox Name="textBox16" Margin="5 0 0 0" Text="{x:Bind rectangle1.(Shape.Fill).(SolidColorBrush.Color)}" />
    
                <!--
                    再来个更长的看看,要理解
                -->
                <Rectangle Name="rectangle2" Height="20" Width="100" HorizontalAlignment="Left" Fill="Orange" Margin="5">
                    <!--
                        注:这里必须先要声明出 ScaleTransform,这样才能与之绑定(否则运行时会报错)
                    -->
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <ScaleTransform />
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <TextBox Name="textBox17" Margin="5 0 0 0" Text="{x:Bind rectangle2.(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX), Mode=TwoWay}" />
    
            </StackPanel>
        </Grid>
    </Page>

    Bind/Tips.xaml.cs

    /*
     * 用于演示使用绑定过程中的一些技巧
     *
     * 在这里插一句:
     * 在 xaml 使用的 {Binding}, {x:Bind}, {StaticResource} 之类的这种带大括号的语法被称为标记扩展(Markup Extension),在 uwp 中无法开发自定义标记扩展(但是在 wpf 中是可以的)
     */
    
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Data;
    using Windows10.Common;
    
    namespace Windows10.Bind
    {
        public sealed partial class Tips : Page
        {
            public Tips()
            {
                this.InitializeComponent();
    
                this.Loaded += Tips_Loaded;
            }
    
            private void Tips_Loaded(object sender, RoutedEventArgs e)
            {
                BindingAttachedProperty();
            }
    
            // 在 CodeBehind 端绑定附加属性
            private void BindingAttachedProperty()
            {
                Binding binding = new Binding()
                {
                    Path = new PropertyPath("(Grid.Row)"), // 注意要有括号,另外在 CodeBehind 端绑定自定义附加属性暂时没有成功
                    Source = textBox3
                };
                BindingOperations.SetBinding(textBox3, TextBox.TextProperty, binding);
            }
    
            // 通过 x:Bind 绑定时,要做转换
            public object CurrentEmployee { get; set; } = new Employee() { Name = "wanglei", Age = 36, IsMale = true };
    
            public string MyName { get; set; } = "webabcd";
        }
    
    
    
        /// <summary>
        /// 用于附加属性的演示
        /// </summary>
        public class MyAttachedProperty
        {
            // 获取附加属性
            public static string GetSubTitle(DependencyObject obj)
            {
                return (string)obj.GetValue(SubTitleProperty);
            }
    
            // 设置附加属性
            public static void SetSubTitle(DependencyObject obj, string value)
            {
                obj.SetValue(SubTitleProperty, value);
            }
    
            // 注册一个附加属性
            public static readonly DependencyProperty SubTitleProperty =
                DependencyProperty.RegisterAttached(
                    "SubTitle", // 附加属性的名称
                    typeof(string), // 附加属性的数据类型
                    typeof(MyAttachedProperty), // 附加属性所属的类
                    new PropertyMetadata("", PropertyMetadataCallback)); // 指定附加属性的默认值,以及值发生改变时所调用的方法
    
            private static void PropertyMetadataCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
            {
                object newValue = args.NewValue; // 发生改变之后的值
                object oldValue = args.OldValue; // 发生改变之前的值
            }
        }
    }



    OK
    [源码下载]

  • 相关阅读:
    STM32使用定时器实现输入捕获
    Leetcode#101 Symmetric Tree
    Leetcode#100 Same Tree
    Leetcode#26 Remove Duplicates from Sorted Array
    Leetcode#27 Remove Element
    Leetcode#83 Remove Duplicates from Sorted List
    Leetcode#70 Climbing Stairs
    Leetcode#66 Plus One
    Leetcode#36 Valid Sudoku
    Leetcode#67 Add Binary
  • 原文地址:https://www.cnblogs.com/webabcd/p/5648722.html
Copyright © 2011-2022 走看看