You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从子窗口向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实现INotifyPropertyChanged
  • ShowDialog()是处理模态窗口操作的标准方式,能明确区分用户确认/取消行为
  • 数据绑定是WPF推荐的实现方式,可大幅减少手动同步代码

内容的提问来源于stack exchange,提问作者Rembie01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:54:17