在MVVM中实现文本框失去焦点事件

3

我想完成一个简单的任务。

需要实现文本框失去焦点功能,当用户输入数据时,一旦填写了一个字段并转到下一个字段,它应该在上一个字段上触发验证功能。

此外,我正在使用MVVM模式。

所以我有这个类

public class data : INotifyPropertyChanged
{

    public string name;
    public string Name
    {
        get
        {
            return name;
        }

        set
        {
            name = value;
            OnPropertyChanged("Name");
        }
    }
    public string firstname;
    public string FirstName
    {
        get
        {
            return firstname;
        }

        set
        {
            firstname = value;
            OnPropertyChanged("FirstName");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            // Raise the PropertyChanged event
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
} 

在 Viewmodel 中,我得到了这个。
data1 = new data() { name = "Eddie Vedder", firstname = "Eddie" }; //this line in initialization 
public data _data1;
public data data1
{
    get { return _data1; }
    set 
    {

        _data1 = value;
        ValidateThis();
        NotifyPropertyChanged(new PropertyChangedEventArgs("data1"));
    }
}

在Xaml中:

<StackPanel Orientation="Horizontal" >
    <Label Width="90" Content="Name" Height="28" HorizontalAlignment="Left" Name="lblName" VerticalAlignment="Top" />
    <TextBox Text="{Binding Path=data1.name, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"   MaxLength="40" TabIndex="2" Height="25" Margin="0,3,0,0" HorizontalAlignment="Left" Name="txtName" VerticalAlignment="Top" Width="200" />
</StackPanel>
<StackPanel Orientation="Horizontal" >
    <Label Width="90" Content="First Name" Height="28" HorizontalAlignment="Left" Name="lblFirstName" VerticalAlignment="Top" />
    <TextBox Text="{Binding  Path=data1.firstname, UpdateSourceTrigger=LostFocus, Mode=TwoWay}" MaxLength="40" TabIndex="3" Name="txtFirstName" Height="25" Margin="0,3,0,0" VerticalAlignment="Top" Width="200" >
    </TextBox>
</StackPanel>

我的绑定正常工作,当我执行它时,它显示默认名称Eddie Vedder。但是在调试它时,它没有进入类数据。


还有没有什么特别的原因,你不想用 System.ComponentModel.DataAnnotations 中的属性在你的视图模型中完成“常规”的方式呢? - Mark Feldman
为什么不在你的XAML绑定中使用ValidatesOnDataErrors=true, UpdateSourceTrigger=LostFocus,以及在你的VM中使用IDataErrorInfo呢? - blindmeis
抱歉回复晚了,大家好,我刚刚上传了我已经完成的部分。 - nostafict
嘿,马克,我想在一个单独的网格中显示自定义错误。 - nostafict
3个回答

16

由于您使用MVVM模式,我假设您已经将某些绑定到视图模型属性,并且它看起来像:

Xaml:
<StackPanel>
    <!--Pay attention on UpdateSourceTrigger-->
    <TextBox Text="{Binding Text, UpdateSourceTrigger=LostFocus}" />
    <TextBox />
</StackPanel>

c#:

C#:
private string _text;
public string Text
{
    get { return _text; }
    set
    {
        _text = value;
        Validate(); // Desired validation
        OnPropertyChanged();
    }
}

如果将UpdateSourceTrigger属性设置为LostFocus,那么当您失去焦点时,属性更改将被触发。


如果我们因其他目的而使用UpdateSourceTrigger=PropertyChanged,该怎么办? - Emir

4

有一篇非常好的文章:MVVM WPF命令

首先创建一个类:DelegateCommand.cs

public class DelegateCommand<T> : System.Windows.Input.ICommand where T : class
{
    private readonly Predicate<T> _canExecute;
    private readonly Action<T> _execute;

    public DelegateCommand(Action<T> execute)
     : this(execute, null)
    {
    }

    public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecute == null)
            return true;

        return _canExecute((T)parameter);
    }

    public void Execute(object parameter)
    {
        _execute((T)parameter);
    }

    public event EventHandler CanExecuteChanged;
    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
            CanExecuteChanged(this, EventArgs.Empty);
    }
}

将委托添加到您的ViewModel中:
  private readonly DelegateCommand<string> _lostFocusCommand;

  public DelegateCommand<string> LostFocusCommand
  {
     get { return _lostFocusCommand; }
  }
  private string _input;
  public string Input
  {
     get { return _input; }
     set
     {
        _input = value;
     }
  }

并在ViewModel的构造函数中初始化它:

// _input will be the property you have with a binding to the textbox control in the view.
// in the canExecute part add the conditions you want to use to check if the lostfocus command will be raised
 _lostFocusCommand = new DelegateCommand<string>(
  (s) => { /* perform some action */
     MessageBox.Show("The lostfocuscommand works!");
  }, //Execute
  (s) => { return !string.IsNullOrEmpty(_input); } //CanExecute
  );

视图: 您需要添加以下命名空间

xmlns:b="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"  

控制

<TextBox Grid.Column="0"
    Text="{Binding Input, UpdateSourceTrigger=PropertyChanged}">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="LostFocus">
            <b:InvokeCommandAction  Command="{Binding LostFocusCommand}" CommandParameter="{Binding Input}"/>
        </b:EventTrigger>
     </b:Interaction.Triggers>
  </TextBox>

2
The name "Interaction" does not exist in the namespace "clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity". - BurnsBA

0

嗯,这种方法有点起作用了。

public class Validate
{
    public static ErrorProperties ep = new ErrorProperties();
    public static bool ValidateThis(string PropertyName, string PropertyValue)
    {
        if (PropertyValue.Length > 10)
        {
            ep.ErrorPropertyName = PropertyName;
            return true;
        }
        return false;
    }
}

public class ErrorProperties
{
    public string ErrorPropertyName { get; set; }
    public string Error { get; set; }
}

public class data : INotifyPropertyChanged
{
    private ObservableCollection<ErrorProperties> _ErrorList = new ObservableCollection<ErrorProperties>();
    public ObservableCollection<ErrorProperties> ErrorList
    {
        get
        {
            return _ErrorList;
        }
        set
        {
            if (_ErrorList != value)
            {
                _ErrorList = value;
                OnPropertyChanged("ErrorList");
            }
        }
    }


    private string _Name;
    public string Name
    {
        get
        {
            return _Name;
        }
        set
        {
            if (_Name != value)
            {
                _Name = value;
                if (Validate.ValidateThis("Name", value))
                    ErrorList.Add(Validate.ep);
                OnPropertyChanged("Name");
            }
        }
    }


    private string _FirstName;
    public string FirstName
    {
        get
        {
            return _FirstName;
        }
        set
        {
            if (_FirstName != value)
            {
                _FirstName = value;
                if (Validate.ValidateThis("FirstName", value))
                    ErrorList.Add(Validate.ep);
                OnPropertyChanged("FirstName");

            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            // Raise the PropertyChanged event
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接