当需要在xaml中绑定至数组中的某个元素时,常规写法不利于阅读理解,因为你必须得知道这个元素在集合中的位置才能进行绑定。下面以班级中学生的名字为例:
比如我想绑定至A班学号为1的学生的名字
常规写法:(前提是你得知道这个学生在集合中的第一个位置)
<TextBlock Text="{Binding Path=(local:Students.StuClassList)[0].StudentList[0].Name}" Width="100" Height="30"/>
想用自定义写法实现:
<TextBlock Text="{ local:StudentBinding A.1.Name}" Width="100" Height="30"/>
班级类:
public class StuClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _classId;
public string ClassID
{
get { return _classId; }
set
{
_classId = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ClassID"));
}
}
private ObservableCollection<Student> _studentList = new ObservableCollection<Student>();
public ObservableCollection<Student> StudentList
{
get { return _studentList; }
set { _studentList = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("StudentList"));
}
}
}
学生类:
public static class Students
{
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
private static ObservableCollection<Student> _student = new ObservableCollection<Student>();
public static ObservableCollection<Student> StudentList
{
get { return _student; }
set
{
_student = value;
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs("StudentList"));
}
}
private static ObservableCollection<StuClass> _stuClassesList = new ObservableCollection<StuClass>();
public static ObservableCollection<StuClass> StuClassList
{
get { return _stuClassesList; }
set { _stuClassesList = value;
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs("StuClassList"));
}
}
}
静态全局班级集合:
public static class Students
{
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
private static ObservableCollection<StuClass> _stuClassesList = new ObservableCollection<StuClass>();
public static ObservableCollection<StuClass> StuClassList
{
get { return _stuClassesList; }
set
{
_stuClassesList = value;
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs("StuClassList"));
}
}
}
自定义绑定标记:
public class StudentBinding : MarkupExtension
{
public string Path;
public StudentBinding()
{
}
public StudentBinding(string path)
{
Path = path;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var result = Path.Split('.');
StuClass stuclass = Students.StuClassList.Single(s => s.ClassID == result[0]) as StuClass;
Student stu = stuclass.StudentList.Single(s => s.ID == int.Parse(result[1])) as Student;
Binding binding = new Binding();
binding.Source = stu;
binding.Path = new PropertyPath(result[2]);
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.NotifyOnSourceUpdated = true;
binding.NotifyOnTargetUpdated = true;
return binding.ProvideValue(serviceProvider);
}
}
在窗体构造函数中添加班级和学生:
public MainWindow()
{
StuClass stuClass = new StuClass();
stuClass.ClassID = "A";
stuClass.StudentList.Add(new Student()
{
ID = 1,
Name = "可莉"
});
stuClass.StudentList.Add(new Student()
{
ID = 2,
Name = "派蒙"
});
stuClass.StudentList.Add(new Student()
{
ID = 3,
Name = "七七"
});
stuClass.StudentList.Add(new Student()
{
ID = 4,
Name = "早柚"
});
Students.StuClassList.Add(stuClass);
InitializeComponent();
}
xaml:
<Grid>
<StackPanel VerticalAlignment="Center">
<TextBox Text="{ local:StudentBinding A.1.Name}" Width="100" Height="30"/>
<TextBlock Text="{ local:StudentBinding A.2.Name}" Width="100" Height="30"/>
<TextBlock Text="{Binding Path=(local:Students.StuClassList)[0].StudentList[0].Name}" Width="100" Height="30"/>
<Button Content="change" Width="60" Height="30" Click="Button_Click"/>
</StackPanel>
</Grid>
效果:
属性变动通知测试:
前台改变数据:
后台改变数据:
private void Button_Click(object sender, RoutedEventArgs e)
{
Students.StuClassList[0].StudentList[0].Name = "宵宫";
}