“级联"绑定到ObservableCollection,包含其他ObservableCollection

问题描述:

我有一个项目,我需要在其中显示合同清单(Affaire类). 每个合同都有一个阶段列表(Class Phase). 我使用绑定将它们分别显示在2个不同的ListView中. 问题是,当我从ListView中删除一个Phase时,也没有在ListView所在的位置显示Phases时,也没有更新我的ObjectCollection时.

I have a project where I need to display a list of contract (Class Affaire). Each contract has a list of phases (Class Phase). I display each of them in 2 different ListView using binding. Problem is when I remove a Phase from ListView, nor the ListView where are displayed Phases, nor my ObjectCollection are updated.

我用两个不同的ObservableCollection创建了一个上下文:

I created a context with two distinct ObservableCollection :

ObservableCollection,其中是Affaire的列表. ObservableCollection是所选Affaire中存在的阶段的列表

ObservableCollection, where is the list of Affaire. ObservableCollection that are list of phases present in selected Affaire

我的上下文如下:

public class Contexte : INotifyPropertyChanged
    {
        private Affaire selectedAffaire;
        private Phase selectedPhase;
        private Assemblage selectedAssemblage;
        public Affaire SelectedAffaire
        {
            get { return selectedAffaire; }
            set
            {
                selectedAffaire = value;
                this.NotifyPropertyChanged("SelectedAffaire");
            }
        }
        public Phase SelectedPhase
        {
            get { return selectedPhase; }
            set
            {
                selectedPhase = value;
                this.NotifyPropertyChanged("SelectedPhase");
            }
        }
        public Assemblage SelectedAssemblage
        {
            get { return selectedAssemblage; }
            set
            {
                selectedAssemblage = value;
                this.NotifyPropertyChanged("SelectedAssemblage");
            }
        }
        private ObservableCollection<Affaire> listeDesAffaires;
        public ObservableCollection<Affaire> ListeDesAffaires
        {
            get { return listeDesAffaires; }
            set { NotifyPropertyChanged(ref listeDesAffaires, value); }
        }
        /**************************************************/

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string nomPropriete)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(nomPropriete));
        }

        private bool NotifyPropertyChanged<T>(ref T variable, T valeur, [CallerMemberName] string nomPropriete = null)
        {
            if (object.Equals(variable, valeur)) return false;

            variable = valeur;
            NotifyPropertyChanged(nomPropriete);
            return true;
        }

    }

我的班级事务:

public class Affaire : INotifyPropertyChanged
    {
        public long ID { get; set; }
        private string nom;
        public string Nom
        {
            get { return this.nom; }
            set
            {
                if (this.nom != value)
                {
                    this.nom = value;
                    this.NotifyPropertyChanged("Nom");
                }
            }
        }
        private string code;
        public string Code
        {
            get { return this.code; }
            set
            {
                if (this.code != value)
                {
                    this.code = value;
                    this.NotifyPropertyChanged("Code");
                }
            }
        }
        private string comm;
        public string Comm
        {
            get { return this.comm; }
            set
            {
                if (this.comm != value)
                {
                    this.comm = value;
                    this.NotifyPropertyChanged("Comm");
                }
            }
        }
        private ObservableCollection<Phase> listPhases;
        public ObservableCollection<Phase> ListPhases {
            get { return listPhases; }
            set
            {
                listPhases = value;
                if (PropertyChanged != null)
                {
                    NotifyPropertyChanged("ListPhases");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string propName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    ....
    }

我的课堂阶段:

public class Phase : INotifyPropertyChanged
    {
        private string nomPhase;
        public string NomPhase
        {
            get { return this.nomPhase; }
            set
            {
                if (this.nomPhase != value)
                {
                    this.nomPhase = value;
                    this.NotifyPropertyChanged("NomPhase");
                }
            }
        }
        private int priorite;
        public int Priorite
        {
            get { return this.priorite; }
            set
            {
                if (this.priorite != value)
                {
                    this.priorite = value;
                    this.NotifyPropertyChanged("Priorite");
                }
            }
        }
        private string commPhase;
        public string CommPhase
        {
            get { return this.commPhase; }
            set
            {
                if (this.commPhase != value)
                {
                    this.commPhase = value;
                    this.NotifyPropertyChanged("CommPhase");
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string propName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
        public long IdAffaire { get; set; }
        public long ID { get; set; }
        private ObservableCollection<Assemblage> listAssemblages;
        public ObservableCollection<Assemblage> ListAssemblages
        {
            get { return listAssemblages; }
            set
            {
                listAssemblages = value;
                if (PropertyChanged != null)
                {
                    NotifyPropertyChanged("ListAssemblages");
                }
            }
        }
    ...
    }

1)当我双击合同(在ListView1中)时,我在ListView2中显示其阶段列表,我将执行以下操作:

1) When I doubleclick on a contract(in ListView1), I display in ListView2 list of its phases, I do the following :

contexte.SelectedAffaire = (Affaire)ListView1.SelectedItem;
contexte.SelectedAffaire.getListPhases();
afficherListview("2");

2)当我编辑阶段时,所有视图在我的视图以及ObservableCollection中都正确更新了

2) When I edit my Phase, all is updated correctly in my view, and also in my ObservableCollection

3)对于添加/删除新的阶段,所有步骤都已解决.

3) For adding/removing a new Phase, all is solved.

Netstep给出的示例可以很好地工作,但是我仍然遇到一个问题:

Example given by Netstep works perfectly but I still meet an issue :

我有一个第三级"Assembly",这是"Phase"类中的一个ObservableCollection,使用四个ListView导航时没有问题,但是当我想做其他事情时遇到了一个问题:当我正确时,单击阶段"的标题,我想在程序集"列表中显示Affaire中包含的所有程序集的列表,而不对阶段"进行过滤. 为此,我执行以下操作:我在三级listview程序集上,右键单击Phase标题,事件如下:

I have a third level "Assembly", this is an ObservableCollection in class "Phase", I have no problem to navigate with the four ListViews, but I meet a problem when I want to make something else : When I right-click on the header of "Phase", I want to display in the list of Assembly, the list of all assemblies contained in Affaire, without filtering on Phase. For this I do the following : I am on the 3rd level listview Assemblies, I make right click on Phase header and event is as following :

Phase ph = new Phase();
                ph.IdAffaire = contexte.SelectedAffaire.ID;
                ph.ListAssemblages = new ObservableCollection<Assemblage>(contexte.SelectedAffaire.getListAssemblages(true));
                contexte.SelectedPhase = ph;

我捣蛋"了一个新的空白阶段,只是将一个ObservableCollection放在里面,然后将ObservableCollection绑定到我的ListView3. 那部分代码很好用...我只是在代码中的某个地方刷新了上下文,却忘了它,确保出价有问题...全部解决了,谢谢

I "shit" a bit making a new empty phase, just to put an ObservableCollection inside and bind the ObservableCollection to my ListView3. Edit : That part of code works good... I just refreshed the context somewhere in my code and forgot about it, sure that there was something wrong in biding... All solved thanks

以下是根据您的来源处理所有内容的示例. 视图模型:

Here is the example, based on your source, that will handle all stuff. a View Models:

使用System.Collections.ObjectModel; 使用System.ComponentModel;

using System.Collections.ObjectModel; using System.ComponentModel;

命名空间WpfApp2 { 公共类BaseViewModel:INotifyPropertyChanged { 公共事件PropertyChangedEventHandler PropertyChanged;

namespace WpfApp2 { public class BaseViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string nomPropriete)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(nomPropriete));
    }
}

public class Contexte : BaseViewModel
{
    private Affaire _selectedAffaire;
    private Phase _selectedPhase;
    public ObservableCollection<Affaire> ListeDesAffaires { get; set; }

    public Affaire SelectedAffaire
    {
        get { return _selectedAffaire; }
        set
        {
            _selectedAffaire = value;
            this.NotifyPropertyChanged("SelectedAffaire");
        }
    }

    public Phase SelectedPhase
    {
        get { return _selectedPhase; }
        set
        {
            _selectedPhase = value;
            this.NotifyPropertyChanged("SelectedPhase");
        }
    }

    public Contexte()
    {
        ListeDesAffaires = new ObservableCollection<Affaire>
        {
            new Affaire("Affaire1"),
            new Affaire("Affaire2")
        };
    }
}

public class Affaire : BaseViewModel
{
    private string nom;
    public string Nom
    {
        get { return this.nom; }
        set
        {
            this.nom = value;
            this.NotifyPropertyChanged("Nom");
        }
    }

    public ObservableCollection<Phase> ListPhases { get; set; }

    public Affaire(string n)
    {
        nom = n;
        ListPhases = new ObservableCollection<Phase>
        {
            new Phase { NomPhase = nom + "_Phase1" },
            new Phase { NomPhase = nom + "_Phase2" }
        };
    }
}

public class Phase : BaseViewModel
{
    private string nomPhase;
    public string NomPhase
    {
        get { return this.nomPhase; }
        set
        {
            this.nomPhase = value;
            this.NotifyPropertyChanged("NomPhase");
        }
    }

    public ObservableCollection<Assemblage> ListAssemblages { get; set; }
}

public class Assemblage : BaseViewModel
{
    private string nom;
    public string Nom
    {
        get { return this.nom; }
        set
        {
            this.nom = value;
            this.NotifyPropertyChanged("Nom");
        }
    }

}

}

MainWindow.xaml:

a MainWindow.xaml:

<Window x:Class="WpfApp2.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:local="clr-namespace:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:Contexte x:Name="Contexte" d:IsDataSource="True" />
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <ListBox ItemsSource="{Binding ListeDesAffaires}" DisplayMemberPath="Nom" SelectedItem="{Binding SelectedAffaire}"/>
        <ListBox Grid.Column="1" ItemsSource="{Binding SelectedAffaire.ListPhases}" DisplayMemberPath="NomPhase" />
        <Button Grid.Column="2" VerticalAlignment="Top" Click="FillClick">Fill</Button>
        <ListBox Grid.Column="2" ItemsSource="{Binding SelectedPhase.ListAssemblages}" DisplayMemberPath="Nom" Margin="0,20,0,0"/>
    </Grid>
</Window>

还有您问题中的一些代码(MainWindow.xaml.cs):

And some code from your question (MainWindow.xaml.cs):

using System.Collections.ObjectModel;
using System.Windows;

namespace WpfApp2
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void FillClick(object sender, RoutedEventArgs e)
        {
            Phase ph = new Phase();
            ph.NomPhase = "SomeId";
            ph.ListAssemblages = new ObservableCollection<Assemblage>()
            {
                new Assemblage { Nom =  "Assemblage1" },
                new Assemblage { Nom =  "Assemblage2" }
            };
            Contexte.SelectedPhase = ph;
        }
    }
}

结果如下:

这是您可以扩展的基本示例.它处理所有字段修改和添加/删除"对象并在屏幕上显示. MainWindow.xaml.cs中没有其他代码.请问问题(如果有的话).

This is basic sample that you can extend. It handles all field modification and Add/Remove objects and displays on screen. There is no additional code in MainWindow.xaml.cs. Please ask questions, if any.