“级联"绑定到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.