WPF 绑定到 属性 列表未更新
WPF Binding to property list not updating
求助。我用 google 和 Whosebug 搜索栏搜索了一个星期,但没有找到我的答案。
所以我有一个名为 Student 的 class,属性是字符串名称、字符串地址、DoB 出生日期和列表分数。以及学生 class 的 ViewModel class。
public partial class StudentWindow : Window
{
public class DoB
{
public int Day { get; set; }
public int Month { get; set; }
public int Year { get; set; }
public DoB(int day, int month, int year)
{
Day = day;
Month = month;
Year = year;
}
public override string ToString()
{
return Day + "/" + Month + "/" + Year;
}
}
public class Student
{
public string Name { get; set; }
public string Address { get; set; }
public DoB DateOfBirth { get; set; }
public List<int> Score { get; set; }
}
public class ViewModel : INotifyPropertyChanged
{
private Student entry;
public event PropertyChangedEventHandler PropertyChanged;
public void Notify(string Property)
{
PropertyChanged(this, new PropertyChangedEventArgs(Property));
}
public string Name
{
get { return entry.Name; }
set { entry.Name = value; Notify("Name"); }
}
public string Address
{
get { return entry.Address; }
set { entry.Address = value; Notify("Address"); }
}
public string DateOfBirth
{
get { return entry.DateOfBirth.ToString(); }
set
{
var p = value.Split('/');
int d = 1, m = 1, y = 1;
bool pass = int.TryParse(p[0], out d) && int.TryParse(p[1], out m) && int.TryParse(p[2], out y);
if (pass)
{
entry.DateOfBirth = new DoB(d, m, y);
Notify("DateOfBirth");
}
else
throw new InvalidCastException();
}
}
public List<string> Score
{
get { return entry.Score.Select(sc => "" + sc).ToList(); }
set { entry.Score = value.Select(va => int.Parse(va)).ToList(); Notify("Score"); }
}
public ViewModel(Student entry)
{
this.entry = entry;
}
}
public ObservableCollection<ViewModel> entry { get; set; }
public StudentWindow()
{
InitializeComponent();
entry = new ObservableCollection<ViewModel>();
entry.Add(new ViewModel(new Student() { Name = "First People", Address = "Earth", DateOfBirth = new DoB(13, 11, 1996), Score = new List<int>(new int[] { 100, 90, 100, 90 }) }));
entry.Add(new ViewModel(new Student() { Name = "Second People", Address = "Moon", DateOfBirth = new DoB(13, 11, 1995), Score = new List<int>(new int[] { 90, 80, 100, 100 }) }));
DataContext = this;
}
}
而 XAML 是
<Grid>
<DataGrid x:Name="dataGridStudent" ItemsSource="{Binding entry}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="210" Width="572"/>
<DataGrid x:Name="dataGridStudentScore" ItemsSource="{Binding ElementName=dataGrid, Path=SelectedItem.Score}" HorizontalAlignment="Left" Margin="10,242,0,0" VerticalAlignment="Top" Height="218" Width="572" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
dataGridStudent 一切正常。
但dataGridStudentScore 只显示数值,无法编辑数值。我必须设置绑定路径=。 ,否则将抛出 Path 或 Xpath 异常。
请帮助解决您的任何问题。我是这里的新手,请告诉我我的方法是否有问题。提前致谢。
忽略对MVVM架构的混淆理解。
学生分数不可编辑的原因是您尝试将值类型变量绑定到 DataGridTextColumn。我不确定 DependencyProperty 绑定的后台实现,但我想没有引用可以绑定到以执行更新,因为它只是一个值类型变量。
我也不是 wpf 的期望,但我会在下面实现同样的事情。
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Score : ViewModelBase
{
public int Value { get; set; }
}
public class Student : ViewModelBase
{
public string Name { get; private set; }
public string Address { get; private set; }
public DateTime Dob { get; private set; }
public ObservableCollection<Score> Scores { get; set; }
public Student(string name, string address, DateTime dob)
{
Name = name;
Address = address;
Dob = dob;
Scores = new ObservableCollection<Score>();
}
}
public class StudentViewModel : ViewModelBase
{
public ObservableCollection<Student> Students { get; private set; }
public StudentViewModel()
{
Students = new ObservableCollection<Student>
{
new Student("Student A", "A Address", DateTime.Now)
{
Scores = new ObservableCollection<Score>
{
new Score { Value = 80 },
new Score { Value = 85 },
new Score { Value = 90 },
}
},
new Student("Student B", "B Address", DateTime.Now)
{
Scores = new ObservableCollection<Score>
{
new Score { Value = 70 },
new Score { Value = 75 },
new Score { Value = 60 },
}
}
};
}
private Student _selectedStudent;
public Student SelectedStudent
{
get { return _selectedStudent; }
set
{
_selectedStudent = value;
OnPropertyChanged("SelectedStudentScores");
}
}
public ObservableCollection<Score> SelectedStudentScores
{
get
{
if (_selectedStudent == null) return null;
return _selectedStudent.Scores;
}
}
public Score SelectedScore { get; set; }
}
<Window x:Class="StudentScoreWpfProj.MainWindow"
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:studentScoreWpfProj="clr-namespace:StudentScoreWpfProj"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=studentScoreWpfProj:StudentViewModel,IsDesignTimeCreatable=True}"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding Students}" AutoGenerateColumns="False"
SelectedItem="{Binding SelectedStudent}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name, Mode=OneWay}" />
<DataGridTextColumn Header="Address" Binding="{Binding Address, Mode=OneWay}" />
<DataGridTextColumn Header="Birth" Binding="{Binding Dob, Mode=OneWay, StringFormat={}{0:MM/dd/yyyy}}" />
</DataGrid.Columns>
</DataGrid>
<DataGrid Grid.Row="1" ItemsSource="{Binding SelectedStudentScores}"
SelectedItem="{Binding SelectedScore}">
</DataGrid>
</Grid>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = new StudentViewModel();
}
}
求助。我用 google 和 Whosebug 搜索栏搜索了一个星期,但没有找到我的答案。
所以我有一个名为 Student 的 class,属性是字符串名称、字符串地址、DoB 出生日期和列表分数。以及学生 class 的 ViewModel class。
public partial class StudentWindow : Window
{
public class DoB
{
public int Day { get; set; }
public int Month { get; set; }
public int Year { get; set; }
public DoB(int day, int month, int year)
{
Day = day;
Month = month;
Year = year;
}
public override string ToString()
{
return Day + "/" + Month + "/" + Year;
}
}
public class Student
{
public string Name { get; set; }
public string Address { get; set; }
public DoB DateOfBirth { get; set; }
public List<int> Score { get; set; }
}
public class ViewModel : INotifyPropertyChanged
{
private Student entry;
public event PropertyChangedEventHandler PropertyChanged;
public void Notify(string Property)
{
PropertyChanged(this, new PropertyChangedEventArgs(Property));
}
public string Name
{
get { return entry.Name; }
set { entry.Name = value; Notify("Name"); }
}
public string Address
{
get { return entry.Address; }
set { entry.Address = value; Notify("Address"); }
}
public string DateOfBirth
{
get { return entry.DateOfBirth.ToString(); }
set
{
var p = value.Split('/');
int d = 1, m = 1, y = 1;
bool pass = int.TryParse(p[0], out d) && int.TryParse(p[1], out m) && int.TryParse(p[2], out y);
if (pass)
{
entry.DateOfBirth = new DoB(d, m, y);
Notify("DateOfBirth");
}
else
throw new InvalidCastException();
}
}
public List<string> Score
{
get { return entry.Score.Select(sc => "" + sc).ToList(); }
set { entry.Score = value.Select(va => int.Parse(va)).ToList(); Notify("Score"); }
}
public ViewModel(Student entry)
{
this.entry = entry;
}
}
public ObservableCollection<ViewModel> entry { get; set; }
public StudentWindow()
{
InitializeComponent();
entry = new ObservableCollection<ViewModel>();
entry.Add(new ViewModel(new Student() { Name = "First People", Address = "Earth", DateOfBirth = new DoB(13, 11, 1996), Score = new List<int>(new int[] { 100, 90, 100, 90 }) }));
entry.Add(new ViewModel(new Student() { Name = "Second People", Address = "Moon", DateOfBirth = new DoB(13, 11, 1995), Score = new List<int>(new int[] { 90, 80, 100, 100 }) }));
DataContext = this;
}
}
而 XAML 是
<Grid>
<DataGrid x:Name="dataGridStudent" ItemsSource="{Binding entry}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="210" Width="572"/>
<DataGrid x:Name="dataGridStudentScore" ItemsSource="{Binding ElementName=dataGrid, Path=SelectedItem.Score}" HorizontalAlignment="Left" Margin="10,242,0,0" VerticalAlignment="Top" Height="218" Width="572" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
dataGridStudent 一切正常。
但dataGridStudentScore 只显示数值,无法编辑数值。我必须设置绑定路径=。 ,否则将抛出 Path 或 Xpath 异常。
请帮助解决您的任何问题。我是这里的新手,请告诉我我的方法是否有问题。提前致谢。
忽略对MVVM架构的混淆理解。 学生分数不可编辑的原因是您尝试将值类型变量绑定到 DataGridTextColumn。我不确定 DependencyProperty 绑定的后台实现,但我想没有引用可以绑定到以执行更新,因为它只是一个值类型变量。
我也不是 wpf 的期望,但我会在下面实现同样的事情。
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Score : ViewModelBase
{
public int Value { get; set; }
}
public class Student : ViewModelBase
{
public string Name { get; private set; }
public string Address { get; private set; }
public DateTime Dob { get; private set; }
public ObservableCollection<Score> Scores { get; set; }
public Student(string name, string address, DateTime dob)
{
Name = name;
Address = address;
Dob = dob;
Scores = new ObservableCollection<Score>();
}
}
public class StudentViewModel : ViewModelBase
{
public ObservableCollection<Student> Students { get; private set; }
public StudentViewModel()
{
Students = new ObservableCollection<Student>
{
new Student("Student A", "A Address", DateTime.Now)
{
Scores = new ObservableCollection<Score>
{
new Score { Value = 80 },
new Score { Value = 85 },
new Score { Value = 90 },
}
},
new Student("Student B", "B Address", DateTime.Now)
{
Scores = new ObservableCollection<Score>
{
new Score { Value = 70 },
new Score { Value = 75 },
new Score { Value = 60 },
}
}
};
}
private Student _selectedStudent;
public Student SelectedStudent
{
get { return _selectedStudent; }
set
{
_selectedStudent = value;
OnPropertyChanged("SelectedStudentScores");
}
}
public ObservableCollection<Score> SelectedStudentScores
{
get
{
if (_selectedStudent == null) return null;
return _selectedStudent.Scores;
}
}
public Score SelectedScore { get; set; }
}
<Window x:Class="StudentScoreWpfProj.MainWindow"
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:studentScoreWpfProj="clr-namespace:StudentScoreWpfProj"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=studentScoreWpfProj:StudentViewModel,IsDesignTimeCreatable=True}"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding Students}" AutoGenerateColumns="False"
SelectedItem="{Binding SelectedStudent}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name, Mode=OneWay}" />
<DataGridTextColumn Header="Address" Binding="{Binding Address, Mode=OneWay}" />
<DataGridTextColumn Header="Birth" Binding="{Binding Dob, Mode=OneWay, StringFormat={}{0:MM/dd/yyyy}}" />
</DataGrid.Columns>
</DataGrid>
<DataGrid Grid.Row="1" ItemsSource="{Binding SelectedStudentScores}"
SelectedItem="{Binding SelectedScore}">
</DataGrid>
</Grid>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = new StudentViewModel();
}
}