WPF - 如果更新源,文本框文本不会更新

时间:2011-02-22 07:30:42

标签: mvvm wpf-controls binding prism

我的目标是为用户创建一个登录屏幕,以便在进入应用程序之前登录。 我开始使用PRISM来控制我的模块,视图,视图模型等......

现在我的问题是,我有一个类似于下面的人类:

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

}

你看到的代码是我的人类,我在Josh Smits MVVMFoundation的基础上实现了INotifyPropertyChanged。 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;
        }
    }
}

我的问题是,当我按下重置按钮时,我的viewmodel中的Person属性会更新并通知更改,但我的文本框中的文本不会更新。

我有一个示例模块,它可以工作,我似乎无法找到我的问题。 (http://blog.projectsoftware.ro/2009/09/wpf-login-demo-with-mvvm-pattern-update/

任何人都知道我做错了什么......我将示例转换为4.0并且它仍在工作......它让我疯了,说实话......

提前非常感谢!

1 个答案:

答案 0 :(得分:2)

您的SurName和Name属性中似乎缺少对RaisePropertyChanged(Person.Properties.<Name>);的调用。

更新:
在澄清和第二次看之后,问题似乎是Person中的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_”前缀,因此consts包含属性名称