我有一个由属性组成的模型,该模型在我的视图模型中引用。
我正在以编程方式更改Model属性的值(从DB获取数据)。 当这些值发生变化时," 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;
}
答案 0 :(得分:1)
当然是null
。
UserModel
中有MainWindowVM
属性,但您没有在任何地方初始化它(至少在您粘贴的代码中没有)。
视图模型代码中应该有UserModel = new User(/* arguments */);
。
答案 1 :(得分: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
}
是的,这意味着任何需要在UI中编辑并且还需要响应底层视图模型中的更改的字段必须在视图和视图模型层中重复。有一些方法可以自动将其添加到模型层,但它通常需要对模型和/或数据库层进行特定于实现的修改,因此我不会在此处介绍它。
所有这一点要点是视图模型正是如此:视图的逻辑表示,它提供INPC供视图使用。如果您希望代码修改模型,并且希望该更改反映在视图中,则必须通过视图模型执行此操作,以便更改传播。