2016-03-07 198 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,它將在基本視圖模型類中爲您完成,否則您必須自己添加它。無論哪種方式,您都必須在屬性設置者中自己提出更改的事件。 –