开发者

WPF - Textbox text doesn't update if source is updated

开发者 https://www.devze.com 2023-02-12 18:57 出处:网络
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...

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

0

精彩评论

暂无评论...
验证码 换一张
取 消