zoukankan      html  css  js  c++  java
  • [WPF] DataTemplate Binding to Interface

    在WPF内可以使用DataTemplate,来辅助完成对对象集合做DataBinding的工作。并且透过DataTemplate的DataType属性,来让对象集合中不同的对象,经过DataBinding之后能有「不同的外观」。简单的范例如下:不同的车辆类型,会依照车辆类型,呈现不同的详细数据。

    namespace BindingInterfaceSample
    {
        public class Car
        {
            public string Name { get; set; }
        }
    
        public class Truck : Car
        {
            public int MaxLoad { get; set; }
        }
    
        public class Roadster : Car
        {
            public int MaxSpeed { get; set; }
        }
    }
    
    <Window x:Class="BindingInterfaceSample.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:clk="clr-namespace:BindingInterfaceSample"
            Title="MainWindow" Height="350" Width="525">
        <ItemsControl >
            <ItemsControl.Items>
                <clk:Truck Name="Truck01" MaxLoad="100" />
                <clk:Truck Name="Truck02" MaxLoad="500" />
                <clk:Roadster Name="Roadster01" MaxSpeed="99" />
            </ItemsControl.Items>
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type clk:Truck}">
                    <WrapPanel>
                        <TextBlock Text="Truck" />
                        <TextBlock Text="{Binding Path=MaxLoad}" />
                    </WrapPanel>
                </DataTemplate>
                <DataTemplate DataType="{x:Type clk:Roadster}">
                    <WrapPanel>
                        <TextBlock Text="Roadster" />
                        <TextBlock Text="{Binding Path=MaxSpeed}" />
                    </WrapPanel>
                </DataTemplate>
            </ItemsControl.Resources>
        </ItemsControl>
    </Window>
    

    反过来说,也可以经由DataTemplate的DataType属性,来让对象集合中不同的对象,经过DataBinding之后能有「相同的外观」。简单的范例如下:只要是车,都只呈现车的数据。

    namespace BindingInterfaceSample
    {
        public class Car
        {
            public string Name { get; set; }
        }
    
        public class Truck : Car
        {
            public int MaxLoad { get; set; }
        }
    
        public class Roadster : Car
        {
            public int MaxSpeed { get; set; }
        }
    }
    
    <Window x:Class="BindingInterfaceSample.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:clk="clr-namespace:BindingInterfaceSample"
            Title="MainWindow" Height="350" Width="525">
        <ItemsControl >
            <ItemsControl.Items>
                <clk:Truck Name="Truck01" MaxLoad="100" />
                <clk:Truck Name="Truck02" MaxLoad="500" />
                <clk:Roadster Name="Roadster01" MaxSpeed="99" />
            </ItemsControl.Items>
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type clk:Car}">
                    <Button Content="{Binding Path=Name}" />
                </DataTemplate>
            </ItemsControl.Resources>
        </ItemsControl>
    </Window>
    

    而在让对象集合中不同的对象,经过DataBinding之后能有「相同的外观」。这个使用情景中,DataTemplate的DataType如果设定为Interface型别,在WPF中会出现意外的执行结果。简单的范例如下:DataType设定为Interface型别,会无法对应DataTemplate。

    namespace BindingInterfaceSample
    {
        public interface ICar
        {
            string Name { get; set; }
        }
    
        public class Truck : ICar
        {
            public string Name { get; set; }
    
            public int MaxLoad { get; set; }        
        }
    
        public class Roadster : ICar
        {
            public string Name { get; set; }
    
            public int MaxSpeed { get; set; }
        }
    }
    
    <Window x:Class="BindingInterfaceSample.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:clk="clr-namespace:BindingInterfaceSample"
            Title="MainWindow" Height="350" Width="525">
        <ItemsControl >
            <ItemsControl.Items>
                <clk:Truck Name="Truck01" MaxLoad="100" />
                <clk:Truck Name="Truck02" MaxLoad="500" />
                <clk:Roadster Name="Roadster01" MaxSpeed="99" />
            </ItemsControl.Items>
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type clk:ICar}">
                    <Button Content="{Binding Path=Name}" />
                </DataTemplate>
            </ItemsControl.Resources>
        </ItemsControl>
    </Window>
    

    遇到必须设定DataTemplate的DataType为Interface型别的情景。解决的方法很简单:只要改写数据系结容器使用的DataTemplateSelector,增加以Interface型别做索引,查询Resource里的DataTemplate,再用这个DataTemplate来做DataBinding。简单的范例如下:只要是有实做车接口,都只呈现车的数据。

    namespace BindingInterfaceSample
    {
        public interface ICar
        {
            string Name { get; set; }
        }
    
        public class Truck : ICar
        {
            public string Name { get; set; }
    
            public int MaxLoad { get; set; }
        }
    
        public class Roadster : ICar
        {
            public string Name { get; set; }
    
            public int MaxSpeed { get; set; }
        }
    }
    
    <Window x:Class="BindingInterfaceSample.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:clk="clr-namespace:BindingInterfaceSample"
            Title="MainWindow" Height="350" Width="525">
        <ItemsControl>
            <ItemsControl.Items>
                <clk:Truck Name="Truck01" MaxLoad="100" />
                <clk:Truck Name="Truck02" MaxLoad="500" />
                <clk:Roadster Name="Roadster01" MaxSpeed="99" />
            </ItemsControl.Items>        
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type clk:ICar}">
                    <Button Content="{Binding Path=Name}" />
                </DataTemplate>
            </ItemsControl.Resources>
            <ItemsControl.ItemTemplateSelector>
                <clk:StandardDataTemplateSelector />
            </ItemsControl.ItemTemplateSelector>
        </ItemsControl>
    </Window>
    
    namespace BindingInterfaceSample
    {
        public class StandardDataTemplateSelector : DataTemplateSelector
        {
            // Methods
            public override DataTemplate SelectTemplate(object item, DependencyObject container)
            {
                #region Require
    
                if (item == null) throw new ArgumentNullException();
                if (container == null) throw new ArgumentNullException();
    
                #endregion
    
                // Result
                DataTemplate itemDataTemplate = null;
    
                // Base DataTemplate
                itemDataTemplate = base.SelectTemplate(item, container);
                if (itemDataTemplate != null) return itemDataTemplate;
    
                // Interface DataTemplate
                FrameworkElement itemContainer = container as FrameworkElement;
                if (itemContainer == null) return null;
    
                foreach (Type itemInterface in item.GetType().GetInterfaces())
                {
                    itemDataTemplate = itemContainer.TryFindResource(new DataTemplateKey(itemInterface)) as DataTemplate;
                    if (itemDataTemplate != null) break;
                }
    
                // Return
                return itemDataTemplate;
            }
        }
    }
    

    参考数据
    Style、DataTemplate 和隐含索引键
    DataTemplateKey 类别

    范列下载
    BindingInterfaceSample点此下载


  • 相关阅读:
    golang并发
    golang接口
    golang方法
    golang函数
    微信小程序请求封装
    使用vue实现打印功能时出现多余空白页的问题
    mybatis 基本配置
    sql调优
    触发器 索引
    收藏 故事形式讲解javaScript中创建对象和Java创建对象的区别
  • 原文地址:https://www.cnblogs.com/clark159/p/2524559.html
Copyright © 2011-2022 走看看