惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Heimdal Security Blog
A
Arctic Wolf
K
Kaspersky official blog
V
Vulnerabilities – Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Simon Willison's Weblog
Simon Willison's Weblog
L
LINUX DO - 热门话题
MongoDB | Blog
MongoDB | Blog
T
Threat Research - Cisco Blogs
D
Docker
爱范儿
爱范儿
T
Tenable Blog
C
Check Point Blog
B
Blog
C
Cisco Blogs
Vercel News
Vercel News
The Cloudflare Blog
T
Threatpost
NISL@THU
NISL@THU
T
Tor Project blog
V2EX - 技术
V2EX - 技术
P
Palo Alto Networks Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tailwind CSS Blog
G
GRAHAM CLULEY
P
Privacy & Cybersecurity Law Blog
SecWiki News
SecWiki News
博客园 - 司徒正美
S
Security @ Cisco Blogs
GbyAI
GbyAI
S
Secure Thoughts
Microsoft Security Blog
Microsoft Security Blog
The Register - Security
The Register - Security
Recorded Future
Recorded Future
Cloudbric
Cloudbric
Webroot Blog
Webroot Blog
N
News and Events Feed by Topic
Y
Y Combinator Blog
博客园_首页
T
Troy Hunt's Blog
The Hacker News
The Hacker News
雷峰网
雷峰网
Google DeepMind News
Google DeepMind News
U
Unit 42
AWS News Blog
AWS News Blog
PCI Perspectives
PCI Perspectives
V
Visual Studio Blog
博客园 - 聂微东
有赞技术团队
有赞技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell

博客园 - surfsky

用阿里的 sketch 插件 FusionDesign 来快速设计中后台 用 Sketch 设计和输出响应式网页 百度、高德、腾讯、天地图、谷歌、必应瓦片图地图切图工具 MapCutter(旧名 MapTiler),支持超大图、高清切片、webgl、leaflet、maptalk、openlayers、cesium netcore 下的 Javascript 表达式求值 netcore 下的 C# 表达式求值 中标麒麟安装SQLServer 中标麒麟上开启MySql 在 MAC 下配置 Nginx Color Schema 配色随笔 .Net与 WebAssembly 随笔 用Nuget部署程序包 Qt3D Qt3D Shader Qt QML 2D shader LearnOpenGL Qt3D 5.9 and future FineUI 相关 EntityFramwork 七七八八 Qt qml 单例模式
关于Xamarin、Qml、数据绑定、MVC、MVVM 相关的散讲
surfsky · 2018-07-12 · via 博客园 - surfsky
关于Xamarin、Qml、数据绑定、MVC、MVVM 相关的散讲
SURFSKY 2017.02


最近又在学习Xamarin了?为什么是“又”?有几个利好消息,让我重新拾起它:
    (1)微软去年收购了Xamarin,而且免费。原先的费用会吓死人,而且按人头+平台来收费。
    (2)Xamarin.Forms 的出现,UI层也可以复用了,不像原先只能逻辑层代码复用。
    (3)IDE增强:
        Xamarin Forms Previewer,可以直接预览 XAML 的外观。
        XAML 智能感应的增强,现在编写XAML舒服多了。原先编写XAML可不是件轻松的事情,所以之前的教材全部都是用C#写的UI,这很不利于视图和逻辑的分离。
        Visual Studio for mac 发布,可替代原先的 Xamarin Studio for mac。毕竟,在mac下编写ios/Android app无论性能还是便利性都要比在windows上好得多。
        不愧是宇宙最强IDE开发商,一接手Xamarin,编辑器就增强了:)
    (4)真正的一个语言可以编写跨平台移动app,包括后台、ios、android、windows uwp 等
        数据接口和后台:用 asp.net 写即可
        移动客户端API:Xamarin 已用C#封装好,如果需要平台专用功能,直接调用即可。
        这很利于节省成本、积累技术、简化员工招招聘和培训。
    (5)性能
        对于ios平台,xamarin是将c#编译成原生的代码。android是嵌入了.NET运行时。
        实测试了下,ios下没有任何问题,3秒左右进入主界面,进去后性能就和原生的没有区别了
        android的启动略慢,估计要5秒,进去后性能没有问题。
        加个欢迎屏可以稍微减缓客户等待的焦虑感。

当然还有缺陷和期望
    缺陷
        Xamarin.Forms 的控件是转化为各平台原生控件的,也就是说,这些控件在各平台上外观都有区别!
        IED
            复杂的 XAML previewer展示不出来。
            无法拖拽控件快速设计页面。
            VS MAC 有时候屏幕刷新不过来,一片白。
            经常出现“不是在活动配置中生成的项目”,无法加载项目。
        启动速度还是慢了点,位于可容忍的边缘。
        没有官方的、统一的移动平台功能 API 库。
            类似PhoneGap那样的,访问摄像头、传感器等API,一套代码各平台通用。
            现有的这些功能API是分散在各平台自己的库里的,学习一个统一库与学习多平台类库,工作量当然不一样。
            早些年有Xamarin.Mobile项目,但与Xamarin.Forms不兼容已经废弃了。
            现在这些功能API插件处于散乱琐碎状态,要自己一个个去Xamarin Compoents/GitHub上找。
    期望
        不知什么时候可以直接拖拽 Xamarin Forms 控件,一个平台也行啊。
        加快 Xamarin Form Android app 启动速度。
        需要一套外观一致的 Xamarin Forms UI 库,但短期内不会有,要我们直接写了(*)
        官方推出统一的跨平台移动功能 API 库:Xamarin.Forms.Mobile(*)
    备注
        当然 Visual Studio for mac 还是预览版本,等正式版估计BUG会少一些。
        (*)打算启动这两个项目,欢迎有共同志向的同学参与。

相比较 Qt
    性能还是Qt占优的,毕竟底层是C++写的。但Xamarin的性能也在可容忍范围内,主要是启动时间稍慢了点。
    APP 大小。
        都在20M以上,
        Qt
            V-Play apps 基于Qt的游戏引擎 52.4M
            新发布的 Qt 5.8据说可以裁剪库的大小,将APP压缩到4、5M内
        Xamarin 我也搞不清楚了。
            Xuni Explorer 只有 5.6 M
            Evlove 16 有46.1M
            随便编译个debug版本的,估计有60多M,release的还没试验
    虽然说理论上 Qml 可以摆平一切界面问题,但我们不可避免的要涉及到各平台的插件,那么你真正需要学习的语言有:
        QML           : 
        Javascript    : 
        C++           : Qt类库
        Object-C      : 
        Android       : 
    ps.真希望Qml能发展成独立的开发语言(参照 swift)
        强类型
        可编译
        简化创建组件语法,直接用new MyItem(),而不是复杂的Qt.CreateComponent.....
        摒弃js、v4引擎,提供工具将js迁移为标准Qml
        独立发展 Qml 类库
        更便利的方式访问c++类库,类似swift那样,只需Import即可使用


绑定的前世今生
    若要监控一个对象的若干属性变化情况,传统写法是为每个要监控的属性加上一个值变更事件,然后让调用者添加这个事件
        public event Event FirstNameChanged;
        public string FirstName {get; set;}
        sample.FirstNameChanged += (o, value)=>txtbox.Text = value;
        这样很可能要写很多的属性变更事件,而且不能自动给订购者赋值
    什么是绑定?它事实上做了两件事
        (1)监听对象指定属性,若变化,则通知给订购者
        (2)给订购者赋值
    微软给出的官方方案是
        (1)绑定系统维护了一个表格(在绑定表达式中指定),字段大致包括:
            object SourceObject         : 监听对象
            string SourcePropertyName   : 监听对象的属性名称
            object TargetObject         : 订购者
            string ValuePath            : 赋值路径
        (2)让数据实现INotifyPropertyChanged接口
            public event PropertyChangedEventHandler PropertyChanged;
            若监听对象的属性有变动,则触发这个事件,通知绑定系统
            这个事件的参数中包含了监听对象和变更的属性名称(SourceObject + SourcePropertyName)
        (3)绑定系统去查表,给订购者进行赋值
            TargetObject = SourceObject.SourcePropertyName.ValuePath

属性变更通知
    INotifyPropertyChanged接口(属性变更的时候通知下绑定系统,我的哪个属性变更了,快处理啊)
        class Sample : INotifyPropertyChanged
        {
            // INotifyPropertyChanged 接口成员
            public event PropertyChangedEventHandler PropertyChanged;

            // 属性
            private string firstName;
            public string FirstName
            {
                get { return firstName; }
                set
                {
                    firstName = value;
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
                }
            }
        }
        // 绑定(textBox.Text <= sourceObject.FirstName)
        Sample sourceObject = new Sample();
        textbox.DataBindings.Add("Text", sourceObject, "FirstName");
        sourceObject.FirstName = "Stack";


我们做一下封装,加上值相等判断。
    定义 ViewModelBase
        using System;
        using System.ComponentModel;
        using System.Runtime.CompilerServices;
        namespace Xamarin.FormsBook.Toolkit
        {
            public class ViewModelBase : INotifyPropertyChanged
            {
                public event PropertyChangedEventHandler PropertyChanged;
                protected bool SetProperty<T>(ref T storage, T value, string propertyName = null)
                {
                    if (Object.Equals(storage, value))
                        return false;
                    storage = value;
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                    return true;
                }
            }
        }
    让数据模型类继承自ViewModelBase
        public class InformationViewModel : ViewModelBase
        {
            string name;
            public string Name
            {
                get { return name; }
                set 
                { 
                    if (SetProperty(ref name, value, "Name"))
                    {
                        ...属性已经更新,该干点啥
                    }; 
                }
            }
        }
    
 

Xamarin 的方案(使用 BindableObject)
    代码
        public RadioButtonGroup : BindableObject
        {
            public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(Radio), "", propertyChanged: TextChanged);
            private static void TextChanged(BindableObject bindable, object oldValue, object newValue)
            {
                var radio = (Radio)bindable;
                radio.Lbl.Text = (string)newValue;
            }
            public string Text 
            {
                get {return (string)this.GetValue(TextProperty);}
                set {this.SetValue(TextProperty, value);}
            }
        }
        this.Icon.SetBinding(Image.IsVisibleProperty, new Binding("ShowRadio", source: this));
    说明
        这里的BindableProperty是用于描述这个属性的元信息,如名称、类型、默认值、绑定方向、属性值变更事件
        BindableObject 是 INotifyPropertyChanged 的封装,增加了绑定上下文、属性变更中、属性变更完毕事件等逻辑
            public abstract class BindableObject : INotifyPropertyChanged, IDynamicResourceHandler
            {
                public static readonly BindableProperty BindingContextProperty;
                public object BindingContext { get; set; }
                protected BindableObject ();
        
                // Methods
                protected void ApplyBindings (object oldContext = null);
                public void ClearValue (BindableProperty property);
                public void ClearValue (BindablePropertyKey propertyKey);
                public object GetValue (BindableProperty property);
                protected virtual void OnBindingContextChanged ();
                protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null);
                protected virtual void OnPropertyChanging ([CallerMemberName] string propertyName = null);
                public void RemoveBinding (BindableProperty property);
                public void SetBinding (BindableProperty targetProperty, BindingBase binding);
                public void SetValue (BindablePropertyKey propertyKey, object value);
                public void SetValue (BindableProperty property, object value);
                protected void UnapplyBindings ();
        
                // Events
                public event EventHandler BindingContextChanged { add; remove;}
                public event PropertyChangedEventHandler PropertyChanged {add; remove;}
                public event PropertyChangingEventHandler PropertyChanging {add; remove;}
            }
            
单向数据绑定和双向数据绑定
    单向:model的变更会刷新view,view上做任何操作都不影响model
    双向:model的变更会刷新view,view的变更会刷新model
    个人只喜欢用单向的,理由呢:
        喜欢实打实的代码来控制数据刷新,双向的数据绑定总觉得不放心
        view的交互,常常带了逻辑控制,不仅仅是给model赋值,这不是双向数据绑定能解决的。
        


其它
    Qt QML的属性、绑定、属性变更事件实现起来非常优美和简单
        A
        {
            property int Property1;
            
            // 编译器会自动生成类似以下方法
            // bool onProperty1Changing(o, oldValue, newValue){...}
            // void onProperty1Changed(o, oldValue, newValue) {....}
        }
        b.Property2 = a.Property1;  // 绑定这两个对象的属性(单向绑定)
    建议 C# 优化编译器,或者提供语法糖之类的东西(如propety关键字)
        public readonly property string Name;
        编译器自动实现:
            getter、setter
            INotifyPropertyChanged 接口
            PropertyChangingEvent
            PropertyChangedEvent
            绑定逻辑
        事实上,这个功能10来年前的 Delphi 就实现了
        


什么是 MVC
    这是将界面、逻辑、数据隔离的一种方案,这其实也是绑定的一种实现,不过是页面级别的。
        Model      : 数据
        View       : 视图
        Controller : 控制器
    视图的呈现由控制器控制,视图的数据(模型)也由控制器提供
    TODO: 补一个简单的示例
    ASP.NET MVC
        是一个controller对应多个view
        它的controller主要就是个跳转器,根据客户端请求,组装数据并提供给某个视图,渲染到客户端
        疑问:
            大的页面用controller跳转好理解
            但小的交互,如按钮点击页面上的某个label变个文字,这个也交给controll是不是太琐碎了?
            这个还是交给页面客户端自己处理会更合适,但这要写js了
    其实传统的 Windows Form 也可以看为一种MVC
        View部分可由设计器创建
        View的数据展示、交互(如点击事件)在后台代码中,这个可以看成Controller
        不过这种方式是一个view对应一个controller,这个controller是这个view专用的
    ios-objectc 的MVC
        这货和 Windows Form 差不多,也是一个视图对应一个专用的控制器
        挂MVC的头衔,行Windows Form的行当。

什么是 MVVM
    这是将界面和数据完全隔离的一种方案
        Model      : 模型
        View       : 视图
        ViewModel  : 视图模型
    传统的页面数据展示,可以是混杂的,既有数据绑定,也可以掺杂代码指定。如:
    TODO:来段 MVVM 的示例代码
    可以看出,MVVM是一种更极端的、界面和数据完全隔离的方案:
        它定义了一个叫 ViewModel 的东西,这个也是一种Model,但专用于视图
        视图的赋值只能用 ViewModel,不能用其它方式
        我们必须为每个 View 定制一个 ViewModel。
    评价
        好处:完全隔离视图和数据、只要约定好数据接口(ViewModel)就行
        坏处:必须为每个视图都定制 ViewModel,这会增加代码量
        
        
ps
    2017-05 出了个 Xamarin Live Player 的东东,可以在手机上展示程序运行效果
        android版本的可以直接下载,ios版本的还在testflight中
        https://docs.microsoft.com/zh-cn/xamarin/tools/live-player/