2016-03-07 145 views
0

我有一个由属性组成的模型,该模型在我的视图模型中被引用。模型在视图模型中为null

我正在以编程方式更改模型属性的值(从数据库中获取数据)。 更改这些值后,会按照预期在模型内触发“OnPropertyChanged”事件。

但是,我的观点并没有被更新这些更改。

调试我的视图模型显示模型为空。

对于MVVM来说很新,并且已经遵循了一段时间的教程,但似乎无法弄清楚这一点。

我的代码如下(省略不相关部分)

型号

class User : INotifyPropertyChanged 
{ 
    private int _ID; 
    private string _FirstName; 
    private string _SurName; 
    private string _Email; 
    private string _ContactNo; 

    public string FirstName 
    { 
     get 
     { 
      return _FirstName; 
     } 
     set 
     { 
      _FirstName = value; 
      OnPropertyChanged("FirstName"); 
     } 
    } 


    #region INotifyPropertyChanged Members 
    private event PropertyChangedEventHandler PropertyChangedEvent; 

    public event PropertyChangedEventHandler PropertyChanged 
    { 
     add { PropertyChangedEvent += value; } 
     remove { PropertyChangedEvent -= value; } 
    } 


    protected void OnPropertyChanged(string prop) 
    { 
     if (PropertyChangedEvent != null) 
      PropertyChangedEvent(this, new PropertyChangedEventArgs(prop)); 
    } 

    #endregion 
} 

视图模型(不认为我需要改变性质的东西在这里,但把它放在反正只是在情况下)

class MainWindowVM : INotifyPropertyChanged 
{ 
    public User UserModel { get; set; } 

    public MainWindowVM() 
    { 
     var test = UserModel.FirstName; 

    } 


    #region INotifyPropertyChanged Members 
    private event PropertyChangedEventHandler PropertyChangedEvent; 

    public event PropertyChangedEventHandler PropertyChanged 
    { 
     add { PropertyChangedEvent += value; } 
     remove { PropertyChangedEvent -= value; } 
    } 


    protected void OnPropertyChanged(string prop) 
    { 
     if (PropertyChangedEvent != null) 
      PropertyChangedEvent(this, new PropertyChangedEventArgs(prop)); 
    } 

    #endregion 

} 

查看

<Window x:Class="ProjectName.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:vm="clr-namespace:ProjectName.ViewModels"> 


    <Window.DataContext> 
     <vm:MainWindowVM/> 
    </Window.DataContext> 


    <Grid Style="{DynamicResource ResourceKey=MainGrid}"> 
     <Label Content="Logged in as:" HorizontalAlignment="Right" VerticalAlignment="Top" Padding="0,0,200,0"/> 
     <Label Content="{Binding Path=UserModel.FirstName}" HorizontalAlignment="Right" VerticalAlignment="Top" Padding="0,0,150,0"/> 
    </Grid> 
</Window> 

用户模型这里

public bool Login(string email, string password) 
    { 

     var userOb = new Models.User(); // new instance of user object 

     using (SqlConnection con = new SqlConnection(FactoryManager.Properties.Resources.ConnectionString)) 
     { 
      using (SqlCommand cmd = new SqlCommand("usp_login", con)) 
      { 
       cmd.CommandType = CommandType.StoredProcedure; 

       cmd.Parameters.Add("@email", SqlDbType.VarChar).Value = email; 

       con.Open(); 
       cmd.ExecuteNonQuery(); 

       SqlDataReader dr = cmd.ExecuteReader(); 

       if (dr.HasRows) 
       { 

        string dbHash = null; 
        while (dr.Read()) 
        { 
         dbHash = dr[1].ToString(); // get db hash value from reader 
        } 

        // if password hash matched DB then log in 
        if (Encryption.ValidatePassword(password, dbHash)) 
        { 
         con.Close(); 
         GetUser(userOb, email); // gets the current user 
         return true; // logged in 
        } 
        else 
        { 
         return false; 
        } 

       } 
       else 
       { 
        return false; //invalid login 
       } 

      } 
     } 

    } 

    // gets the logged in user and populates the user object, returns this 
    public Models.User GetUser(Models.User userOb, string email) 
    { 
     using (SqlConnection con = new SqlConnection(FactoryManager.Properties.Resources.ConnectionString)) 
     { 
      using (SqlCommand cmd = new SqlCommand("usp_getUser", con)) 
      { 
       cmd.CommandType = CommandType.StoredProcedure; 

       cmd.Parameters.Add("@email", SqlDbType.VarChar).Value = email; 

       con.Open(); 
       cmd.ExecuteNonQuery(); 

       SqlDataReader dr = cmd.ExecuteReader(); 

       if (dr.HasRows) 
       { 

        while (dr.Read()) 
        { 

         userOb.ID = Int32.Parse(dr[0].ToString()); 
         userOb.FirstName = dr[1].ToString(); 
         userOb.SurName = dr[2].ToString(); 
         userOb.Email = dr[3].ToString(); 
         userOb.ContactNo = dr[4].ToString(); 
         //Password = dr[4].ToString(); 
         //loginAttempts = dr[5].ToString(); 
        } 

        // GET ALLOCATED LINES AND POPULATE THE OBJECT 

       } 
       else 
       { 
        return null; //invalid login 
       } 

      } 
     } 

     return userOb; 
    } 

回答

1

当然,设置它的null

您在MainWindowVM中拥有UserModel属性,但不会在任何地方初始化它(至少不会在您粘贴的代码中)。

视图模型代码中应该有一个UserModel = new User(/* arguments */);

+0

但是,然后在VM中初始化新模型将重置所有属性,在显示视图之前更新属性 – DNKROZ

+0

您在哪里设置UserModel属性?你可以把它粘贴到你的文章中吗?通常这些是通过构造函数注入,属性注入,在视图模型本身(例如服务调用)中简单地从视图模型新增的位置(这里不是这种情况)设置的。这些现在想起来了。我在这里没有看到这些。 –

+0

更新我的问题..对不起任何不相关的代码 – DNKROZ

0

UserModel不支持INPC本身,因此更改它不会更新视图。您还将INPC添加到您的模型中,它通常不属于它。

说实话,我认为你需要拿出几本有关MVVM是如何工作的书,但我会尽量给出一些初步的指导。你MainViewModel需要这样的事:

private UserViewModel _User; 
    public UserViewModel User 
    { 
     get { return this._User; } 
     set { this._User = value; RaisePropertyChanged(); } 
    } 

您的用户类通常会来自你的数据层,所以它一般不会做INPC,特别是如果你正在做的代码优先发展:

public class User 
{ 
    public int ID { get; set; } 
    public string FirstName { get; set; } 
    public string SurName { get; set; } 
    public string Email { get; set; } 
    public string ContactNo { get; set; } 
} 

(*这有例外,但现在让我们保持简单)。

您的视图模型是构成视图和视图模型之间的绑定的东西两者之间的胶,所以这样的:

public class UserViewModel 
{ 
    private User Model; 

    public UserViewModel(User model) 
    { 
     this.Model = model; 
    } 

    public int ID 
    { 
     get { return this.Model.ID; } 
     set { this.Model.ID = value; RaisePropertyChanged(); } 
    } 

    public string FirstName 
    { 
     get { return this.Model.FirstName; } 
     set { this.Model.FirstName = value; RaisePropertyChanged(); } 
    } 

    // etc 
} 

是的,这意味着需要在两个在编辑的任何字段您的用户界面以及需要响应底层视图模型中的更改都必须在视图和视图模型图层中进行复制。有许多方法可以将它自动添加到模型层,但通常需要对模型和/或数据库图层进行特定于实现的修改,所以我不会在这里介绍它。

要从这一切中获得的一点是,视图模型正是:视图的逻辑表示,它提供INPC供视图使用。如果您希望代码修改模型,并且希望将该更改反映到视图中,则必须通过视图模型执行此操作,以便更改传播。

+0

可以定义INPC? –

+0

@RichardJune [INotifyPropertyChanged](https://msdn.microsoft.com/en-us/library/ms229614%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396),如果您使用的是lib像MVVM Lite,它将在基本视图模型类中为您完成,否则您必须自己添加它。无论哪种方式,您都必须在属性设置者中自己提出更改的事件。 –