CPF 入门教程

CPF netcore跨平台UI框架

系列教程

CPF 入门教程(一)

CPF 入门教程 - 数据绑定和命令绑定(二)

CPF 入门教程 - 样式和动画(三) 

CPF 入门教程 - 绘图(四) 

数据绑定和Wpf类似,支持双向绑定。数据绑定和命令绑定是UI和业务逻辑分离的基础。

首先,你需要定义个MainModel,为了可以有属性通知,这个类可以继承CpfObject或者自己实现INotifyPropertyChanged

1     public class MainModel : CpfObject
2     {
3         [PropertyMetadata("默认值")]
4         public string Test
5         {
6             get { return (string)GetValue(); }
7             set { SetValue(value); }
8         }
9     }

这里定义了一个Test属性,并且设置默认值为“默认值”

设计个测试界面,加个TextBlock和Button,同时TextBlock设置绑定,绑定定义在Bindings属性, {nameof(TextBlock.Text),nameof(MainModel.Test) } 表示TextBlock的Text绑定到DataContext的Test属性

    public class Window4 : Window
    {
        protected override void InitializeComponent()
        {
            Title = "标题";
            Width = 344.8f;
            Height = 126.4f;
            Background = null;
            Children.Add(new WindowFrame(this, new Panel
            {
                Width = "100%",
                Height = "100%",
                Children =
                {
                    //内容元素放这里
                    new Button
                    {
                        MarginLeft = 223.8f,
                        MarginTop = 25.7f,
                        Height = 28f,
                        Width = 67.4f,
                        Content = "Button",
                    },
                    new TextBlock
                    {
                        MarginLeft = 36.7f,
                        MarginTop = 31.6f,
                        Text = "TextBlock",
                        Bindings =
                        {
                            {nameof(TextBlock.Text),nameof(MainModel.Test) }
                        }
                    },
                }
            }));
            LoadStyleFile("res://ConsoleApp1.Stylesheet1.css");
            //加载样式文件,文件需要设置为内嵌资源

        }
    }

修改program,设置Window的DataContext和CommandContext

            var model = new MainModel();
            Application.Run(new Window4 { DataContext = model, CommandContext = model });

写好之后,运行看看效果。TextBlock那边显示MainModel那边定义的默认值

接下来定义命令,通过按钮点击修改Test值,同时自动更新到TextBlock

MainModel里增加个Click方法

    class MainModel : CpfObject
    {
        [PropertyMetadata("默认值")]
        public string Test
        {
            get
            {
                return (string)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }

        public void Click()
        {
            Test += "test";
        }
    }

Button那边增加命令绑定,Commands里添加, {nameof(Button.Click),nameof(MainModel.Click) } 表示Button的Click事件绑定到CommandContext的Click方法

                    new Button
                    {
                        MarginLeft = 223.8f,
                        MarginTop = 25.7f,
                        Height = 28f,
                        Width = 67.4f,
                        Content = "Button",
                        Commands =
                        {
                            {nameof(Button.Click),nameof(MainModel.Click) }
                        }
                    },

运行效果,点击一次增加一次test。这就是最简单的模型视图分离的数据绑定

接下来绑定集合

设计界面,添加Button和ListBox

 

往MainModel里加上Items集合属性,构造函数里初始化集合,用 Collection 是为了有集合变化通知,也可以使用 ObservableCollection。 (string, string) 就是元组里简化的结构体类型定义,是一种偷懒简化数据定义的方式,不过这种方式的话,改item就不能更新到UI了,需要可以更新到UI的就需要自定义类型,继承CpfObject或者继承INotifyPropertyChanged的类型作为Item

        public MainModel()
        {
            Items = new Collection<(string, string)>();
        }

        public Collection<(string,string)> Items
        {
            get
            {
                return (Collection<(string, string)>)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }

MainModel里加个AddItem方法

        public void AddItem()
        {
            Items.Add(("test" + Items.Count, Items.Count.ToString()));
        }

最终代码

using CPF;
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApp1
{
    class MainModel : CpfObject
    {
        [PropertyMetadata("默认值")]
        public string Test
        {
            get
            {
                return (string)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }

        public void Click()
        {
            Test += "test";
        }

        public MainModel()
        {
            Items = new Collection<(string, string)>();
        }

        public Collection<(string, string)> Items
        {
            get
            {
                return (Collection<(string, string)>)GetValue();
            }
            set
            {
                SetValue(value);
            }
        }

        public void AddItem()
        {
            Items.Add(("test" + Items.Count, Items.Count.ToString()));
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CPF;
using CPF.Drawing;
using CPF.Controls;
using CPF.Shapes;
using CPF.Styling;
using CPF.Animation;

namespace ConsoleApp1
{
    public class Window4 : Window
    {
        protected override void InitializeComponent()
        {
            Title = "标题";
            Width = 338.4f;
            Height = 205.6f;
            Background = null;
            Children.Add(new WindowFrame(this, new Panel
            {
                Width = "100%",
                Height = "100%",
                Children =
                {
                    //内容元素放这里
                    new Button
                    {
                        MarginLeft = 223.8f,
                        MarginTop = 25.7f,
                        Height = 28f,
                        Width = 67.4f,
                        Content = "Button",
                        Commands =
                        {
                            {
                                nameof(Button.Click),
                                nameof(MainModel.Click)
                            }
                        }
                    },
                    new TextBlock
                    {
                        MarginLeft = 36.7f,
                        MarginTop = 31.6f,
                        Text = "TextBlock",
                        Bindings =
                        {
                            {
                                nameof(TextBlock.Text),
                                nameof(MainModel.Test)
                            }
                        }
                    },
                    new Button
                    {
                        MarginLeft = 223.8f,
                        MarginTop = 91.6f,
                        Height = 28f,
                        Width = 67.4f,
                        Content = "添加Item",
                        Commands =
                        {
                            {nameof(Button.Click),nameof(MainModel.AddItem) }
                        }
                    },
                    new ListBox
                    {
                        SelectedValuePath = "Item2",//绑定Item里的Item1属性
                        DisplayMemberPath = "Item1",//绑定Item里的Item2属性
                        BorderStroke = "1,Solid",
                        BorderFill = "#DEDEDE",
                        MarginLeft = 36.7f,
                        MarginTop = 60.8f,
                        Height = 76.5f,
                        Width = 123.2f,
                        Bindings =
                        {
                            {nameof(ListBox.Items),nameof(MainModel.Items) }
                        }
                    },
                }
            }));
            LoadStyleFile("res://ConsoleApp1.Stylesheet1.css");
            //加载样式文件,文件需要设置为内嵌资源
        }
    }
}

最终运行效果,点击添加Item的按钮,ListBox里会增加Item

数据类型转换,Test属性值后面加1。 数据转换器用方法或者Lambda就行。

                            {
                                nameof(TextBlock.Text),
                                nameof(MainModel.Test),
                                null,
                                BindingMode.OneWay,
                                (string a)=>a+"1"
                            }

UI元素之间绑定,TextBox的Text绑定到Button的Content,其中TextBox设置PresenterFor=this,是为了标记TextBox的作用域在当前类,因为Name是可以重复的,元素嵌套如果有相同Name会无法判断元素是在哪里的,所以用PresenterFor加标记判断,而且这样可以通过FindPresenterByName方法来获取当前类里的标记元素来绑定

        protected override void InitializeComponent()
        {
            Title = "标题";
            Width = 338.4f;
            Height = 205.6f;
            Background = null;
            Children.Add(new WindowFrame(this, new Panel
            {
                Width = "100%",
                Height = "100%",
                Children =
                {
                    //内容元素放这里
                    new Button
                    {
                        MarginLeft = 223.8f,
                        MarginTop = 25.7f,
                        Height = 28f,
                        Width = 67.4f,
                        Content = "Button",
                        Commands =
                        {
                            {
                                nameof(Button.Click),
                                nameof(MainModel.Click)
                            }
                        },
                        Bindings =
                        {
                            {
                                nameof(Button.Content),
                                nameof(TextBox.Text),
                                FindPresenterByName("textBox")
                            }
                        }
                    },
                    new TextBlock
                    {
                        MarginLeft = 36.7f,
                        MarginTop = 31.6f,
                        Text = "TextBlock",
                        Bindings =
                        {
                            {
                                nameof(TextBlock.Text),
                                nameof(MainModel.Test),
                                null,
                                BindingMode.OneWay,
                                (string a)=>a+"1"
                            }
                        }
                    },
                    new Button
                    {
                        MarginLeft = 223.8f,
                        MarginTop = 91.6f,
                        Height = 28f,
                        Width = 67.4f,
                        Content = "添加Item",
                        Commands =
                        {
                            {
                                nameof(Button.Click),
                                nameof(MainModel.AddItem)
                            }
                        }
                    },
                    new ListBox
                    {
                        SelectedValuePath = "Item2",
                        //绑定Item里的Item1属性
                        DisplayMemberPath = "Item1",
                        //绑定Item里的Item2属性
                        BorderStroke = "1,Solid",
                        BorderFill = "#DEDEDE",
                        MarginLeft = 36.7f,
                        MarginTop = 60.8f,
                        Height = 76.5f,
                        Width = 123.2f,
                        Bindings =
                        {
                            {
                                nameof(ListBox.Items),
                                nameof(MainModel.Items)
                            }
                        }
                    },
                    new TextBox
                    {
                        Name="textBox",
                        PresenterFor=this,
                        AcceptsReturn= false,
                        HScrollBarVisibility= ScrollBarVisibility.Hidden,
                        VScrollBarVisibility= ScrollBarVisibility.Hidden,
                        MarginLeft = 144.8f,
                        MarginTop = 28.1f,
                        Width = 74.5f
                    },
                }
            }));
            LoadStyleFile("res://ConsoleApp1.Stylesheet1.css");
            //加载样式文件,文件需要设置为内嵌资源
        }

TextBox输入,会自动更新Button的文字

命令绑定除了事件之外,属性变化也可以绑定为命令,比如,鼠标移入和移出就调用

                        Commands =
                        {
                            {
                                nameof(Button.IsMouseOver),
                                nameof(MainModel.Click)
                            }
                        }

主要绑定就这些,如果要双向绑定,命令参数等等,看VS那边的智能提示

原文地址:https://www.cnblogs.com/dskin/p/13493342.html