In the previous chapter, a question was raised and three solutions were proposed in this chapter:
Solution One: manual asynchronous conversion, the core idea: put the binding thing into codebehind
Filteritemcontrol.xaml:
<Grid> <image x:name= "filterimage" stretch= "UniformToFill"/> <grid verticalalignment= " Bottom "height=" > <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>/// Set up data source///</summary>// <param name= "filter" ></param> Public async void SetSource (filter filter) { if (filter! = null) { _filter = filter; Using WriteableBitmap has a bad point: you have to know the size of the picture writeablebitmap result = new WriteableBitmap (768, 1280x720); 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; } }
Set the data source for it, FilterItemsControl.cs
<summary>///Data source changed///</summary>// <param name= "Filters" > Filter list </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; //Put the things in the binding into the code! Itemcontrol. SetSource (filter);
Itemcontrol. itemselected + = itemcontrol_itemselected; Itemcontrol. itemdoubleclicked + = itemcontrol_itemdoubleclicked; CONTAINER.CHILDREN.ADD (Itemcontrol);}}}
Advantages: Convenient and simple
Cons: XAML must be written dead, not extensible, and if the same data transforms a display, a control needs to be rewritten.
solution Two: using asynchronous attributes, core ideas, using binding and asynchronous loading
Filteritemcontrol.xaml
<Grid> <image x:name= "filterimage" stretch= "UniformToFill" source= "{Binding Wbasyncproperty.asyncvalue, Converter={staticresource Imagconverter}} "/> <grid VerticalAlignment=" Bottom "height=" > <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 doesn't need extra stuff, but the model layer's data source needs to add an async property to be bound by the view layer
Filter.cs
Private asyncproperty<byte[]> _wbasyncproperty; Async Property Public asyncproperty<byte[]> wbasyncproperty { get { return _wbasyncproperty; } Set { SetProperty (ref _wbasyncproperty, value); }
Initialize public Filter () { wbasyncproperty = new asyncproperty<byte[]> (async () = { var result = await myfiltersdk.processfilterasync (this); return result; });
Because the return value is a byte[] type, we must convert it to WriteableBitmap:BytesToImageConverter.cs at the time of binding.
public class Bytestoimageconverter:ivalueconverter {public Object Conv ERT (object value, Type targetType, object parameter, String language) {//Use WriteableBitmap have a bad point: you have to know The size of the road picture writeablebitmap result = new WriteableBitmap (768, 1280); var filterdata = value as byte[]; if (filterdata! = null) {#region WriteableBitmap scheme using (var Bmpstream = Resul T.pixelbuffer.asstream ()) {Bmpstream.seek (0, Seekorigin.begin); Bmpstream.write (filterdata, 0, (int) bmpstream.length); return result; } #endregion} else return null; public object Convertback (object value, Type targetType, object parameter, string language) {T Hrow new NotImplementedException (); } }
about how to implement AsyncProperty and how it works here do not delve into the pros and cons of this scheme here:
Pros: Using Binding,ui will not stutter, after the picture gets finished, it appears on the UI
Cons: 1. Control reusability is not high
2. The SDK must be UI agnostic, which is why returning byte[], rather than simply returning Wrieablebitmap, is related to AsyncProperty's implementation technology
3. Because of Reason 2, the converter must be implemented
Solution Three: using DataTemplate, the core idea: to put datatemplate transformation into codebehind
Filteritemcontrol.xaml need to change, here only one contentpresenter to receive content
<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 need to add a contenttemplate to get the template applied to the control and display the UI according to the template:
Public DataTemplate Contentdatatemplate {get {return (DataTemplate) GetValue (contentdatatemplateprop Erty); } set {SetValue (Contentdatatemplateproperty, value);} } public static readonly DependencyProperty Contentdatatemplateproperty = Dependencyproperty.register ("C Ontentdatatemplate ", 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 roote Lement = Newdatatemplate.loadcontent () as UIElement; if (rootelement! = null) {Image img = VisualtreeexTensions. Findfirstelementinvisualtree<image> (rootelement); if (img! = null) {#region uses the SDK to process writeablebitmap result = new writ Eablebitmap (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//After changing the picture, you need to add it to the visualization to show that if you don't add this step you can imagine what will happen Presen ter. Content = rootelement; } } }
Again, you need to modify FilterItemsControl.cs and add a itemdatatemplate to Filteritemcontrol:
<summary>///Child templates////</summary> public DataTemplate itemdatatemplate {get {return (DataTemplate) GetValue (itemdatatemplateproperty);} set {SetValue (Itemdatatemplateproperty, value);} } public static readonly DependencyProperty Itemdatatemplateproperty = Dependencyproperty.register ("Item DataTemplate ", typeof (DataTemplate), typeof (FilterItemsControl3), new PropertyMetadata (0));///<summary>// Data source changed///</summary>//<param Name= "Filters" > filter list </param> private void Onitemss Ourcechanged (list<filter> filters) {if (filters! = null) {container.ch Ildren. Clear (); foreach (var filter in filters) {FilterItemControl3 Itemcontrol = new Filteritemcontrol 3 (); Itemcontrol. Width = Itemwidth; No, specify in DataTemplate. Itemcontrol. Height = ItemHeight; 1. Set DataContext Itemcontrol. DataContext = filter; 2. Set the template Itemcontrol. Contentdatatemplate = itemdatatemplate; Itemcontrol. itemselected + = itemcontrol_itemselected; Itemcontrol. itemdoubleclicked + = itemcontrol_itemdoubleclicked; CONTAINER.CHILDREN.ADD (Itemcontrol); } } }
Then we just need to write a itemdatatemplate where we can use this control:
<local:filteritemscontrol3 x:name= "Filteritemsusercontrol" opacity= "0" rendertransformorigin= "0.5,0.5" Margin= " 0 "> <local:FilterItemsControl3.RenderTransform> <compositetransform Translat ey= "/> </local:FilterItemsControl3.RenderTransform> <local:filteritemscontro" L3. itemdatatemplate> <DataTemplate> <grid width= "height=" > <image x:name= "Sourceimage"/> <grid height= "VerticalAlign" Ment= "Top" background= "#7F000000" > <textblock x:name= "TextBlock" textwrapping= "Wrap" text= "{Binding filtername}" horizontalalignment= "center" verticalalignment= "center" foreground= "white"/> </Grid> </Grid> </DataTemplate> &L T;/local:filteritemscontrol3.Itemdatatemplate> </local:FilterItemsControl3>
The third scenario is what I want to express, but we can see that it is not optimal, that you need to remove the visual elements from the DataTemplate in the code, and then place the image that the SDK has processed in the source of the target image control, but there are some advantages: 1. The extensibility of the UI
2. Properties unrelated to Asynchrony can be displayed through the binding
It can be said that scenario three simulates how datatemplate is applied to a control, which is what I want to summarize from this example:
1. The role of DataTemplate
2. What happens to the control after the DataTemplate has been applied?
3. Through Datatemplate.loadcontent (), get the control, and modify the control, if you do not use presenter.content = RootElement, why is there no response?
Summarize:
1. First of all, DataTemplate's MSDN explanation is very clear, which is to convert "data" into visible elements, which is why we chose DataTemplate to display the filter.
2. What happens to the control after the DataTemplate is applied? Because Microsoft is closed, we can't see it, but we can guess that its implementation is similar to our implementation of scenario three: Get the element in DataTemplate and load it into the visual tree to display. The DataTemplate we write in XAML is similar to a declaration of a class, when a control needs this datatemplate, it will be a new instance, then the target control, and replace the visual tree before it.
3. The answer to the third question is based on the second question: the UIElement obtained by Datatemplate.loadcontent () is not the same every time, meaning that invoking the method is similar to calling New DataTemplate (), just one instantiation, The elements at this point are not loaded into the visual tree (can be compared by GetHashCode ()), so no matter what changes you make, you will not see the results. So there must be presenter.content = rootelement this critical step.
Demo has been written, VS2015 project, Wu Frame, pc run.
Myfilterdemo.rar
Windows 10 Development Diary (v)--when binding encounters an asynchronous--solution