Linking ComboBox with LINQ XML

Excuse me for my poor English, this is not my native language.

I start (starting from 3 days) with WPF and LINQ, as a regular C # user.

Yesterday I tried all day to solve my problems and read several documents, but the error in my code persists.

I pass an XElement to a control that binds its contents, but I have it, but in a ComboBox

Here is the XML XElement:

<racine> <element nom="Element 1"> <rubrique nom="Element 1 - rubrique 1"> <etat valeur="Hors service"> <option valeur="En service" /> <option valeur="Hors service service" /> </etat> <observation>lorem ipsum</observation> </rubrique> <rubrique nom="Element 1 - rubrique 2"> <etat> </etat> <observation>titi toto</observation> </rubrique> </element> <element nom="Element 2"> <rubrique nom="Element 2 - rubrique 1"> <etat valeur="foo"> </etat> <observation>youpi</observation> </rubrique> <rubrique nom="Element 2 - rubrique 2"> <etat valeur="bar"> <option valeur="En service" /> </etat> <observation></observation> </rubrique> </element> </racine> 

Here is my MonControle.xaml.cs code:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Xml.Linq; using System.ComponentModel; using System.Collections.ObjectModel; using System.Collections.Specialized; namespace MonProjet.Controles { /// <summary> /// Logique d'interaction pour MonControle.xaml /// </summary> public partial class MonControle : UserControl { XElement xRacine; ObservableCollection<XElement> xElementsObservable = new ObservableCollection<XElement>(); public MonControle() { InitializeComponent(); DataContext = xElementsObservable; } #region PropriΓ©tΓ© Attribus [Category("Configuration"), Browsable(false), Description("Element XML racine")] public XElement xRacine { get { return xRacine; } set { this.xRacine = value; MajXElementsObservable(); } } #endregion private void MajXElementsObservable() { var requette = from xElements in xRacine.Descendants("element") select (XElement)xElements; xElementsObservable.Clear(); foreach (XElement xElement in requette) { xElementsObservable.Add(xElement); } } } } 

And here is the xaml for MonControle.xaml:

 <UserControl x:Class="MonProjet.Controles.MonControle" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="Auto" Width="Auto"> <!-- http://www.youdev.net/post/2008/09/23/WPF-SplitContainer-2.aspx http://www.youdev.net/post/2009/03/19/WPF-SplitContainer-Part-2.aspx --> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="25*"/> <ColumnDefinition Width="Auto" MinWidth="4"/> <ColumnDefinition Width="75*"/> </Grid.ColumnDefinitions> <DockPanel Grid.Column="0" LastChildFill="True"> <ListBox Name="lbxElements" ItemsSource="{Binding UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Attribute[nom].Value" /> </DockPanel> <GridSplitter Grid.Column="1" ResizeBehavior="PreviousAndNext" Width="4" VerticalAlignment="Stretch"/> <DockPanel Grid.Column="2" LastChildFill="True" DataContext="{Binding Path=SelectedItem.Elements[rubrique], ElementName=lbxElements, UpdateSourceTrigger=PropertyChanged}"> <ListBox ItemsSource="{Binding UpdateSourceTrigger=PropertyChanged}" IsSynchronizedWithCurrentItem="True"> <ListBox.ItemTemplate> <DataTemplate> <GroupBox Header="{Binding Path=Attribute[nom].Value}"> <StackPanel Orientation="Horizontal"> <!-- http://stackoverflow.com/questions/561166/binding-wpf-combobox-to-a-custom-list --> <ComboBox MinWidth="75" IsEditable="True" ItemsSource="{Binding Path=Element[etat].Elements[option], UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Attribute[valeur].Value" SelectedValuePath="Attribute[valeur].Value" SelectedValue="{Binding Path=Element[etat].Element[option].Attribute[valeur].Value}" /> <TextBox MinWidth="150" AcceptsReturn="False" AcceptsTab="False" TextWrapping="NoWrap" Text="{Binding Path=Element[observation].Value, UpdateSourceTrigger=PropertyChanged}" /> </StackPanel> </GroupBox> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </DockPanel> </Grid> </UserControl> 

My questions:

  • When the control load, this is normal, but if I switch the betwen element to the left ListBox, change the ComboBox value ... Try a lot of things, do a lot of test, but it cannot be fixed!

  • It is not possible to enter a value that is not in the list, but I want to be able to do this. In addition, I am doing a lot of test, but I can not solve the problem.

  • And last but not least, I want to raise an event when the ObservableCollection changes to write an XML file, but it is impossible to catch the event ... I tried something like xElementsObservable.CollectionChanged + = new NotifyCollectionChangedEventHandler (XElementsObservable_CollectionChanged); but it does not work ...

Thanks in advance for your help!

+4
source share
1 answer

It was difficult, but I have a solution to all my questions!

here is the solution:

For the first time, the ComboBox XAML should look like this:

 <ComboBox MinWidth="75" IsEditable="True" IsSynchronizedWithCurrentItem="False" ItemsSource="{Binding Path=Element[etat].Elements[option]}" DisplayMemberPath="Attribute[valeur].Value" Text="{Binding Element[etat].Attribute[valeur].Value, UpdateSourceTrigger=PropertyChanged}" /> 

This question of answer 1 and 2: since we focus on the value of the β€œvaleur” attribute of the node that it contains, we can write what we want, even if the value we are writing is not in the collection, and the problem of displaying the node in the ComboBox text has disappeared !

In question 3, my mistake is that I focus on the observed collection!

But the solution is simple, I connected the "Modified" event to the XDocument, which contains all the XElements that I am manipulating here!

So, I put this code in the main window of my software:

  private void InitPerso() { xDoc = XDocument.Load(@"C:\fichier.xml"); xDoc .Changed += new EventHandler<XObjectChangeEventArgs>(XDoc_Changed); } private void XEdls_Changed(object sender, XObjectChangeEventArgs e) { xDoc .Save(@"C:\fichier.xml"); } 

Et voilΓ !

Excuse me for my bad English, hope this helps ...

+3
source

Source: https://habr.com/ru/post/1302504/


All Articles