ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

c#软件开发学习笔记--WPF(Canvas、数据绑定、MVVM模式、值转换器)

c#软件开发学习笔记--WPF(Canvas、数据绑定、MVVM模式、值转换器) WPF 学习总结一、Canvas 绘图1.1 概述Canvas 是 WPF 中的一个布局容器允许通过绝对坐标Canvas.Left、Canvas.Top精确定位子元素适合绘制自定义图形和仪表盘等场景。1.2 常用绘图元素Ellipse椭圆/圆!-- 外圆 --EllipseCanvas.Left0Canvas.Top0Width300Height300FillBlackStrokeBlackStrokeThickness20/!-- 内圆 --EllipseCanvas.Left20Canvas.Top20Width260Height260FillBlackStrokeYellowStrokeThickness2/Line线条!-- 绘制刻度线 --LineStrokeWhiteStrokeThickness3X1150X2150Y130Y250/Path ArcSegment弧形!-- 使用 Path 绘制弧形 --PathFillTransparentStrokeRedStrokeThickness30Path.DataPathGeometryPathFigureStartPoint150,30ArcSegmentIsLargeArcFalsePoint270,150Size135,135SweepDirectionClockwise//PathFigure/PathGeometry/Path.Data/PathPath绘制任意线条和图形的控件PathGeometry描述几何形状数据由多段路径组合而成PathFigure实现一段或多段路径ArcSegment绘制弧形的段关键属性StartPoint起始点、Point弧形结束位置、Size半径、SweepDirection方向Clockwise顺时针 /Counterclockwise逆时针、IsLargeArc大弧/小弧二、静态资源与动态资源2.1 概念对比类型关键字加载时机运行时更新适用场景静态资源StaticResource窗口加载时不更新固定不变的资源动态资源DynamicResource实际使用时运行时更新需要动态切换的资源三、数据绑定3.1 绑定基础绑定到元素Sliderx:Nameslider2/TextBoxText{Binding ElementNameslider2, PathValue, ModeOneWay}/绑定到数据源非元素方式一创建数据上下文XAML 中推荐有智能提示!-- 引用命名空间 --xmlns:localclr-namespace:_3数据绑定!-- 创建上下文对象 --Window.DataContextlocal:Student//Window.DataContext方式二代码中设置 DataContext// MainWindow.xaml.csPersoncsp1newPersoncs();this.DataContextp1;!-- 配合设计时数据上下文获取智能提示 --d:DataContext{d:DesignInstance Typelocal:Personcs}3.2 五种绑定模式模式描述使用场景Default默认绑定根据目标属性决定常规绑定OneWay单向数据源 → UI数据变化需更新界面TwoWay双向数据源 ↔ UI表单输入等双向同步OneTime一次性数据源 → UI仅初始化时只需初始值的静态展示OneWayToSource单向UI → 数据源UI 变化需更新数据源3.3 INotifyPropertyChanged 接口实现该接口后当属性值变化时通知 UI 更新。方式一手动传递属性名publicclassPersoncs:INotifyPropertyChanged{publiceventPropertyChangedEventHandlerPropertyChanged;publicvirtualvoidOnPropertyChanged(stringpropertyName){PropertyChanged?.Invoke(this,newPropertyChangedEventArgs(propertyName));}privatestringname张三;publicstringName{get{returnname;}set{namevalue;OnPropertyChanged(Name);// 手动传属性名}}}方式二使用[CallerMemberName]推荐更简洁publicclassPersoncs1:INotifyPropertyChanged{publiceventPropertyChangedEventHandlerPropertyChanged;// CallerMemberName 让编译器自动传入属性名publicvirtualvoidOnPropertyChanged([CallerMemberName]stringpropertyNamenull){PropertyChanged?.Invoke(this,newPropertyChangedEventArgs(propertyName));}privatestringname张三;publicstringName{get{returnname;}set{namevalue;OnPropertyChanged();// 无需传参}}}3.4 绑定实体类属性StackPanelWrapPanelLabelContent用户/TextBoxWidth100Height30Text{Binding PathName}//WrapPanelWrapPanelLabelContent年龄/TextBoxWidth100Height30Text{Binding Age}//WrapPanelWrapPanelLabelContent性别/ComboBoxWidth100ItemsSource{Binding Sex}//WrapPanelWrapPanelLabelContent出生日期/DatePickerWidth150Text{Binding BirthDay}//WrapPanel/StackPanel四、MVVM 模式4.1 MVVM 理论MVVM 分为三层各司其职完全解耦┌──────────┐ 数据绑定 ┌────────────┐ 操作/通知 ┌──────────┐ │ View │ ◄──────────► │ ViewModel │ ◄────────────► │ Model │ │ (界面) │ │ (视图模型) │ │ (数据模型) │ └──────────┘ └────────────┘ └──────────┘View视图XAML 界面负责展示和交互不写业务逻辑ViewModel视图模型中间桥梁封装数据、命令、业务逻辑不持有 View 引用Model模型数据实体、数据访问、业务模型数据流向Model → ViewModel → View数据展示用户操作View → ViewModel → Model数据修改完整流程用户操作界面 View → Binding 将数据传给 ViewModelViewModel 做业务处理ViewModel 执行 Update将新数据写入 ModelModel 数据改变Notify 通知 ViewModelViewModel 触发PropertyChanged事件通知绑定刷新 View 界面4.2 ViewModelBase基类publicclassViewModelBase:INotifyPropertyChanged{publiceventPropertyChangedEventHandlerPropertyChanged;publicvirtualvoidOnPropertyChanged([CallerMemberName]stringpropertyNamenull){PropertyChanged?.Invoke(this,newPropertyChangedEventArgs(propertyName));}}4.3 RelayCommandICommand 实现publicclassRelayCommand:ICommand{privatePredicateobject_canExecute;// 控制按钮是否可执行privateActionobject_excute;// 按钮点击回调逻辑// 构造函数传入控制条件和执行逻辑publicRelayCommand(PredicateobjectcanExecute,Actionobjectexcute){this._excuteexcute;this._canExecutecanExecute;}// 构造函数始终可执行publicRelayCommand(Actionobjectexcute){this._canExecute(o)true;this._excuteexcute;}// 使用 CommandManager.RequerySuggested 自动刷新按钮状态publiceventEventHandlerCanExecuteChanged{add{CommandManager.RequerySuggestedvalue;}remove{CommandManager.RequerySuggested-value;}}publicboolCanExecute(objectparameter)_canExecute(parameter);publicvoidExecute(objectparameter)_excute(parameter);}4.4 Model数据模型publicclassStudent:ViewModelBase{publicintId{get;set;}privatestringname;publicstringName{get{returnname;}set{namevalue;OnPropertyChanged();}}publicintAge{get;set;}}4.5 ViewModel核心逻辑publicclassMainViewModel:ViewModelBase{privateObservableCollectionStudent_allStudents;privateObservableCollectionStudentstudents;publicObservableCollectionStudentStudents{get{returnstudents;}set{studentsvalue;OnPropertyChanged();}}// 构造时初始化数据publicMainViewModel(){studentsnewObservableCollectionStudent(MockDataHelper.initData);_allStudentsnewObservableCollectionStudent(MockDataHelper.initData);}// 添加命令publicRelayCommandAddCommandnewRelayCommand((obj){StudentstunewStudent(){Id_nextId,NameFoo,Age20};_allStudents.Add(stu);DoFitter();});// 带条件的查询命令publicRelayCommandSearchCommandnewRelayCommand((obj)!string.IsNullOrEmpty(searchName),// 仅在搜索框不为空时可执行(obj){DoFitter();});// 筛选方法publicvoidDoFitter(){IEnumerableStudentlist_allStudents;if(!string.IsNullOrEmpty(SearchName))list_allStudents.Where(ss.Name.Contains(SearchName));StudentsnewObservableCollectionStudent(list);}}4.6 View 绑定XAMLWindow.DataContextvm:MainViewModel//Window.DataContext!-- 绑定命令 --ButtonContent查询Command{Binding SearchCommand}/ButtonContent添加Command{Binding AddCommand}/!-- 绑定输入框实时更新 --TextBoxText{Binding SearchName, UpdateSourceTriggerPropertyChanged}/!-- DataGrid 绑定集合 --DataGridItemsSource{Binding Students}AutoGenerateColumnsFalseDataGridTemplateColumnHeader编号DataGridTemplateColumn.CellTemplateDataTemplateTextBlockText{Binding Id}HorizontalAlignmentCenter//DataTemplate/DataGridTemplateColumn.CellTemplate/DataGridTemplateColumn/DataGrid4.7 DataGrid 单元格内命令绑定RelativeSource!-- 在 DataGrid 单元格模板中绑定 ViewModel 的命令 --ButtonContent修改Command{Binding DataContext.CellEditCommand, RelativeSource{RelativeSource AncestorTypeDataGrid}}CommandParameter{Binding}/RelativeSource AncestorTypeDataGrid向上查找父级 DataGrid获取其 DataContext即 MainViewModelCommandParameter{Binding}传递当前行绑定的 Student 对象作为参数4.8 ObservableCollection可观察集合ObservableCollectionT是 WPF 中可被监听的集合当添加或删除元素时UI 会自动更新普通ListT的 Add/Remove 操作不会被 UI 监听五、值转换器5.1 单值转换器IValueConverter实现IValueConverter接口将bool转为string显示文本。publicclassBoolToTextConvert:IValueConverter{// 数据源 → UIbool → stringpublicobjectConvert(objectvalue,TypetargetType,objectparameter,CultureInfoculture){if(valueisboolb)returnb?正常:禁用;return未知;}// UI → 数据源string → boolpublicobjectConvertBack(objectvalue,TypetargetType,objectparameter,CultureInfoculture){stringtextvalueasstring;if(text正常)returntrue;if(text禁用)returnfalse;returnBinding.DoNothing;}}XAML 中使用!-- 引入转换器资源 --Window.Resourceslocal:BoolToTextConvertx:KeyBoolToText//Window.Resources!-- 使用转换器 --TextBoxText{Binding IsNormal, Converter{StaticResource BoolToText}}/5.2 多值转换器IMultiValueConverter实现IMultiValueConverter接口将多个值合并为一个。publicclassNameAgeMul:IMultiValueConverter{// 多个值 → 合并为一个字符串publicobjectConvert(object[]values,TypetargetType,objectparameter,CultureInfoculture){stringnamevalues[0].ToString();intage(int)values[1];return$姓名:{name},年龄:{age};}// 字符串 → 拆分为多个值publicobject[]ConvertBack(objectvalue,Type[]targetTypes,objectparameter,CultureInfoculture){stringstrvalue.ToString();string[]arrstr.Split(,);stringnamearr[0].Split(:)[1];stringagearr[1].Split(:)[1];returnnewobject[]{name,int.Parse(age)};}}XAML 中使用 MultiBindingWindow.Resourceslocal:NameAgeMulx:KeyNameAge//Window.ResourcesTextBlockTextBlock.TextMultiBindingConverter{StaticResource NameAge}BindingPathName/BindingPathAge//MultiBinding/TextBlock.Text/TextBlock5.3 转换器使用步骤总结定义转换器实现IValueConverter单值或IMultiValueConverter多值接口引入 XAML先导入命名空间再定义为资源应用转换器在标签中使用Converter{StaticResource 资源Key}
返回列表