数据提供者

在大多数的代码中,都是通过设置元素的DataContext属性或者列表控件的ItemsSource属性,从而提供顶级的数据源。当数据对象是通过另一个类构造时,可以有其他选择。

一种是作为窗口的资源定义数据对象。如果能够使用声明的方式构造对象,这种方法工作的很好,但是如果需要在运行时使用数据库等方式获取数据,这种技术就没有意义了。但是会出现部分开发人员采用这种方法,基本思路是在构造函数中获取所需的数据。

<Window.Resources>
    <local:PhotoList x:Key="MyPhotos" />
</Window.Resources> public class Photo
{
    public Photo(string path, string eyeFlag)
        {
            _source = path;             if (!File.Exists(path)) myBmp = null;
            try
            {
                myBmp = new BitmapImage();
                myBmp.BeginInit();
                myBmp.CacheOption = BitmapCacheOption.OnLoad;
                myBmp.StreamSource = new MemoryStream(File.ReadAllBytes(path));
                myBmp.EndInit();
                myBmp.Freeze();
            }
            catch (Exception)
            {
                myBmp = null;
            }             EyeFlag = eyeFlag;
        }     public override string ToString()
        {
            return Source;
        }     private string _source;
    public string Source { get { return _source; } }     private BitmapImage myBmp;
    public BitmapImage MyBmp
        {
            get { return myBmp; }
            set { myBmp = value; }
        }     private string _EyeFlag;
    public string EyeFlag
        {
            get { return _EyeFlag; }
            set
            {
                _EyeFlag = value;
                //this.OnPropertyChanged("EyeFlag");
            }
        }
} public class PhotoList : ObservableCollection<Photo>
{
    public void FilePathAdd(string bmpFile, string eyeFlag = "")
    {
        Add(new Photo(bmpFile, ""));
    }
}

此处的PhotoList类继承自ObservableCollection类,因此他能够存储列表,可以通过方法或者直接在构造函数中填充数据。现在其他元素就可以在他们的绑定中使用这个资源了。

<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

这种方法看起来可以,但是有一定风险。当添加错误处理时,需要将错误处理代码放在PhotoList类中。这种方式将数据模型、数据访问代码以及用户界面代码混合在一起,所以当需要访问外部资源时,这种方法就很不合理了。

数据提供者是这种模型的扩展,可以通过数据提供者直接绑定带在标记的资源部分定义的对象,然而,不是直接绑定到数据对象自身,而是绑定到能够检索或者构建数据对象的数据提供者。如果数据提供者能够在发生异常时引发事件并提供用于配置与其操作相关细节的属性,这种方法就合理。但是WPF的数据提供者还没有达到这个标准,导致不值得使用这种方法。WPF提供了两种数据提供者:

  • ObjectDataProvider,数据提供者通过调用另一个类中的方法获取信息
  • XmlDataProvider,直接从XML文件获取信息

ObjectDataProvider

ObjectDataProvider能够从应用程序的另一个类中获取信息。

  • 能够创建需要的对象并为构造函数传递参数
  • 能够调用所创建对象中的方法,并向他传递方法参数
  • 能够异步创建数据对象(能够窗口加载之前一直等待,之后在后台完成工作)
<Window.Resources>
    <ObjectDataProvider x:Key="MyPhotosProvider" MethodName="GetAll" ObjectType="{x:Type local:PhotoList}">
        <ObjectDataProvider.MethodParameters />
    </ObjectDataProvider>
    <local:PhotoList x:Key="MyPhotos" />
</Window.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
    <ListBox ItemsSource="{Binding Source={StaticResource MyPhotosProvider}}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Grid>
  1. 错误提示

当创建窗口时,XAML创建窗口并调用GetAll()方法,从而设置绑定。如果GetAll()方法返回期望的数据,一切没有问题。如果抛出异常,这事异常从窗口的构造函数中的InitializeComponent();向上传输,显示此窗口的代码就要捕获这个异常,即使在构造函数中捕获这个异常,其余代码也无法正常展示。

  1. 异步支持

只要将IsAsynchronous="True"就可以在后台进程中执行工作。

异步数据绑定

WPF还通过绑定每个对象的IsAsyn属性来提供异步支持。WPF异步地从数据对象检索绑定属性,数据对象自身仍然是同步创建的。一旦创建集合,绑定就会异步地从Phone对象中查询相关属性,这个过程没有什么意义。利用这一属性的唯一方法是构建在属性获取过程中添加耗时逻辑的特殊类,例如,考虑一个绑定到数据模型的分析应用程序。数据对象可能包含一部分信息,使用耗时计算对其进行计算。可使用异步绑定这种属性,并使用同步绑定绑定其他属性,应用程序中的一些信息会立即显示,其他信息会在准备后显示。WPF还提供了绑定优先级,基于异步绑定可以优先绑定一些属性。

XmlDataProvider

XmlDataProvider数据提供者被设计成只读的,不具有提交数据修改的能力,而且不能处理来自其他源的XML数据(数据库记录、Web服务消息等)。如果预见到需要修改XML或者需要将XML数据转换成代码中能够使用的对象形式,最好使用XML扩展支持。如果数据是以XML形式存储,然后由页面支持展示,那么XmlDataProvider是最合理的选择。

数据转换

WPF提供了2种工具,可以进行数据转换:

  • 字符串格式化:可以设置Binding的StringFormat属性对文本形式的数据进行转换(例如包含日期和数字的字符串)
  • 值转换器:功能强大,使用该功能可以将任意类型的数据源转换为任意类型的对象表示,然后传递到关联的控件

字符串转换器

具体形式为{0:C}。其中0代表第一个数值,C表示希望的数据格式。完整的格式是 {}{0:C},代码如下:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="{Binding Date, StringFormat={}{0:F}}"/>
    <TextBlock Text="{Binding Date, StringFormat=当前日期:{0:F}}"/>
</StackPanel>

值转换器简介

值转换器负责在目标中显示数据之前转换源数据,并且对于双向绑定在将数据应用回源之前转换新的目标值。使用方式如下:

  • 将数据格式化为字符串表示形式。例如将数字转换成货币字符串
  • 创建特定类型的WPF对象。读取二进制数据并将其转换成BitmapImage对象,绑定到Image控件
  • 根据绑定数据有条件地改变元素中的属性。
  1. 使用值转换器设置字符串的格式

创建值转换器,主要有4个步骤:

  • 创建一个实现了IValueConverter接口的类
  • 为该类声明添加ValueConversion特性,并制定目标数据类型(可选)
  • 实现Convert方法,将原来的格式转换为显示的格式
  • 实现ConvertBack方法,该方法实现反向变换,将值从显示格式转换为原格式

public class EyeTypeForegroundConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Brush output = ResourceHelper.GetResource<Brush>("PrimaryReverseTextBrush");
        //Brush output = (Brush)Application.Current.Resources["PrimaryReverseTextBrush"];         if (value != null && value != DependencyProperty.UnsetValue && parameter != null && parameter != DependencyProperty.UnsetValue)
        {
            int param = System.Convert.ToInt32(parameter);
            int eyeType = System.Convert.ToInt32(value);             if (param == eyeType) output = ResourceHelper.GetResource<Brush>("InfoBrush");
        }         return output;
    }     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
  1. 使用值转换器创建对象

最典型的应用就是从二进制数据转换BitmapImage对象,用于Image控件展示图像

public class Path2BitmapImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return null;         if (value is string imagePath)
        {
            //return imagePath;
            return ImageShareHelper.File2BitmapImage(imagePath);
        }
        return null;
    }     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
} public static BitmapImage File2BitmapImage(string path)
{
    if (!string.IsNullOrEmpty(path) && File.Exists(path) && (Path.GetExtension(path).Equals(".bmp") || Path.GetExtension(path).Equals(".jpeg") || Path.GetExtension(path).Equals(".jpg") || Path.GetExtension(path).Equals(".png")))
    {
        BitmapImage bitmap = new BitmapImage();
        bitmap.BeginInit();
        bitmap.CacheOption = BitmapCacheOption.OnLoad;
        bitmap.StreamSource = new MemoryStream(File.ReadAllBytes(path));
        bitmap.EndInit();
        bitmap.Freeze();
        return bitmap;
    }
    else
    {
        return null;
    }
}
  1. 应用条件格式化

有些转换器不是为了显示格式化的数据,而是根据不同条件展示不同数据

public class DtoShowStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null) return null;             string output = null;             {
                if (value is DateTime input)
                {
                    if (parameter == null)
                    {
                        output = input.ToString();
                    }
                    else//, ConverterParameter=date, 此处获得是字符串类型
                    {
                        var param = parameter.ToString();
                        output = input.ToShortDateString();
                    }
                }
            }
            {
                if (value is SexType input)
                {
                    switch (input)
                    {
                        case SexType.Female:
                            output = Properties.Langs.Lang.SexFemale;
                            break;
                        case SexType.Male:
                            output = Properties.Langs.Lang.SexMale;
                            break;
                        case SexType.Null:
                            output = Properties.Langs.Lang.SexNull;
                            break;
                        default:
                            break;
                    }
                }
            }
            {
                if (value is ExamFileType input)
                {
                    switch (input)
                    {
                        case ExamFileType.Jpg:
                            output = Properties.Langs.Lang.ExamFileTypeJpg;
                            break;
                        case ExamFileType.Avi:
                            output = Properties.Langs.Lang.ExamFileTypeAvi;
                            break;
                        case ExamFileType.Data:
                            output = Properties.Langs.Lang.ExamFileTypeData;
                            break;
                        default:
                            break;
                    }
                }
            }
            {
                if (value is EyeType input)
                {
                    switch (input)
                    {
                        case EyeType.Right:
                            output = Properties.Langs.Lang.EyeTypeRight;
                            break;
                        case EyeType.Left:
                            output = Properties.Langs.Lang.EyeTypeLeft;
                            break;
                        case EyeType.Both:
                            output = Properties.Langs.Lang.EyeTypeBoth;
                            break;
                        case EyeType.Unknown:
                            output = Properties.Langs.Lang.EyeTypeUnknown;
                            break;
                        default:
                            break;
                    }
                }
            }
            {
                if (value is ExamType input)
                {
                    switch (input)
                    {
                        case ExamType.SW8800:
                            output = Properties.Langs.Lang.ExamTypeSW8800;
                            break;
                        case ExamType.SW8000:
                            output = Properties.Langs.Lang.ExamTypeSW8000;
                            break;
                        case ExamType.SW6000D:
                            output = Properties.Langs.Lang.ExamTypeSW6000D;
                            break;
                        case ExamType.SW6000:
                            output = Properties.Langs.Lang.ExamTypeSW6000;
                            break;
                        case ExamType.SW9000:
                            output = Properties.Langs.Lang.ExamTypeSW9000;
                            break;
                        case ExamType.SW7000:
                            output = Properties.Langs.Lang.ExamTypeSW7000;
                            break;
                        case ExamType.SW6000A:
                            output = Properties.Langs.Lang.ExamTypeSW6000A;
                            break;
                        case ExamType.SW9800:
                            output = Properties.Langs.Lang.ExamTypeSW9800;
                            break;
                        case ExamType.SW4000:
                            output = Properties.Langs.Lang.ExamTypeSW4000;
                            break;
                        case ExamType.SW4000T:
                            output = Properties.Langs.Lang.ExamTypeSW4000A;
                            break;
                        case ExamType.SW900:
                            output = Properties.Langs.Lang.ExamTypeSW900;
                            break;
                        case ExamType.SW8800T:
                            output = Properties.Langs.Lang.ExamTypeSW8800T;
                            break;
                        case ExamType.SW9600:
                            output = Properties.Langs.Lang.ExamTypeSW9600;
                            break;
                        default:
                            break;
                    }
                }
            }
            {
                if (value is RoleType input)
                {
                    switch (input)
                    {
                        case RoleType.Admin:
                            output = Properties.Langs.Lang.UserRoleTypeAdmin;
                            break;
                        case RoleType.Company:
                            output = Properties.Langs.Lang.UserRoleTypeCompany;
                            break;
                        case RoleType.Doctor:
                            output = Properties.Langs.Lang.UserRoleTypeDoctor;
                            break;
                        default:
                            break;
                    }
                }
            }
            {
                if (value is LangType input)
                {
                    switch (input)
                    {
                        case LangType.zh:
                            output = Properties.Langs.Lang.LanguageZh;
                            break;
                        case LangType.en:
                            output = Properties.Langs.Lang.LanguageEn;
                            break;
                        case LangType.fa:
                            output = Properties.Langs.Lang.LanguageFa;
                            break;
                        case LangType.fr:
                            output = Properties.Langs.Lang.LanguageFr;
                            break;
                        default:
                            break;
                    }
                }
            }
            {
                if (value is IOLFormulaType input)
                {
                    switch (input)
                    {
                        case IOLFormulaType.SRKII:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaSRKII;
                            break;
                        case IOLFormulaType.SRKT:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaSRKT;
                            break;
                        case IOLFormulaType.Holladay:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaHolladay;
                            break;
                        case IOLFormulaType.BinkhorstII:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaBinkhorstII;
                            break;
                        case IOLFormulaType.HofferQ:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaHofferQ;
                            break;
                        case IOLFormulaType.Haigis:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaHaigis;
                            break;
                        case IOLFormulaType.HaigisL:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaHaigisL;
                            break;
                        case IOLFormulaType.ShammasPL:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaShammas;
                            break;
                        case IOLFormulaType.Masket:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaMasket;
                            break;
                        case IOLFormulaType.ModifiedMasket:
                            output = Properties.Langs.Lang.DeviceIolMasterIOLFormulaModifiedMasket;
                            break;
                        default:
                            break;
                    }
                }
            }
            {
                if (value is double input)
                {
                    if (parameter != null && parameter is string digits)
                    {
                        double roundDouble = (double)Math.Round((decimal)input, System.Convert.ToInt32(digits), MidpointRounding.AwayFromZero);
                        output = roundDouble.ToString(string.Format("f{0}", System.Convert.ToInt32(digits)));
                    }
                    else
                    {
                        output = input.ToString();
                    }
                }
            }
            return output;
        }     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
  1. 评估多个属性

到目前为止,已经使用绑定表达式将一部分源数据转换成单个格式化的结果。也可以创建能够评估或者结合多个源属性信息的绑定

/// <summary>
/// 多绑定 有一个为true 则显示,否则隐藏,参数为0时,逻辑翻转
/// </summary>
public class MultiOrEqualVisibleConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        Visibility output = Visibility.Collapsed;         if (values != null && values.Count() > 0)
        {
            {
                bool param = true;
                if (parameter != null)
                {
                    param = System.Convert.ToBoolean(parameter);
                }
                var count = values.Where(p => p != DependencyProperty.UnsetValue && p != null && System.Convert.ToBoolean(p)).Count();
                if (count == 0)
                {
                    output = param ? Visibility.Collapsed : Visibility.Visible;
                }
                else
                {
                    output = param ? Visibility.Visible : Visibility.Collapsed;
                }
            }
        }
        return output;
    }     public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

WPF进阶技巧和实战08-依赖属性与绑定03的更多相关文章

  1. WPF进阶技巧和实战08-依赖属性与绑定01

    依赖项属性 定义依赖项属性 注意:只能为依赖对象(继承自DependencyObject的类)添加依赖项属性.WPF中的元素基本上都继承自DependencyObject类. 静态字段 名称约定(属性 ...

  2. WPF进阶技巧和实战08-依赖属性与绑定02

    将元素绑定在一起 数据绑定最简单的形式是:源对象是WPF元素而且源属性是依赖项属性.依赖项属性内置了更改通知支持,当源对象中改变依赖项属性时,会立即更新目标对象的绑定属性. 元素绑定到元素也是经常使用 ...

  3. WPF进阶技巧和实战03-控件(3-文本控件及列表控件)

    系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...

  4. WPF进阶技巧和实战03-控件(4-基于范围的控件及日期控件)

    系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...

  5. WPF进阶技巧和实战09-事件(1-路由事件、鼠标键盘输入)

    理解路由事件 当有意义的事情发生时,有对象(WPF的元素)发送的用于通知代码的消息,就是事件的核心思想.WPF通过事件路由的概念增强了.NET事件模型.事件由允许源自某个元素的事件由另一个元素引发.例 ...

  6. WPF进阶技巧和实战03-控件(5-列表、树、网格04)

    ListView控件 ListView继承自简单的没有特色的ListBox,增加了对基于列显示的支持,并增加了快速切换视图或显示模式的能力,而不需要重新绑定数据以重新构建列表. ListView类继承 ...

  7. WPF进阶技巧和实战07--自定义元素01

    完善和扩展标准控件的方法: 样式:可使用样式方便地重用控件属性的集合,甚至可以使用触发器应用效果 内容控件:所有继承自ContentControl类的控件都支持嵌套的内容.使用内容控件,可以快速创建聚 ...

  8. WPF进阶技巧和实战03-控件(5-列表、树、网格01)

    列表控件 ItemsControl为列表项控件定义了基本功能,下图是ItemsControl的继承关系: 在继承自ItemsControl类的层次结构中,还显示了项封装器(MenuItem.TreeV ...

  9. WPF进阶技巧和实战09-事件(2-多点触控)

    多点触控输入 多点触控输入和传统的基于比的输入的区别是多点触控识别手势,用户可以移动多根手指以执行常见的操作,放大,旋转,拖动等. 多点触控的输入层次 WPF允许使用键盘和鼠标的高层次输入(例如单击和 ...

随机推荐

  1. 在linux查询本机的公网IP

    linux服务器查看公网IP信息的方法 最近在解决网络问题时,需要查看本机的出口公网IP信息,所以在网络上搜索和请求运维达人,获得如下两个方法: curl ifconfig.me 在linux系统中输 ...

  2. 编译执行 VS 解释执行

    一般编译程序从对源程序执行途径的角度不同,可分为解释执行和编译执行. 所谓解释执行是借助于解释程序完成,即按源程序语句运行时的动态结构,直接逐句地边分析边翻译并执行.像自然语言翻译中的口译,随时进行翻 ...

  3. 在PHP中操作临时文件

    关于文件相关的操作,想必大家已经非常了解了,在将来我们刷到手册中相关的文件操作函数时也会进行详细的讲解.今天,我们先来了解一下在 PHP 中关于临时文件相关的一些内容. 获取 PHP 的默认临时创建文 ...

  4. 解决IE浏览器 点击子元素重复调用执行 mouseover 与mouseout兼容性问题

    将函数配对换为下面2个就可以解决兼容性问题. mouseenter() mouseleave(0

  5. 解决下载的css样式文件在同一排的问题

    一.将样式文件里的所有内容复制到word里 Ctrl+F查找替换,将所有分号;替换成;^p 小提示:在word里^p表示回车 二.将央视文件里的所有反括号}进行替换替换成}^p然后将代码整个粘贴回样式 ...

  6. Java基础系列(7)- 标识符和关键字

    关键字 标识符 Java所有的组成部分都需要名字.类名.变量名.方法名都称为标识符 首字母以字母(A-Z或者a-z),美元符号($),或者下划线(_)开头 首字母之后可以用字母.美元符号.下划线.数字 ...

  7. Groovy系列(1)- Groovy简述

    Groovy简述 前言 由于性能测试的JSR223 Sampler取样器需要用到 Groovy 语言,这两天对其进行了粗略的学习,本文是对学习做的一个简单总结,主要内容参考于官方文档(Groovy 的 ...

  8. 再谈OAuth授权

    工作场景流程 大家都知道OAuth是用于第三方授权的,当你用其他的APP想访问微信账号的昵称.粉丝.联系人等信息,这里就需要微信进行授权,此时在APP的网页端是可以发现有微信登录的,点开会出现弹框,在 ...

  9. python学习笔记(一)-基础知识

    O.解释型语言和编译型语言 编译型语言就是先把写好的程序翻译成计算机语言然后执行,就是所谓的一次编译到处运行,比如c.c++就是编译型语言,这样的语言特点是运行速度快,但是需要事先把程序编译好才可以. ...

  10. 如何使用jemeter进行性能测试

    下载链接:http://jmeter.apache.org/download_jmeter.cgi 一:如何使用jemeter进行压测 1)稳定性测试就需要长时间运行,其运行时间1天.2天.一周等 2 ...