UWP数据绑定无法与ViewModel配合使用

3
我对UWP和MVVM还比较陌生,遇到了一个问题,可能对你们中的许多人来说很显然。
在我的项目中,我有3个文件夹,分别命名为ViewsViewModelsModels,其中包括一些文件,如下图所示: 目前还不能上传图片(声望不够):

http://i.imgur.com/42f5KeT.png

The problem: 我正在尝试实现MVVM。我已经花了几个小时查找文章和视频,但似乎总是缺少某些东西。我在LoginPage.xaml中有一些绑定,然后在Models/LoginPageModel.cs类中进行修改。我在我的LoginPageViewModel.cs中有一个INotifyPropertyChanged类,在LoginPageModel.cs中每次属性更改时,我希望INotifyPropertyChanged类触发,然后更改LoginPage.xaml视图中的属性。下面是这些文件的内容。
This is a sample of my LoginPageModel.cs code:
using System;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace App_Name.Models
{
    class LoginPageModel
    {
        private NotifyChanges notify;

        public async void LogIn()
        {
            if (something is true)
                notify.LoginUIVisibility = Visibility.Visible;
        }
    }
}

这是我的 LoginPageViewModel.cs 文件:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using Windows.UI.Xaml;

namespace App_Name.ViewModels
{
    public class NotifyChanges : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private Visibility loginUIVisibility = Visibility.Collapsed;

        public Visibility LoginUIVisibility
        {
            get
            {
                return loginUIVisibility;
            }

            set
            {
                if (value != loginUIVisibility)
                {
                    loginUIVisibility = value;
                    NotifyPropertyChanged("LoginUIVisibility");
                }
            }
        }
    }
}

这里是一个LoginPage.xaml的示例:

<Page
    x:Class="App_Name.LoginPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App_Name"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="using:App_Name.ViewModels"
    mc:Ignorable="d">

    <Page.DataContext>
        <vm:NotifyChanges/>
    </Page.DataContext>

    <StackPanel Visibility="{Binding LoginUIVisibility}">

这是我的 LoginPage.xaml.cs 文件:

namespace App_Name
{
    public sealed partial class LoginPage : Page
    {
        private LoginPageModel login;
        public LoginPage()
        {
            InitializeComponent();
            login.LogIn();
        }
    }
}

我不知道为什么这不起作用。绑定以前不起作用,但现在在运行时它给了我一个未处理的异常,我认为这与没有为私有的NotifyChanges notify和private LoginPageModel login对象分配任何值有关,但我不知道具体是什么原因。提前感谢大家的时间!如果您需要澄清我的问题,请写下评论。谢谢!

你基本上是在创建一个新的notifyChanges对象(ViewModel的命名真是有点...)并在其中设置你的属性,如果UI有不同的此类实例作为DataContext,你为什么期望它会改变呢? - RTDev
这个应该放在我的初始页面构造函数里,而不是XAML中?那么我在ViewModel文件中如何引用它? - KonKarapas
如果所有内容都在同一个文件中,它将正常工作。我的问题是DataContext = new NotifyChanges(); 发生在我的 XAML.cs 文件中,而 NotifyChanges() 类和我修改这些属性的类位于不同的文件中。不同的文件:两个类,一个是 NotifyChanges,另一个是修改发生的类。再次提问,如何在同一文件中从 NotifyChanges 类引用那些属性到上面的类,而不需要创建新实例?谢谢 :) - KonKarapas
DataContext = new NotifyChanges(); 在上面未命名样例中的神秘控件的构造函数xaml.cs文件中,然后在您的其他对象中,您需要引用ViewModel(您只需要更改其属性)或您的控件(xaml.cs)实例 - 如果是这样,请获取它的DataContext(例如,var viewModel = sampleControl.DataContext as NotifyChanges;),并玩弄它的属性,提示:首先阅读有关MVVM中的View first和ViewModel first方法。 - RTDev
在你的绑定中,尝试以双向模式绑定数据上下文。类似这样:<StackPanel Visibility="{Binding LoginUIVisibility,Mode=TwoWay}"> - Mohanvel V
显示剩余6条评论
2个回答

5
我正在尝试实现MVVM,但还没有做对。先不要考虑绑定,让我们专注于架构。按照首字母缩写,您需要以下三个部分:
- 模型(Model)。它支持您的业务逻辑,并通常由后端(数据库)定义。它不应依赖于视图(Views)或视图模型(ViewModels)。轻量级的UWP应用可以没有模型层。 - 视图(View)。这是XAML部分,我们希望保持尽可能简单,原因之一是它最难测试。 - 视图模型(ViewModel)。它的目的是为视图服务。它应该包含视图可以直接绑定到的属性和命令。它尽可能多地进行转换和聚合,以保持视图轻量化。它通常依赖于0个或多个模型或服务。
鉴于此,您并不总是需要为1个ViewModel拥有1个模型。一个ViewModel可以使用多个模型,也可以不使用任何模型。很明显,您的“LoginPageModel.Login()”放错了地方。“Login()”应该是视图模型上的一个方法(Command)。
你的故事应该是这样的:
  1. 我想要一个LoginView
  2. 所以我需要使用实现INPC的LoginViewModel来支持它
  3. ViewModel可能需要使用LoginService或UserModel。但只有在成功登录后,它才需要一个Model实例。 LoginModel听起来不太对。

查看Template10以开始使用View、ViewModel和线程安全的BindableBase。

你也可以查看over here的图片,了解MVVM的完整(甚至过度)布局。


0
这里是主类中更改的调用:
NotifyChanges notifyChanges = new NotifyChanges(); notifyChanges.LoginUIVisibility = Visibility.Visible;
你已经在XAML文件中实例化了notifyChanges,通过添加。并且使用将绑定添加到StackPanel。但是你创建了一个新的notifyChanges,并没有将新的notifyChanges绑定到StackPanel。所以它不起作用。你可以像下面的代码一样初始化viewModel。
MainPage
private LoginViewModel viewModel;

public MainPage()
 {
     this.InitializeComponent();
     viewModel = this.DataContext as LoginViewModel;
 }

 private void showDetail_Click(object sender, RoutedEventArgs e)
 {
     viewModel.LoginUIVisibility = Visibility.Visible;
 }
 

MainPage.xaml

<Page.DataContext>
    <vm:LoginViewModel />
</Page.DataContext>
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button x:Name="loginButon" Content="Login" Visibility="{Binding LoginUIVisibility}" />
    <Button x:Name="showDetail" Content="Show" Click="showDetail_Click" />
</StackPanel>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接