如何从子窗口向MainWindow传递Artikel对象并更新ObservableCollection
新闻站点文章管理程序:子窗口编辑后更新主窗口ObservableCollection的方案
我正在开发一款新闻站点的文章管理程序,支持文章的添加、修改和删除操作。主窗口通过DataGrid展示所有文章,点击添加按钮会打开子窗口编辑新创建的Artikel,点击修改按钮则编辑当前选中的Artikel。请问如何将Artikel对象传回MainWindow,以添加至或修改ObservableCollection?
现有代码问题分析
现有代码中Artikel是引用类型,主窗口传递给子窗口的是对象引用,但当前实现存在冗余和逻辑漏洞:
- 子窗口单独维护
title、category等字段,未直接绑定到Artikel对象,需要手动同步属性 - 添加文章时提前将空对象加入集合,用户取消编辑后无法自动移除
- 使用
Show()无法区分用户是确认还是取消操作
以下是两种优化解决方案:
方案1:利用引用类型特性+数据绑定简化流程
因为Artikel是引用类型,子窗口修改对象属性后,主窗口集合中的对象会自动同步。配合INotifyPropertyChanged实现DataGrid自动刷新,再用ShowDialog()处理用户操作。
1. 给Artikel类实现INotifyPropertyChanged
using System.ComponentModel; using System.Runtime.CompilerServices; public class Artikel : INotifyPropertyChanged { private int _id; private string _title; private object _category; private string _nameJournalist; private bool _mayBePublished; private bool _isPublished; private string _content; private int _length; private DateTime _creationDate; public int id { get => _id; private set { _id = value; OnPropertyChanged(); } } public string title { get => _title; set { _title = value; OnPropertyChanged(); } } public object category { get => _category; set { _category = value; OnPropertyChanged(); } } public string nameJournalist { get => _nameJournalist; set { _nameJournalist = value; OnPropertyChanged(); } } public bool mayBePublished { get => _mayBePublished; set { _mayBePublished = value; OnPropertyChanged(); } } public bool isPublished { get => _isPublished; set { _isPublished = value; OnPropertyChanged(); } } public string content { get => _content; set { _content = value; OnPropertyChanged(); } } public int length { get => _length; set { _length = value; OnPropertyChanged(); } } public DateTime creationDate { get => _creationDate; private set { _creationDate = value; OnPropertyChanged(); } } public Artikel(int id) { this.id = id; this.creationDate = DateTime.Now; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
2. 修改ArtikelVenster,使用数据绑定
移除子窗口中单独维护的字段,直接将Artikel设为数据上下文,实现双向绑定:
public partial class ArtikelVenster : Window { private readonly Artikel _artikel; public ArtikelVenster(Artikel huidigArtikel) { InitializeComponent(); _artikel = huidigArtikel ?? throw new ArgumentNullException(nameof(huidigArtikel)); DataContext = _artikel; LaadData(); CategorieBox.SelectedIndex = 2; } private void Cancel_Click(object sender, RoutedEventArgs e) { DialogResult = false; Close(); } private void LaadData() { IdLabel.Content = _artikel.id; DatumLabel.Content = _artikel.creationDate.ToString(); // 其余控件通过XAML双向绑定自动赋值,示例: // <TextBox x:Name="TitelBox" Text="{Binding title, Mode=TwoWay}"/> } private void Confirm_Click(object sender, RoutedEventArgs e) { _artikel.length = _artikel.content?.Length ?? 0; DialogResult = true; Close(); } }
3. 修改MainWindow的Add/Modify方法
用ShowDialog()判断用户操作,仅在确认后添加对象到集合:
public partial class MainWindow : Window { private int lastIdArtikel = 0; private Artikel currentSelection = null; private ObservableCollection<Artikel> ArtikelDatabase = new ObservableCollection<Artikel>(); private void Add_Click(object sender, RoutedEventArgs e) { Artikel nieuwArtikel = new Artikel(++lastIdArtikel); var artikelVenster = new ArtikelVenster(nieuwArtikel); if (artikelVenster.ShowDialog() == true) { ArtikelDatabase.Add(nieuwArtikel); } } private void Modify_Click(object sender, RoutedEventArgs e) { if (currentSelection == null) { MessageBox.Show("请先选择一篇文章"); return; } var artikelVenster = new ArtikelVenster(currentSelection); artikelVenster.ShowDialog(); // 引用类型自动同步,DataGrid通过INotifyPropertyChanged刷新 } }
方案2:使用自定义事件传递结果
如果需要传递新创建的对象,或不想依赖引用类型特性,可以在子窗口定义自定义事件:
1. 在ArtikelVenster中定义事件
public partial class ArtikelVenster : Window { public event EventHandler<ArtikelEventArgs> ArtikelSaved; private Artikel _artikel; public ArtikelVenster(Artikel huidigArtikel) { InitializeComponent(); _artikel = huidigArtikel; LaadData(); } private void Confirm_Click(object sender, RoutedEventArgs e) { if (_artikel == null) { _artikel = new Artikel(++lastIdArtikel); // 这里可以调整ID生成逻辑 } _artikel.title = TitelBox.Text; _artikel.category = CategorieBox.SelectedItem; _artikel.nameJournalist = NaamJournalistBox.Text; _artikel.mayBePublished = MagGepubliceerdWordenToggle.IsChecked ?? false; _artikel.isPublished = IsGepubliceerdToggle.IsChecked ?? false; _artikel.content = InhoudBox.Selection.Text; _artikel.length = _artikel.content?.Length ?? 0; ArtikelSaved?.Invoke(this, new ArtikelEventArgs(_artikel)); Close(); } } public class ArtikelEventArgs : EventArgs { public Artikel Artikel { get; } public ArtikelEventArgs(Artikel artikel) => Artikel = artikel; }
2. 在MainWindow中订阅事件
private void Add_Click(object sender, RoutedEventArgs e) { ArtikelVenster artikelVenster = new ArtikelVenster(null); artikelVenster.ArtikelSaved += (s, args) => { args.Artikel.id = ++lastIdArtikel; ArtikelDatabase.Add(args.Artikel); }; artikelVenster.Show(); } private void Modify_Click(object sender, RoutedEventArgs e) { if (currentSelection == null) { MessageBox.Show("请先选择一篇文章"); return; } ArtikelVenster artikelVenster = new ArtikelVenster(currentSelection); artikelVenster.ArtikelSaved += (s, args) => { // 若需替换对象,可执行: // ArtikelDatabase.Remove(currentSelection); // ArtikelDatabase.Add(args.Artikel); }; artikelVenster.Show(); }
关键注意事项
ObservableCollection仅在集合增删时通知UI刷新,对象内部属性变化需Artikel实现INotifyPropertyChangedShowDialog()是处理模态窗口操作的标准方式,能明确区分用户确认/取消行为- 数据绑定是WPF推荐的实现方式,可大幅减少手动同步代码
内容的提问来源于stack exchange,提问作者Rembie01
相关产品推荐
相关产品推荐

