WPF 数据绑定 定制一个集合的视图 数据提供程序

XmlDataProvider

提供了一种简单的方式绑定到一段XML,无论这段XML在内存中的片段或一个完成文件中。

<Page.Resources>
    <XmlDataProvider x:Key="xmlData" XPath="Images">
        <!-- 数据岛包含在x:XData标记中 -->
        <x:XData>
            <!-- XML 数据岛 -->
            <!-- 用空xmlns标记XML根节点,否则会被默认命名空间影响,XPath查询无法工作 -->
            <Images xmlns="">
                <Image ID="1">
                    <Name>a.jpg</Name>
                    <Image ID="3">
                        <Name>c.jpg</Name>
                    </Image>
                </Image>
                <Image ID="2">
                    <Name>b.jpg</Name>
                </Image>
            </Images>
        </x:XData>
    </XmlDataProvider>
        
    <!-- XML文件位于一个独立文件中 -->
    <XmlDataProvider x:Key="xmlData2" XPath="Images" Source="Images.xml" />
        
    <!-- 将整个XML数据绑定到一个可以理解层次结构TreeView或Menu的元素上 -->
    <!-- 绑定XML的根节点Images样式模板 -->
    <!-- 未定义显示x:Key,因为默认以DataType值做了资源键名 -->
    <!-- DataType对应XML元素名称 -->
    <HierarchicalDataTemplate DataType="Images" ItemsSource="{Binding XPath=*}">
        <TextBlock Text="All Images" Background="DeepPink"/>
    </HierarchicalDataTemplate>
    <!-- 绑定XML的子节点Image样式模板 -->
    <HierarchicalDataTemplate DataType="Image" ItemsSource="{Binding XPath=*}">
        <TextBlock FontWeight="Bold" Text="{Binding XPath=.}"/>
    </HierarchicalDataTemplate>
    <!-- 绑定XML元素Image的子节点Name样式模板 -->
    <DataTemplate DataType="Name">
        <TextBlock Foreground="CornflowerBlue" Text="{Binding XPath=.}"/>
    </DataTemplate>
</Page.Resources>
    
<StackPanel>
    <ListBox ItemsSource="{Binding Source={StaticResource xmlData2}, XPath=Image/Name}"/>
        
    <TreeView ItemsSource="{Binding Source={StaticResource xmlData},XPath=.}"/>

    <Menu ItemsSource="{Binding Source={StaticResource xmlData},XPath=.}" />
</StackPanel>


ObjectDataProvider

可以提供一个.Net对象为数据源,提供附加能力:

1.声明式的使用带参构造函数实例化对象

<Page x:Class="WPF_Test.Page4"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:sys="clr-namespace:System;assembly=mscorlib"
      xmlns:local="clr-namespace:WPF_Test"
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
	Title="Page4">
    
    <Page.Resources>
        <!-- ObjectDataProvider star -->
        <local:PhotoList x:Key="photos"/>
        <ObjectDataProvider x:Key="ObjectProvider" ObjectInstance="{StaticResource photos}" />
        <ObjectDataProvider x:Key="ObjectProvider_2" ObjectType="{x:Type local:PhotoList}">
            <!-- 用带一个参数的构造函数实例化PhotoList对象 -->
            <ObjectDataProvider.ConstructorParameters>
                <sys:Int32>2</sys:Int32>
            </ObjectDataProvider.ConstructorParameters>
        </ObjectDataProvider>
        <!-- ObjectDataProvider end -->
    </Page.Resources>
    
    <StackPanel>
        <ListBox SelectedValuePath="ID" DisplayMemberPath="Name" ItemsSource="{Binding Source={StaticResource ObjectProvider_2}}"/>
    </StackPanel>
</Page>
//PhotoList pl = Resources["photos"] as PhotoList;
PhotoList pl = ((ObjectDataProvider)Resources["ObjectProvider_2"]).Data as PhotoList;
pl.Add(new PhotoModel("lulu", "66" + pl.Value.ToString(), 4, DateTime.Now));

2.绑定到源对象的一个方法

<Page.Resources>
    <!-- 绑定一个静态方法 -->
    <ObjectDataProvider x:Key="ObjectProvider" ObjectType="{x:Type local:PhotoList}" MethodName="GetValue">
        <ObjectDataProvider.MethodParameters>
            <sys:String>lulu</sys:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Page.Resources>
    
<StackPanel>
    <TextBlock Text="{Binding Source={StaticResource ObjectProvider}}"></TextBlock>
</StackPanel>
namespace WPF_Test
{
    //PhotoList继承ObservableCollection可实现自动跟新绑定值
    class PhotoList : System.Collections.ObjectModel.ObservableCollection<PhotoModel>
    {
        public static string GetValue(string value)
        {
            return value;
        }
    }
}

3.有更多选项做异步数据绑定

 

自定义数据流
Binding支持目标属性直接被用户修改,可以让数据回源。

通过设置Mode属性实现,其值可为:

BindingMode.OneWay:当源改变,目标会跟新

                         TwoWay:源或目标改变,导致另一方面被跟新

                         OneWayToSource:OneWay反向方式,目标改变,源会更新

                          OneTime:同OneWay,但源的改变不会被反映在目标上

注:TextBox.Text无法绑定到集合的Count属性,因为Count属性只读,TextBox.Text默认为TwoWay绑定,需要提供一个可读写属性,需显示修改TextBox绑定模式为OneWay

由于绑定模式的不同,值转换器才有Convert也有ConverBack,当采用TwoWay是,2个方法都有机会调用。
 

当使用了TwoWay或OneWayToSource绑定方式后,可指定何时跟新,如何跟新数据源。

通过Binding的UpdateSourceTrigger属性指定:

UpdateSourceTrigger.PropertyChanged:只要目标属性值改变,源跟新

LostFocus:目标属性值改变后,目标失去焦点,源跟新

Explicit:显示调用BindingExpression.UpdateSource时,源跟新(通过调用Element的GetBindingExpression方法获取)

 

向绑定添加验证规则

跟新数据,会调用验证检查,用规则否决本次跟新后,将数据标记无效。

数据标记无效后,默认会给元素一个新控件模板,显示红色系框。可通过Validation.ErrorTemplate附加属性实现自定义模板。

数据标记无效后,元素Validation.HasError变为true,同时Validation.Error附加事件也会触发(仅当Binding的NotifyOnValidationError设置为true才有效)

<TextBlock Name="txtBlock_1" Text="lulu"></TextBlock>
<TextBox Name="txt_1">
    <TextBox.Text>
        <Binding ElementName="txtBlock_1" Path="Text">
            <Binding.ValidationRules>
                <!-- 自定义验证法则,在文本失去焦点后,数据转换前调用,将不合法数据标记为无效 -->
                <local:JpgValidation />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>
class JpgValidation:ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        string fileName = value.ToString();
        //检查字符串是否以.jpg结束
        if (!fileName.EndsWith(".jpg", StringComparison.InvariantCultureIgnoreCase))
        {
            return new ValidationResult(false, "不为jpg文件");
        }

        return new ValidationResult(true, null);
    }
}


使用不相交源
1.CompositeCollection

提供独立集合或单个集合中的任意项混合。

<Page.Resources>
    <local:PhotoList x:Key="photoList"/>
    <CompositeCollection x:Key="CompositeCollection">
        <!-- 将photoList中的项目作为CompositeCollection的一部分,而非photoList -->
        <!-- 因此CompositeCollection中项总数为2+photoList.Count -->
        <CollectionContainer Collection="{Binding Source={StaticResource photoList}}"/>
        <!-- PhotoModel为含无参构函的类 -->
        <local:PhotoModel/>
        <local:PhotoModel/>
    </CompositeCollection>
</Page.Resources>

<ListBox ItemsSource="{Binding Source={StaticResource CompositeCollection}}" />

2.MultiBinding

允许多个绑定汇集,输出给一个单独目标值。

<Page.Resources>
    <local:PhotoListConverter x:Key="photoListConverter" />
    <local:PhotoModel x:Key="pmodel1"/>
    <local:PhotoModel x:Key="pmodel2"/>
</Page.Resources>

<TextBox>
    <!-- 通过指定转换器,汇合多个绑定值,付给一个元素,设定绑定模式OneWay -->
    <MultiBinding Converter="{StaticResource photoListConverter}" Mode="OneWay">
        <Binding Source="{StaticResource pmodel1}" Path="Name" />
        <Binding Source="{StaticResource pmodel2}" Path="Name" />
    </MultiBinding>
</TextBox>
public class PhotoListConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string total = string.Empty;
        foreach (object value in values)
        {
            total += value.ToString()+",";
        }

        return total.TrimEnd(',');
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

3.PriorityBinding

也封装多个Binding对象,让多个Binding为设置目标而竞争!

如果绑定到一个较慢数据源,在等待时可能需要一个较快的临时数据版本。

<Page.Resources>
    <local:SlowSpeed x:Key="HightPri"/>
    <local:MediumSpeed x:Key="MediumPri"/>
    <local:FastSpeed x:Key="LowPri"/>
</Page.Resources>

<TextBlock>
    <TextBlock.Text>
        <!-- 最后显示结果为SlowSpeed -->
        <PriorityBinding>
            <!-- 优先级最高,操作耗时最多,应设为异步操作,避免UI阻塞 -->
            <Binding Source="{StaticResource HightPri}" Path="Value" IsAsync="True" />
            <!-- 操作耗时较多,应设为异步操作,避免UI阻塞 -->
            <Binding Source="{StaticResource MediumPri}" Path="Value" IsAsync="True" />
            <!-- 优先级最低,操作耗时最少,应设为同步操作 -->
            <Binding Source="{StaticResource LowPri}" Path="Value" />
        </PriorityBinding>
    </TextBlock.Text>
</TextBlock>
public class SlowSpeed
{
    private string _value;

    public string Value
    {
        get { return _value; }
        set { _value = value; }
    }

    public SlowSpeed()
    {
        Thread.Sleep(5000);
        _value = "SlowSpeed";
    }
}

public class MediumSpeed
{
    private string _value;

    public string Value
    {
        get { return _value; }
        set { _value = value; }
    }

    public MediumSpeed()
    {
        Thread.Sleep(1000);
        _value = "MediumSpeed";
    }
}

public class FastSpeed
{
    private string _value;

    public string Value
    {
        get { return _value; }
        set { _value = value; }
    }

    public FastSpeed()
    {
        _value = "FastSpeed";
    }
}

你可能感兴趣的:(WPF 数据绑定 定制一个集合的视图 数据提供程序)