2017-02-22 27 views
2

Слишком новое для UWP и MVVM. Я столкнулся с проблемой, которая может показаться очевидной для многих из вас.привязка данных UWP, не работающая с ViewModel

В моем проекте у меня есть 3 папки с именем Views, ViewModels и Models, которые включают в себя некоторые файлы, как показано на рисунке ниже:

Can't upload image yet (reputation):

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

Проблема: Я пытаюсь реализовать MVVM. Я искал часы для статей и видео, но кажется, что я всегда что-то пропускаю. У меня есть привязки в LoginPage.xaml, которые затем изменяю в классе внутри Models/LoginPageModel.cs. У меня есть класс INotifyPropertyChanged в моем LoginPageViewModel.cs, где каждый раз, когда свойство изменяется в моем LoginPageModel.cs, я хочу, чтобы запускался класс INotifyPropertyChanged, который затем изменит свойство в представлении LoginPage.xaml. Ниже у меня есть содержимое этих файлов.

Это образец моего LoginPageModel.cs кода:

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(); 
     } 
    } 
} 

Я не знаю, почему это не работает. Привязки используются не для работы, но теперь во время выполнения это дает мне необработанное исключение, и я думаю, что это связано с тем, что не присваивается значение и private LoginPageModel login объектам, но я не знаю, что. Спасибо всем за ваше время заранее!

Пожалуйста, если вам нужны пояснения по моему вопросу, просто напишите комментарий. Спасибо!

+0

В основном вы создаете новый объект notifyChanges (какое имя для ViewModel ...) и устанавливаете в нем свое свойство, почему вы ожидаете, что пользовательский интерфейс изменится, если у него есть другой экземпляр этого класса, заданного как DataContext? – RTDev

+0

Итак, это входит в мой первоначальный конструктор страницы вместо XAML? И как я могу ссылаться на него в файле ViewModel? – KonKarapas

+0

это один из возможных способов сделать это, в construtor (в файле xaml.cs) создать экземпляр ViewModel, сохранить ссылку на него и установить его как DataContext, теперь, когда вы будете играть со свойствами этого ссылочного объекта, пользовательский интерфейс должен изменить привязку корыта – RTDev

ответ

2

Я пытаюсь реализовать MVVM.

И вы еще не поняли это. Забудьте о Bindings на мгновение, давайте сосредоточимся на архитектуре.

Спускаясь аббревиатуру, вам нужно

  • модели. Он поддерживает вашу бизнес-логику и обычно определяется вашим бэкэнд (база данных). Он не должен зависеть от того, как (следует знать) Views или ViewModels. Легкое приложение UWP может обойтись без слоя модели.

  • a Вид. Это часть XAML, которую нам нравится держать как можно проще, a.o. потому что это труднее проверить.

  • a ViewModel. Цель состоит в том, чтобы обслуживать представление. Он должен содержать свойства и команды, к которым может напрямую привязываться представление. Он делает столько конверсий и агрегации, насколько это возможно, чтобы сохранить свет «Вид». Обычно он использует (0 или более) Модели или Службы.

Учитывая это, не обязательно, чтобы у вас всегда была 1 модель для 1 ViewModel. ViewModel может использовать несколько моделей или ни один.

Понятно, что ваш LoginPageModel.Login() находится не в том месте. Login() должен быть методом (Command) на вашем ViewModel.

Ваша история должна идти, как это:

  1. Я хочу LoginView
  2. Так что мне нужно, чтобы поддержать его с LoginViewModel, реализующий INPC
  3. ViewModel, вероятно, нужно использовать LoginService или UserModel , Но после успешного входа в систему потребуется экземпляр модели. LoginModel не звучит правильно.

Посмотрите на Template10, чтобы начать работу с View, ViewModel и поточной BindableBase.

Вы также можете посмотреть изображение over here для полной (сверху) макета MVVM.

:
+0

Спасибо за отзыв. Пройдет через это. Еще раз спасибо :) – KonKarapas

0

А вот призыв к изменению основного класса:

NotifyChanges notifyChanges = new NotifyChanges();

notifyChanges.LoginUIVisibility = Visibility.Visible;

Вы инстанцирован notifyChanges в файле XAML путем добавления <vm:NotifyChanges/>. И добавьте привязку к StackPanel, используя <StackPanel Visibility="{Binding LoginUIVisibility}">.Но вы создали новый 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> 
+0

Я отредактировал полный пост. Если у вас есть время, пожалуйста, прочитайте с самого начала и попробуйте дать ответ. Спасибо :) – KonKarapas