使用 LINQ XML 绑定 ComboBox

Posted

技术标签:

【中文标题】使用 LINQ XML 绑定 ComboBox【英文标题】:Binding ComboBox with LINQ XML 【发布时间】:2011-01-21 12:55:44 【问题描述】:

对不起,我的英语很差,那不是我的母语。

我是 WPF 和 LINQ 的初学者(从 3 天开始),并且是 C# 的临时用户。

昨天,我整天都在努力解决我的问题并阅读了几个文档,但我的代码中的一个错误仍然存​​在。

我将 XElement 传递给绑定其内容的控件,但我有一个但在 ComboBox 中

这是 XElement 的 XML:

<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>

这是我的控件 MonControle.xaml.cs 背后的代码:

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);
            
        

    

这里是 MonControle.xaml 的 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://***.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>

我的问题是:

控件加载的时候还可以,但是 如果我在元素之间切换 left ListBox,ComboBox的值 改变...尝试很多事情,做很多事情 测试,但不可能修复它!

无法输入没有的值 在列表中,但我想要 能够做到。同样,我做了很多 测试,但我无法解决问题

最后但同样重要的是:我想升职 ObservableCollection 时的事件 更改为写入 XML 文件, 但不可能赶上一个事件...... 我试过类似的东西 xElementsObservable.CollectionChanged += 新的 NotifyCollectionChangedEventHandler(XElementsObservable_CollectionChanged); 但它不起作用......

提前感谢您的帮助!

【问题讨论】:

【参考方案1】:

这很难,但我有解决我所有问题的方法!

这里是解决方案:

第一时间,ComboBox XAML 必须如下所示:

<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"
          />

这个回答问题1和2:当我们关注包含的节点的属性“valeur”的值时,我们可以写我们想要的,即使我们写的值不在集合中,并且, ComboBox文本中节点显示的问题解决了!

对于问题 3,我的错误是我专注于可观察的集合!

但是,解决方案很简单,我在 XDocument 上附加了一个“已更改”事件,其中包含我在此处操作的所有 XElement!

所以,我把这段代码放在我软件的主窗口中:

  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");
    

等等!

对不起,我的英语不好,我希望这会有所帮助......

【讨论】:

以上是关于使用 LINQ XML 绑定 ComboBox的主要内容,如果未能解决你的问题,请参考以下文章

绑定列表和 LINQ?

使用 Linq (asp.net) 绑定 Gridview 数据源

需要使用 LINQ 将 WPF 对象绑定到列表框的简单示例

如何使用 System.Xml.Linq 解析 xml 文件

Linq操作XML生成XML,实体生成XML和互转

将 System.Xml.Linq 与单声道命令行编译器一起使用