【我们一起写框架】MVVM的WPF框架(二)—绑定

简介: MVVM的特点之一是实现数据同步,即,前台页面修改了数据,后台的数据会同步更新。 上一篇我们已经一起编写了框架的基础结构,并且实现了ViewModel反向控制Xaml窗体。 那么现在就要开始实现数据同步了。

MVVM的特点之一是实现数据同步,即,前台页面修改了数据,后台的数据会同步更新。

上一篇我们已经一起编写了框架的基础结构,并且实现了ViewModel反向控制Xaml窗体。

那么现在就要开始实现数据同步了。

DataContext—数据上下文
在实现数据同步前,我们要了解一个知识点——DataContext。

WPF中每个UI都有一个Content和一个DataContext,那么Content和DataContext是什么呢?

Content:Content是指页面内容,即我们编写的代码,或者认为它是展示的UI。

打个比方,Content就是HTML页面中的标签,如【< html >< / html >】;那么,在WPF中Content是指的就是Xaml页面的标签了。

DataContext:DataContext是指页面中的数据内容,这部分内容只有运行了才存在,用过 ASPNETMVC的同学可以把它理解为MVC中的Model。(每个页面都有一个唯一的指定Model)

既然在WPF里DataContext就是MVC中的Model。那么,自然的,DataContext就要存储页面的ViewModel了,所以,我们为它赋值它自身对应的ViewModel。

现在,找到我们的BaseViewModel的构造函数,加入这行代码[UIElement.DataContext = this;],代码如下:

public BaseViewModel()
{
    WindowMain = Application.Current.MainWindow; 
    SetUIElement();
    UIElement.DataContext = this;
}

这样用ViewModel创建的页面的DataContext就被自动赋值了。

页面与ViewModel的基础关系就建立完成了。

Binding—绑定
在我们编写的框架中,绑定分两种,一种是属性绑定,一种是命令绑定。

属性绑定:属性绑定很好理解,就是将Xaml页面的控件属性和ViewModel中的自定义属性捆绑到一起,让他们的数据值同步。

命令绑定:命令绑定是Xaml页面触发命令,然后由ViewModel来处理命令。

这里的命令(Command)有点不太好理解,不过大家都做过面向事件的开发,我们可以把命令想象成事件,就是Xaml页面触发事件,ViewModel来执行事件内容。

接下来,我们一起做一些简单的绑定。

Property—属性绑定
首先,在程序框架中找到VM_WindowMain页面,然后在里面创建属性HeaderName,代码如下:

public string _HeaderName = "HeaderName_KibaFramework";
public string HeaderName { get { return _HeaderName; } set { _HeaderName = value; OnPropertyChanged(); } }

然后,我们再找到VM对应的Xam页面—WindowMain.xaml,修改Header代码如下:

<StackPanel  DockPanel.Dock="Top" Background="Gainsboro">
    <TextBlock TextAlignment="Left" Text="{Binding HeaderName}" Margin="20,20,0,0" Height="70" FontSize="36"></TextBlock>
</StackPanel>

界面效果如下:

图片描述

通过图片,我们可以看到,属性已经绑定成功了,并且成功输出了我们的HeaderName。

然后,我们重点看一下这段代码{Binding HeaderName}。

这句话的意思就是让TextBlock的Text属性绑定HeaderName属性,其中Binding就是绑定的意思。【注意,这里只能是属性绑定属性】

HeaderName是我们在VM中刚刚定义的属性,那么Text是怎么绑定到了HeaderName上的呢?

很简单,因为上面我们已经把ViewModel赋值到了DataContext中了,所以在Xaml中,我们就可以使用{Binding 属性名}这样的语句,来绑定VM中所有的属性。

在Xaml中,默认的绑定是单向绑定,就是说,VM中的属性值改变会同步Xaml页面的属性值,让其改变;但,当Xaml页面的属性值改变了,VM中的属性值却不会改变。

那么如何让他们同步呢?

很简单,只需要在绑定的时候多加一个属性Mode=TwoWay即可,代码如下:

{Binding HeaderName,Mode=TwoWay}

Command—命令绑定
在MVVM中,事件被极大的程度的弱化了,因为Command在ViewModel中替代了事件来处理业务逻辑,所以,事件在框架中就只负责处理UI变化这么一件事了。

BaseCommand

在WPF中,系统为我们提供一些Command,但为了能处理更多细节,自定义Command的效果会更好,所以,我们需要编写属于我们框架自己的自定义BaseCommand。

代码如下:

public class BaseCommand : ICommand
{
    public Action<object> ExecuteAction;
    public BaseCommand(Action<object> action)
    {
        ExecuteAction = action;
    }
    public bool CanExecute(object parameter)
    {
        return true;
    } 
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter)
    { 
        ExecuteAction(parameter); 
    } 
}

如上代码所示,我们自定义了BaseCommand,并且继承了ICommand接口,实现了接口方法。

Command的应用

下面我们开始Command的基础应用,使用Command实现页面切换;页面切换我们采用最简单的模式Window—Frame—Page的控制模式。

首先我们找到VM_WindowMain,创建切换Page的Command和存储页面实例的属性FrameSource。

代码如下:

public Page _FrameSource;
public Page FrameSource { get { return _FrameSource; } set { _FrameSource = value; OnPropertyChanged(); } } 
public BaseCommand ChangeFrameSourceCommand
{
    get
    {
        return new BaseCommand(ChangeFrameSourceCommand_Executed);
    }
}
public void ChangeFrameSourceCommand_Executed(object obj)
{
    string pageName = obj.ToString();
   switch(pageName)
   {
       case "PageMain":
           FrameSource = new VM_PageMain().UIElement as Page;
           break;
       case "PageUser":
           FrameSource = new VM_PageUser().UIElement as Page;
           break;
   }
}

接下来在页面实现按钮事件绑定和Frame显示页面绑定。

代码如下:

<TreeViewItem>
    <TreeViewItem.Template>
        <ControlTemplate>
            <Button HorizontalAlignment="Left" Content="PageMain" Command="{Binding ChangeFrameSourceCommand}" CommandParameter="PageMain"  Style="{StaticResource NullButton}"></Button>
        </ControlTemplate>
    </TreeViewItem.Template>
</TreeViewItem>
<TreeViewItem>
    <TreeViewItem.Template>
        <ControlTemplate>
            <Button HorizontalAlignment="Left" Content="PageUser" Command="{Binding ChangeFrameSourceCommand}" CommandParameter="PageUser"  Style="{StaticResource NullButton}"></Button>
        </ControlTemplate>
    </TreeViewItem.Template>
</TreeViewItem>

/* 省略了框架其他元素代码 */

<Frame x:Name="frameMain" Content="{Binding FrameSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"  NavigationUIVisibility="Hidden" ScrollViewer.CanContentScroll="True"  ></Frame>

从代码中我们可以看到,VM中的属性FrameSource绑定到了页面Frame的Content属性上。

由于TreeViewItem没有Command的依赖属性,所以我们修改了他的模板,然后用模板内的Button的Command属性绑定了VM中的ChangeFrameSourceCommand属性。

因为ChangeFrameSourceCommand是BaseCommand类型,所以,当按钮被按下时,就会触发ChangeFrameSourceCommand定义的执行命令——ChangeFrameSourceCommand_Executed。

这样我们就实现了框架内的页面切换了。


到此,我们框架的基础功能就已经实现了。

但如果框架只写到这里,那ViewModel对页面的掌控力度就显的太弱了。

而且项目框架不能仅仅考虑结构分离和业务独立,我们还要降低使用难度和提高使用者的开发效率。

所以为了更好的掌控UI,降低开发者的门槛,我们还需要编写数据控件,让开发者在不能熟练掌握Xaml样式的情况下,依然可以顺利完成开发。

那么,本篇文章就先讲到这了,下一篇文章我们将一起为框架编写数据控件,敬请期待。

框架代码已经传到Github上了,并且会持续更新。

相关文章:

【我们一起写框架】MVVM的WPF框架之序篇(一)

To be continued
Github地址:https://github.com/kiba518/KibaFramework


注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接!
若您觉得这篇文章还不错,请点击下右下角的【推荐】,非常感谢!
如果您觉得这篇文章对您有所帮助,那就不妨支付宝小小打赏一下吧。

目录
相关文章
|
14天前
|
设计模式 前端开发 C#
使用 Prism 框架实现导航.NET 6.0 + WPF
使用 Prism 框架实现导航.NET 6.0 + WPF
56 10
|
1月前
|
设计模式 前端开发 C#
WPF 项目中 MVVM模式 的简单例子说明
本文通过WPF项目中的加法操作示例,讲解了MVVM模式的结构和实现方法,包括数据模型、视图、视图模型的创建和数据绑定,以及命令的实现和事件通知机制。
|
2月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
55 0
|
2月前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
82 0
|
2月前
|
前端开发 开发者 C#
WPF开发者必读:MVVM模式实战,轻松实现现代桌面应用架构,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离应用程序的逻辑和界面,提高了代码的可维护性和可扩展性。本文介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定和逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种方式,开发者可以构建更加高效和可扩展的桌面应用程序。
107 0
|
2月前
|
前端开发 C# 开发者
WPF开发者必读:MVVM模式实战,轻松构建可维护的应用程序,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离关注点,提高了代码的可维护性和可扩展性。本文详细介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定与逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种模式,开发者可以更高效地构建桌面应用程序。希望本文能帮助你在WPF开发中更好地应用MVVM模式。
110 0
|
2月前
|
C# Windows 开发者
超越选择焦虑:深入解析WinForms、WPF与UWP——谁才是打造顶级.NET桌面应用的终极利器?从开发效率到视觉享受,全面解读三大框架优劣,助你精准匹配项目需求,构建完美桌面应用生态系统
【8月更文挑战第31天】.NET框架为开发者提供了多种桌面应用开发选项,包括WinForms、WPF和UWP。WinForms简单易用,适合快速开发基本应用;WPF提供强大的UI设计工具和丰富的视觉体验,支持XAML,易于实现复杂布局;UWP专为Windows 10设计,支持多设备,充分利用现代硬件特性。本文通过示例代码详细介绍这三种框架的特点,帮助读者根据项目需求做出明智选择。以下是各框架的简单示例代码,便于理解其基本用法。
94 0
|
2月前
|
设计模式 前端开发 C#
WPF/C#:理解与实现WPF中的MVVM模式
WPF/C#:理解与实现WPF中的MVVM模式
110 0
|
2月前
|
开发框架 JSON 前端开发
WPF应用框架中工作流模块的介绍
WPF应用框架中工作流模块的介绍
|
设计模式 开发框架 前端开发
深入理解WPF中MVVM的设计思想
近些年来,随着WPF在生产,制造,工业控制等领域应用越来越广发,很多企业对WPF开发的需求也逐渐增多,使得很多人看到潜在机会,不断从Web,WinForm开发转向了WPF开发,但是WPF开发也有很多新的概念及设计思想,如:数据驱动,数据绑定,依赖属性,命令,控件模板,数据模板,MVVM等,与传统WinForm,ASP.NET WebForm开发,有很大的差异,今天就以一个简单的小例子,简述WPF开发中MVVM设计思想及应用。
96 0