【发布时间】:2018-01-14 16:58:20
【问题描述】:
我有一个带有 Master-Detail 视图的项目,其中 Master 部分包含一个用于选择对象的列表,Detail 部分显示该对象的细节并允许对其进行编辑。
我的问题是我不能允许 2 个对象具有相同的名称,虽然这听起来很容易,但事实证明我知道的验证过程并不能很好地发挥作用。
这是一个简短的例子。
XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:WpfApplication1="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<ListView Grid.Column="0" ItemsSource="{Binding Path=People, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" Name="masterList"
DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedPerson}" />
<StackPanel Grid.Column="1" Margin="5" DataContext="{Binding Path=SelectedPerson}">
<TextBlock>Name</TextBlock>
<TextBox>
<TextBox.Text>
<Binding Path="Name" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True">
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock>Address</TextBlock>
<TextBox Text="{Binding Path=Address}" />
<TextBlock>Phone</TextBlock>
<TextBox Text="{Binding Path=Phone}" />
</StackPanel>
</Grid>
</Window>
人物类
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class Person {
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
}
RegisteredPeople 类
public class RegisteredPeople {
public ObservableCollection<Person> People { get; set; }
public Person SelectedPerson { get; set; }
public RegisteredPeople() {
People = new ObservableCollection<Person>() {
new Person() {Name = "Ramzi", Address = "A1", Phone = "1"},
new Person() {Name = "Frank", Address = "A2", Phone = "12"},
new Person() {Name = "Ihab", Address = "A3", Phone = "123"}
};
}
}
这没有任何验证,但它显示了我想要的基本机制。
我尝试在两个类上实现IDataErrorInfo,但没有成功:
Person 类的其他实现
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class Person : System.ComponentModel.IDataErrorInfo, INotifyPropertyChanged {
private string m_name;
public string Name {
get { return m_name; }
set {
m_name = value;
OnPropertyChanged();
OnPropertyChanged("People"); //Name of the list that the master list is bound to.
}
}
public string Address { get; set; }
public string Phone { get; set; }
public string this[string columnName] {
get {
switch (columnName) {
case "Name":
if (string.IsNullOrEmpty(Name)) {
/** This one works, but from here I cannot compare with names of other Person objects. **/
return "The name cannot be empty.";
}
break;
default:
return string.Empty;
}
return String.Empty;
}
}
public string Error { get; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
RegisteredPeople 类的其他实现
public class RegisteredPeople : System.ComponentModel.IDataErrorInfo {
public ObservableCollection<Person> People { get; set; }
public Person SelectedPerson { get; set; }
public RegisteredPeople() {
People = new ObservableCollection<Person>() {
new Person() {Name = "Ramzi", Address = "A1", Phone = "1"},
new Person() {Name = "Frank", Address = "A2", Phone = "12"},
new Person() {Name = "Ihab", Address = "A3", Phone = "123"}
};
}
public string this[string columnName] {
get {
switch (columnName) {
case "People":
foreach (Person person1 in People) {
foreach (Person person2 in People) {
if (person1 == person2) {
continue;
}
if (person1.Name == person2.Name) {
return "Error, 2 people cannot have the same name.";
}
}
}
break;
default:
return string.Empty;
}
return string.Empty;
}
}
public string Error { get; }
}
我也尝试过使用ValidationRule 界面,但没有成功。
这是我尝试过的:
XAML
我将名称的文本框替换为:
<TextBox>
<TextBox.Text>
<Binding Path="Name" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True">
<Binding.ValidationRules>
<WpfApplication1:EventNameValidationRule EventList="{Binding ElementName=masterList, Path=ItemsSource}" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
EventNameValidationRule
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows.Controls;
class EventNameValidationRule : ValidationRule {
public ObservableCollection<Person> EventList { get; set; }
public override ValidationResult Validate(object value, CultureInfo cultureInfo) {
return new ValidationResult(false, "Duplicate names are not allowd.");
}
}
问题是这样抛出异常,说明绑定到EventList 不好。 (如果没有这份清单,我显然没有比较的起点。)
我的问题:当有两个人叫同一个名字时,如何将这个名字标记为无效?
【问题讨论】:
-
也许您应该告诉我们您对 ValidationRule 的尝试。对我来说,使用 ValidationRule 似乎是可行的方法。您可以尝试将您的列表绑定到 ValidationRule(如何做到这一点:dedjo.blogspot.de/2007/05/fully-binded-validation-by-using.html),然后,当调用 Validate 方法时,只需检查您绑定到 ValidationRule 的列表,如果它包含多个带有给定的名字。
-
感谢@Dr.Coconut 查看我的编辑。
标签: c# wpf xaml master-detail