Windows 10 开发日记(五)-- 当Binding遇到异步 -- 解决方案


前文再续,上一章提出了问题,本章提出了三种解决方案:

 

解决方案一:手动进行异步转换,核心思想:将binding做的事情放入CodeBehind

 

FilterItemControl.XAML:

    <Grid><Image x:Name="FilterImage" Stretch="UniformToFill"/><Grid VerticalAlignment="Bottom" Height="20"><TextBlock x:Name="FilterName" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/></Grid><Border x:Name="border" BorderBrush="White" BorderThickness="1" d:LayoutOverrides="LeftPosition, RightPosition, TopPosition, BottomPosition" Margin="1" Visibility="Collapsed"/></Grid>

  

FilterItemControl.cs

 /// <summary>/// 设置数据源/// </summary>/// <param name="filter"></param>public async void SetSource(Filter filter){if (filter != null){_filter = filter;// 使用WriteableBitmap有一个不好的点:必须要知道图片的大小WriteableBitmap result = new WriteableBitmap(768, 1280);var wbData = await MyFilterSDK.ProcessFilterAsync(filter);if(wbData != null){using (var bmpStream = result.PixelBuffer.AsStream()){bmpStream.Seek(0, SeekOrigin.Begin);bmpStream.Write(wbData, 0, (int)bmpStream.Length);}FilterImage.Source = result;}FilterName.Text = filter.FilterName;}}

为其设置数据源, FilterItemsControl.cs

/// <summary>/// 数据源发生变化/// </summary>/// <param name="filters">滤镜列表</param>private void OnItemsSourceChanged(List<Filter> filters){if(filters != null){Container.Children.Clear();foreach(var filter in filters){FilterItemControl itemcontrol = new FilterItemControl();itemcontrol.Width = ITEMWIDTH;itemcontrol.Height = ITEMHEIGHT;// 将binding中做的事情放到代码中!itemcontrol.SetSource(filter);
itemcontrol.ItemSelected += Itemcontrol_ItemSelected;itemcontrol.ItemDoubleClicked += Itemcontrol_ItemDoubleClicked;Container.Children.Add(itemcontrol);}}}

  优点:方便简单

      缺点:XAML必须写死,没有扩展性,如果同样的数据变换一种显示方式,需要重写一个控件。

 

解决方案二:使用异步属性,核心思想,使用Binding和异步加载

 

FilterItemControl.xaml

    <Grid><Image x:Name="FilterImage" Stretch="UniformToFill" Source="{Binding WBAsyncProperty.AsyncValue, Converter={StaticResource imagConverter}}"/><Grid VerticalAlignment="Bottom" Height="20"><TextBlock x:Name="FilterName" TextWrapping="Wrap" Text="{Binding FilterName}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/></Grid><Border x:Name="border" BorderBrush="White" BorderThickness="1" d:LayoutOverrides="LeftPosition, RightPosition, TopPosition, BottomPosition" Margin="1" Visibility="Collapsed"/></Grid>

FilterItemControl.cs不需要额外的东西,但是Model层的数据源需要增加一个异步属性用于被View层绑定

Filter.cs

        private AsyncProperty<byte[]> _wbAsyncProperty; // 异步属性public AsyncProperty<byte[]> WBAsyncProperty{get{return _wbAsyncProperty;}set{SetProperty(ref _wbAsyncProperty, value);}} 

     // 初始化public Filter(){WBAsyncProperty = new AsyncProperty<byte[]>(async () =>{var result = await MyFilterSDK.ProcessFilterAsync(this);return result;});}

  

由于返回值是byte[]类型,所以我们在binding时,必须要进行一次转换,将其转换为WriteableBitmap:BytesToImageConverter.cs

public class BytesToImageConverter : IValueConverter{public object Convert(object value, Type targetType, object parameter, string language){// 使用WriteableBitmap有一个不好的点:必须要知道图片的大小WriteableBitmap result = new WriteableBitmap(768, 1280);var filterData = value as byte[];if (filterData != null){#region  WriteableBitmap方案using (var bmpStream = result.PixelBuffer.AsStream()){bmpStream.Seek(0, SeekOrigin.Begin);bmpStream.Write(filterData, 0, (int)bmpStream.Length);return result;}#endregion}elsereturn null;}public object ConvertBack(object value, Type targetType, object parameter, string language){throw new NotImplementedException();}}

  关于如何实现AsyncProperty和其工作原理在这里不做深究,在这里总结一下这个方案的优缺点:

优点:使用Binding,UI上不会卡顿,图片获取完之后会显示在UI上

缺点: 1. 控件重用性不高

        2. SDK必须与UI无关,这也是为什么返回byte[],而不是直接返回WrieableBitmap的原因,与AsyncProperty的实现技术有关

        3. 因为原因2,必须实现转换器

 

解决方案三:使用DataTemplate,核心思想:将DataTemplate转换放到CodeBehind

 FilterItemControl.XAML需要改变,这里只需要一个ContentPresenter接收内容

   <Grid>  
<ContentPresenter x:Name="Presenter"/><Border x:Name="border" BorderBrush="White" BorderThickness="1" d:LayoutOverrides="LeftPosition, RightPosition, TopPosition, BottomPosition" Margin="1" Visibility="Collapsed"/></Grid>

FilterItemControl.cs需要增加一个ContentTemplate,用于获取应用在这个控件上的模板,并且根据模板把UI显示出来:

   public DataTemplate ContentDataTemplate{get { return (DataTemplate)GetValue(ContentDataTemplateProperty); }set { SetValue(ContentDataTemplateProperty, value); }}public static readonly DependencyProperty ContentDataTemplateProperty =DependencyProperty.Register("ContentDataTemplate", typeof(DataTemplate), typeof(FilterItemControl3), new PropertyMetadata(null,OnContentDataTemplateChanged));private static void OnContentDataTemplateChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args){FilterItemControl3 owner = sender as FilterItemControl3;owner.OnContentDataTemplateChanged(args.NewValue as DataTemplate);}private async void OnContentDataTemplateChanged(DataTemplate newDataTemplate){UIElement rootElement = newDataTemplate.LoadContent() as UIElement;if(rootElement != null){Image img = VisualTreeExtensions.FindFirstElementInVisualTree<Image>(rootElement);if (img != null){#region 使用SDK 处理WriteableBitmap result = new WriteableBitmap(768, 1280);var wbData = await MyFilterSDK.ProcessFilterAsync(this.DataContext as Filter);if (wbData != null){using (var bmpStream = result.PixelBuffer.AsStream()){bmpStream.Seek(0, SeekOrigin.Begin);bmpStream.Write(wbData, 0, (int)bmpStream.Length);}img.Source = result;}#endregion// 改变了图片之后,需要将其加入到可视化中以显示,如果不加这一步你可以想象会出现什么情况Presenter.Content = rootElement;}}}

同样的,需要修改FilterItemsControl.cs,增加一个ItemDataTemplate传递给FilterItemControl:

        /// <summary>/// 子项的模板/// </summary>public DataTemplate ItemDataTemplate{get { return (DataTemplate)GetValue(ItemDataTemplateProperty); }set { SetValue(ItemDataTemplateProperty, value); }}public static readonly DependencyProperty ItemDataTemplateProperty =DependencyProperty.Register("ItemDataTemplate", typeof(DataTemplate), typeof(FilterItemsControl3), new PropertyMetadata(0));/// <summary>/// 数据源发生变化/// </summary>/// <param name="filters">滤镜列表</param>private void OnItemsSourceChanged(List<Filter> filters){if (filters != null){Container.Children.Clear();foreach (var filter in filters){FilterItemControl3 itemcontrol = new FilterItemControl3();//itemcontrol.Width = ITEMWIDTH; // 不要了,在DataTemplate中指定//itemcontrol.Height = ITEMHEIGHT;//1. 设置DataContextitemcontrol.DataContext = filter;//2. 设置模板itemcontrol.ContentDataTemplate = ItemDataTemplate;itemcontrol.ItemSelected += Itemcontrol_ItemSelected;itemcontrol.ItemDoubleClicked += Itemcontrol_ItemDoubleClicked;Container.Children.Add(itemcontrol);}}}

那么我们只需要在使用这个控件的地方编写一个ItemDataTemplate就可以了:

<local:FilterItemsControl3 x:Name="FilterItemsUserControl" Opacity="0" RenderTransformOrigin="0.5,0.5" Margin="0"><local:FilterItemsControl3.RenderTransform><CompositeTransform TranslateY="100"/></local:FilterItemsControl3.RenderTransform><local:FilterItemsControl3.ItemDataTemplate><DataTemplate><Grid Width="80" Height="80"><Image x:Name="SourceImage"/><Grid Height="20" VerticalAlignment="Top" Background="#7F000000"><TextBlock x:Name="textBlock" TextWrapping="Wrap" Text="{Binding FilterName}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/></Grid></Grid></DataTemplate></local:FilterItemsControl3.ItemDataTemplate></local:FilterItemsControl3>

 第三种方案是我想表达的,但是我们看出来,它也并不是最优的,需要在代码中取出DataTemplate中的可视元素,然后将SDK处理过的图片放到目标Image控件的Source中去,但是他的优点也是有的: 1. UI的可扩展性

                             2. 与异步无关的属性可以通过Binding展示

可以说,方案三模拟了DataTemplate如何应用在一个控件上的,这也是我想从这个例子中总结的东西:

1. DataTemplate的作用

2. 控件在应用了DataTemplate之后发生了什么?

3. 通过DataTemplate.LoadContent(), 获取控件,并且修改控件,如果不使用Presenter.Content = rootElement, 为什么没有反应?

 

总结:

1. 首先DataTemplate的MSDN的解释非常清楚,就是将“数据"转换为可见的元素,这也是为什么我们选择DataTemplate来展示Filter的原因。

2. 控件在应用了DataTemplate之后会发生什么?因为微软的封闭,我们看不到,但是可以猜到,它的实现类似于我们方案三的实现:取得DataTemplate中的元素,并且将其加载到可视化树中显示。我们在XAML中写的DataTemplate类似于一个类的声明,当某个控件需要这个DataTemplate时,会new 一个实例,然后目标控件,并且替换它之前的可视化树。

3. 第三个问题的答案基于第二个问题:通过DataTemplate.LoadContent()获得的UIElement每次都是不一样的,就是说调用该方法就类似与调用 new DataTemplate(),一样,只是一次实例化,此时的元素并没有加载到可视化树中(可以通过GetHashCode()对比),所以,无论做什么修改,你都看不出结果。所以必须要有Presenter.Content = rootElement这关键的一步。

 

Demo已经写好,VS2015工程,WU框架,PC运行。

MyFilterDemo.rar

转载于:https://www.cnblogs.com/DinoWu/p/4549770.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/258812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fseek

int fseek( FILE *stream, long offset, int origin );第一个参数stream为文件指针第二个参数offset为偏移量&#xff0c;正数表示正向偏移&#xff0c;负数表示负向偏移第三个参数origin设定从文件的哪里开始偏移,可能取值为&#xff1a;SEEK_CUR、 SEEK_END 或 SEEK_SETSEEK_…

static_cast, dynamic_cast, const_cast探讨【转】

首先回顾一下C类型转换&#xff1a; C类型转换分为&#xff1a;隐式类型转换和显式类型转换 第1部分. 隐式类型转换又称为“标准转换”&#xff0c;包括以下几种情况&#xff1a;1) 算术转换(Arithmetic conversion) : 在混合类型的算术表达式中, 最宽的数据类型成为目标转换类…

RANSAC算法注记

今天学习了一下RANSAC随机样本一致性算法&#xff0c;其在图像融合、特征点匹配方面有很强大的应用。网上已经有很多人写了关于这方面的文档&#xff0c;就不再造轮子了。特此罗列出来&#xff0c;以供后续参考。 我的数学之美&#xff08;一&#xff09;——RANSAC算法详解 …

python字典格式_python – 格式self,这是一个字典

在这种情况下如何使格式(自我)工作&#xff1f;class Commit:number Nonesha Nonemessage Noneidentity Nonedef __init__(self, raw, number):r raw.commits[number]self.number numberself.sha r[sha]self.message r[message]self.identity raw.identities[r[identi…

委托的BeginInvoke和EndInvoke

刚刚搞明白了C#的异步调用&#xff0c;写下来&#xff0c;方便后续调用。 异步主要是解决UI假死的问题&#xff0c;而开辟出一个新的线程&#xff0c;处理大数据。 1.既然是委托的调用&#xff0c;那么先定义个委托&#xff1a; public delegate bool CheckUpdateFile(); 2.定义…

PMP 第七章 项目成本管理

估算成本 制定预算 控制成本 1.成本管理计划的内容和目的是什么? 包括对成本进行估算 预算和控制的各过程&#xff0c;从而确保项目在批准的预算内完工。 2.直接成本、间接成本、可变成本、固定成本、质量成本的内容分别是什么?成本估算的工具有哪些? 成本估算工具 1…

您的请求参数与订单信息不一致_[淘客订单检测]淘宝客订单检测接口,淘客订单查询API...

功能1.输入交易的订单编号&#xff0c;即可查询该订单是否为淘宝客订单。有意向请联系卫星weixiaot168。2.查询结果 0:不是淘宝客订单&#xff1b;1:是。3.根据淘宝官方的后台数据&#xff0c;进行检测&#xff0c;数据真实且有效。4.有效防止佣金损失&#xff0c;降低商家补单…

DebugView输出调试信息

在写windows程序时&#xff0c;需要输出一些调试信息&#xff0c;这里介绍一种极其方便的方法。即使用OutputDebugString 在Debug模式下输出调试信息&#xff0c;在Release模式下不输出。 我们可以在VS的集成平台上输出调试信息&#xff0c;也可以使用DebugView来查看调试信息…

Linux上实现ssh免密码登陆远程服务器

0.说明平常使用ssh登陆远程服务器时&#xff0c;都需要使用输入密码&#xff0c;希望可以实现通过密钥登陆而免除输入密码&#xff0c;从而可以为以后实现批量自动部署主机做好准备。环境如下&#xff1a;IP地址操作系统服务器端10.0.0.128/24CentOS 6.5 x86客户端10.0.0.129/2…

【强连通分量+概率】Bzoj2438 杀人游戏

Description 一位冷血的杀手潜入 Na-wiat&#xff0c;并假装成平民。警察希望能在 N 个人里面&#xff0c;查出谁是杀手。 警察能够对每一个人进行查证&#xff0c;假如查证的对象是平民&#xff0c;他会告诉警察&#xff0c;他认识的人&#xff0c; 谁是杀手&#xff0c; 谁是…

serialversionuid的作用_为什么阿里Java规约要求谨慎修改serialVersionUID字段

serialVersionUID简要介绍serialVersionUID是在Java序列化、反序列化对象时起作用的一个字段。Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时&#xff0c;JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进…

fatal error LNK1169: 找到一个或多个多重定义的符号 的解决方案

昨天&#xff0c;尝试一个项目&#xff0c;遇到了如下的问题。先来还原一下&#xff1a; 头文件test.h #pragma once #include <Eigen/Core> #include <iostream>using namespace Eigen; using namespace std;class point2 { public: point2(int x1,int y1):x(x…

常用工具说明--搭建基于rietveld的CodeReview平台(未测试)

为什么要codereview . 整个团队的编码风格是统一的。 . 有高手能对自己的代码指点一二&#xff0c;从而提高编码水平。 . 减少低级错误的出现 . 约束自己写高质量的代码&#xff0c;因为是要给人看的。 我们对codereview的需求 . 很轻松可以发布自己写的代码。 . 很轻松的可以与…

输入的优化

读入整型时&#xff0c;输入优化可以节省不少时间 1 typedef type long long 2 // 这里以long long为例 3 type read() { 4 type x0; int f1; 5 char chgetchar(); 6 while(ch<0||ch>9) {if(ch-) f-1; chgetchar();} 7 while(ch>0&&ch<9) …

python股票分析系统_熬了一晚上,小白用Python写了一个股票提醒系统

码农小马七夕节去相亲了&#xff0c;见了一个不错的姑娘&#xff0c;长的非常甜美&#xff01;聊着聊着很投缘&#xff01;通过介绍人了解到&#xff0c;对方也很满意&#xff5e;&#xff5e;想着自己单身多年的生活就要结束啦&#xff0c;心里满是欢喜&#xff0c;美美哒&…

有关eigen库的一些基本使用方法

目录 介绍安装Demo矩阵、向量初始化C数组和矩阵转换矩阵基础操作点积和叉积转置、伴随、行列式、逆矩阵计算特征值和特征向量解线性方程最小二乘求解稀疏矩阵介绍 Eigen是一个轻量级的矩阵库,除了稀疏矩阵不成熟&#xff08;3.1有较大改进&#xff09;以外,其他的矩阵和向量操作…

汇编程序:将字符串中所有大写字符转为小写

【任务】 编写程序&#xff0c;将数据区中定义的以0作为结束符的一个字符串中所有的大写字符&#xff0c;全部转换为小写。 【参考解答】 assume cs:cseg, ds:dseg, ss:sseg sseg segment stackdw 100h dup (?) sseg ends dseg segmentdb YanTai123University, 0 d…

从零开始编写自己的C#框架(1)——前言

记得十五年前自学编程时&#xff0c;拿着C语言厚厚的书&#xff0c;想要上机都不知道要用什么编译器来执行书中的例子。十二年前在大学自学ASP时&#xff0c;由于身边没有一位同学和朋友学习这种语言&#xff0c;也只能整天混在图收馆里拼命的啃书。而再后来也差不多&#xff0…

Bash内置命令

Bash有很多内置命令&#xff0c;因为这些命令是内置的&#xff0c;因此bash不需要在磁盘上为它们定位&#xff0c;执行速度更快。 1&#xff09;列出所有内置命令列表$enable 2&#xff09;关闭内置命令test$enable -n test 3&#xff09;打开内置命令test$enable test 4&…

postman调用webservice接口_接口对前后端和测试的意义

1.什么是接口&#xff1f;接口测试主要用于外部系统与系统之间以及内部各个子系统之间的交互点&#xff0c;定义特定的交互点&#xff0c;然后通过这些交互点来&#xff0c;通过一些特殊的规则也就是协议&#xff0c;来进行数据之间的交互。2.接口都有哪些类型&#xff1f;接口…