WPF - текстовое поле не обновляется, если источник обновлен - PullRequest
0 голосов
/ 22 февраля 2011

Моя цель состоит в том, чтобы создать экран входа для моих пользователей, чтобы войти в него до входа в приложение.Я начал использовать PRISM для управления моими модулями, представлениями, моделями представления и т. Д. *

Теперь моя проблема в том, что у меня есть класс person, который выглядит следующим образом:

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

}

КодВы видите, что есть мой класс person, я реализую INotifyPropertyChanged на основе Josh Smits MVVMFoundation.INotifyPropertyChanged захватывается в DeletableSupport.Этот класс делает так, что если я удаляю и возражаю в моем БД, флаг удаленного просто устанавливается в true, вместо того, чтобы удалять его постоянно.

Другой код для DB4O - объектная база данных.

Следующий код взят из моей 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
        {
            _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;
    }
}

И наконец, мой 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 выглядит так:

 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;
        }
    }
}

Моя проблема в том, что когда я нажимаю кнопку сброса, мое свойство Person в моей viewmodel обновляется и уведомляет об изменении, но текст в моем текстовом поле не обновляется.

У меня есть пример модуля, где он делаетработать, и я не могу найти свою проблему.(http://blog.projectsoftware.ro/2009/09/wpf-login-demo-with-mvvm-pattern-update/)

Кто-нибудь знает, что я делаю неправильно ... Я преобразовал пример в 4.0, и он все еще работает .. Это сводит меня с ума, если честно ...

Большое спасибо заранее!

1 Ответ

2 голосов
/ 22 февраля 2011

Похоже, вы пропускаете вызов RaisePropertyChanged(Person.Properties.<Name>); в своих свойствах SurName и Name.

Обновление:
После выяснения и повторного просмотра проблема, похоже, связана с классом Properties внутриЧеловек.Должно быть так:

public class Properties
{
    public const string Name = "Name";
    public const string SurName = "SurName";
    public const string Alias = "Alias";
    public const string Password = "Password";
}

Я удалил префикс «Person_», чтобы в консистентах были точно имена свойств

...