My goal is to create a loginscreen for my users to log in to before entering the application. I started using PRISM to control my modules, view, viewmodels, etc...
Now my problem is, i have a person class that looks like the folowing:
public class Person : DeletableSupport, IObserver, IDataErrorInfo, IActivatable
{
public class Properties
{
public const string Name = "Person_Name";
public const string SurName = "Person_SurName";
public const string Alias = "Person_Alias";
public const string Password = "Person_Password";
}
//TODO Add Rights bitarray type of thing
//TODO add IObserver stuff
private string _Name;
private string _SurName;
private string _Alias;
private string _Password;
private NotificationList _nList;
private ReminderList _rList;
private ProjectList _pList;
private DayPoolList _dpList;
private EventList _eList;
private ActivityList _aList;
[Transient]
private IActivator _activator;
#region Get/Set
public string Name
{
get
{
Activate(ActivationPurpose.Read);
return this._Name;
}
set
{
if (this._Name != value)
{
Activate(ActivationPurpose.Write);
this._Name = value;
}
}
}
public string Password
{
get
{
Activate(ActivationPurpose.Read);
return this._Password;
}
set
{
if (this._Password != value)
{
Activate(ActivationPurpose.Write);
this._Password = value;
RaisePropertyChanged(Person.Properties.Password);
}
}
}
public string SurName
{
get
{
Activate(ActivationPurpose.Read);
return this._SurName;
}
set
{
if (this._SurName != value)
{
Activate(ActivationPurpose.Write);
this._SurName = value;
}
}
}
public string Alias
{
get
{
Activate(ActivationPurpose.Read);
return this._Alias;
}
set
{
if (this._Alias != value)
{
Activate(ActivationPurpose.Write);
this._Alias = value;
RaisePropertyChanged(Person.Properties.Alias);
}
}
}
#endregion
public Person()
{
this._aList = new ActivityList();
this._dpList = new DayPoolList();
this._eList = new EventList();
this._nList = new NotificationList();
this._pList = new ProjectList();
this._rList = new ReminderList();
}
#region ListObjects
public ActivityList getActivityList()
{
Activate(ActivationPurpose.Read);
return this._aList;
}
public DayPoolList getDayPoolList()
{
Activate(ActivationPurpose.Read);
return this._dpList;
}
public EventList getEventList()
{
Activate(ActivationPurpose.Read);
return this._eList;
}
public NotificationList getNotificationList()
{
Activate(ActivationPurpose.Read);
return this._nList;
}
public ProjectList getProjectList()
{
Activate(ActivationPurpose.Read);
return this._pList;
}
public ReminderList getReminderList()
{
Activate(ActivationPurpose.Read);
return this._rList;
}
public ObservableCollectionEx<Activity> ActivityList
{
get
{
Activate(ActivationPurpose.Read);
return this._aList.getObsCollection();
}
set
{
if (this._aList.getObsCollection() != value)
{
Activate(ActivationPurpose.Write);
this._aList.setObsCollection(value);
}
}
}
public ObservableCollectionEx<Day> DayPoolList
{
get
{
Activate(ActivationPurpose.Read);
return this._dpList.getObsCollection();
}
set
{
if (this._dpList.getObsCollection() != value)
{
Activate(ActivationPurpose.Write);
this._dpList.setObsCollection(value);
}
}
}
public ObservableCollectionEx<Event> EventList
{
get
{
Activate(ActivationPurpose.Read);
return this._eList.getObsCollection();
}
set
{
if (this._eList.getObsCollection() != value)
{
Activate(ActivationPurpose.Write);
this._eList.setObsCollection(value);
}
}
}
public ObservableCollectionEx<Notification> NotificationList
{
get
{
Activate(ActivationPurpose.Read);
return this._nList.getObsCollection();
}
set
{
if (this._nList.getObsCollection() != value)
{
Activate(ActivationPurpose.Write);
this._nList.setObsCollection(value);
}
}
}
public ObservableCollectionEx<Project> ProjectList
{
get
{
Activate(ActivationPurpose.Read);
return this._pList.getObsCollection();
}
set
{
if (this._pList.getObsCollection() != value)
{
Activate(ActivationPurpose.Write);
this._pList.setObsCollection(value);
}
}
}
public ObservableCollectionEx<Reminder> ReminderList
{
get
{
Activate(ActivationPurpose.Read);
return this._rList.getObsCollection();
}
set
{
if (this._rList.getObsCollection() != value)
{
Activate(ActivationPurpose.Write);
this._rList.setObsCollection(value);
}
}
}
#endregion
#region IDataErrorInfo Members
private string m_error = string.Empty;
public string Error
{
set
{
m_error = value;
}
get
{
return m_error;
}
}
public string this[string columnName]
{
get
{
if (columnName == "Alias")
{
if (string.IsNullOrEmpty(Alias))
{
m_error = "Username cannot be empty";
return "Username cannot be empty";
}
}
if (columnName == "Password")
{
if (string.IsNullOrEmpty(Password))
{
m_error = "Password cannot be empty";
return "Password cannot be empty";
}
}
return "";
}
}
#endregion
public void Notify(object o, ObservedItem oType)
{
switch (oType)
{
case ObservedItem.oiNotification:
this._nList.Add((Notification)o);
break;
case ObservedItem.oiReminder:
this._rList.Add((Reminder)o);
break;
default:
break;
}
}
#region IActivatable Members
public void Activate(ActivationPurpose purpose)
{
if (_activator != null)
{
_activator.Activate(purpose);
}
}
public void Bind(IActivator activator)
{
if (_activator == activator)
{
return;
}
if (activator != null && null != _activator)
{
throw new System.InvalidOperationException();
}
_activator = activator;
}
#endregion
}
The code you see there is my person class, I implements INotifyPropertyChanged on basis of Josh Smits MVVMFoundation. The INotifyPropertyChanged is captured into the DeletableSupport. This class makes it so that if i delete and object in my db, the deleted flag is just set to true, instead of deleting it permantly.
The other code is for DB4O an object-database.
The following code is from my ViewModel:
public class LoginViewModel : ObservableObject
{
public LoginViewModel(Person person)
{
this.Person = person;
this.LoginCommand = new DelegateCommand<Person>(OnLoginExecuted, CanLoginExecute);
this.ResetCommand = new DelegateCommand<Person>(OnResetExecuted);
this.NewPersonCommand = new DelegateCommand<Person>(OnNewUserExecuted);
this.Person.PropertyChanged += new PropertyChangedEventHandler(LoginViewModel_PersonPropertyChanged);
}
void LoginViewModel_PersonPropertyChanged(object sender, PropertyChangedEventArgs e)
{
//Check after model change if command can be executed
((DelegateCommand<Person>)this.LoginCommand).RaiseCanExecuteChanged();
}
#region Get/Set
public ICommand LoginCommand
{
get;
set;
}
public ICommand ResetCommand
{
get;
set;
}
public ICommand NewPersonCommand
{
get;
set;
}
private Person _person;
public Person Person
{
get
{
return _person;
}
set
开发者_如何学JAVA {
_person = value;
RaisePropertyChanged("Login_Person");
}
}
private string _error = "";
public string Error
{
get
{
return this._error;
}
set
{
this._error = value;
RaisePropertyChanged("Login_Error");
}
}
#endregion
void OnNewUserExecuted(Person p)
{
//Goto new user screen
}
void OnLoginExecuted(Person person)
{
if (person.Password != "Test" && person.Alias != "tce")
{
this.Error = "Incorrect login";
}
else
{
this.Error = "";
}
}
bool CanLoginExecute(Person person)
{
return this.Person.Alias != "" && this.Person.Password != "";
}
void OnResetExecuted(Person p)
{
p.Alias = string.Empty;
p.Password = string.Empty;
}
}
And the finaly my XAML.
<UserControl x:Class="GTV.Modules.Views.LoginView.View.LoginView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:GTV.Modules.Views.LoginView.View"
mc:Ignorable="d">
<Grid Name="MainGrid" Margin="5">
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="5" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="5"/>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right" Foreground="Red"
FontSize="14" FontWeight="Bold">!</TextBlock>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder></AdornedElementPlaceholder>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Target="{Binding ElementName=Alias}" >
_Username:
</Label>
<TextBox Grid.Row="0" Grid.Column="1"
Name="Alias"
Text="{Binding Path=Person.Alias, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,ValidatesOnDataErrors=True}"/>
<Label Grid.Row="1" Grid.Column="0" Target="{Binding ElementName=Password}" >
_Password:
</Label>
<TextBox Grid.Row="1" Grid.Column="1"
Name="Password"
Text="{Binding Path=Person.Password,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,ValidatesOnDataErrors=True}"/>
<TextBlock Grid.ColumnSpan="2" Grid.Row="4" Text="{Binding Path=Error,Mode=TwoWay}" Foreground="Red"></TextBlock>
<Button Command="{Binding Path=LoginCommand}"
CommandParameter="{Binding Path=Person}"
Grid.Column="0" Grid.Row="2"
>Login</Button>
<Button Command="{Binding Path=ResetCommand}"
CommandParameter="{Binding Path=Person}"
Grid.Column="1" Grid.Row="2"
>Reset</Button>
<Button Command="{Binding Path=NewPersonCommand}"
Grid.Column="1" Grid.Row="3"
>New user</Button>
</Grid>
</Border>
</Grid></UserControl>
XAML.cs looks like this:
public partial class LoginView : UserControl, IView
{
public LoginView()
{
InitializeComponent();
MainGrid.DataContext = new LoginViewModel(new Person()
{
Alias = "Enter username",
Password = "123"
});
;
}
public LoginViewModel ViewModel
{
get
{
return this.DataContext as LoginViewModel;
}
}
}
My problem is that when i press the reset button, my Person property in my viewmodel gets updated and notifies the change, but the text in my textbox doens't update.
I have an example module where it does work and i can't seem to find my problem. ( http://blog.projectsoftware.ro/2009/09/wpf-login-demo-with-mvvm-pattern-update/ )
Anybody any clue what i'm doing wrong... I converted the example to 4.0 and it is still working.. it drives me insane to be honest...
Big thanks in advance!
It looks like you are missing a call to RaisePropertyChanged(Person.Properties.<Name>);
in both your SurName and Name properties.
Update:
After clarification and a second look, the problem seems to be the Properties class inside Person. It has to be like this:
public class Properties
{
public const string Name = "Name";
public const string SurName = "SurName";
public const string Alias = "Alias";
public const string Password = "Password";
}
I removed the "Person_" prefix, so the consts contain exactly the properties names
精彩评论