【问题标题】:Binding Generic Xml to Datagrid将通用 XML 绑定到 Datagrid
【发布时间】:2016-06-01 08:20:28
【问题描述】:

我有一组 xml 文件。 文件总是这样构建的:

<?xml version="1.0" encoding="UTF-8"?>
<Data>
  <Row>
    <halfproducten ID="105">Digitale bestanden van papieren zeekaarten en 1800 serie</halfproducten>
    <formaat ID="106">PDF, PS, SHAPE, CARIS NTX/ASCII*, GEOTIFF, S57*</formaat>
    <datum_validiteit ID="107">Meest recente editie</datum_validiteit>
    <geografische_grenzen ID="108">Karteringsgebied</geografische_grenzen>
  </Row>
  <Row>
    <halfproducten ID="109">Fragmenten van bovengenoemde bestanden</halfproducten>
    <formaat ID="110">PDF, PS, SHAPE, CARIS NTX/ASCII*, GEOTIFF, S57*</formaat>
    <datum_validiteit ID="111">Meest recente editie</datum_validiteit>
    <geografische_grenzen ID="112">Karteringsgebied</geografische_grenzen>
  </Row>
  <Row>
    <halfproducten ID="113">Minuutbladen</halfproducten>
    <formaat ID="114">Papier</formaat>
    <datum_validiteit ID="115">
    </datum_validiteit>
    <geografische_grenzen ID="116">Karteringsgebied</geografische_grenzen>
  </Row>
  <Row>
    <halfproducten ID="117">Tracings</halfproducten>
    <formaat ID="118">PDF</formaat>
    <datum_validiteit ID="119">Meest recent</datum_validiteit>
    <geografische_grenzen ID="120">Karteringsgebied</geografische_grenzen>
  </Row>
  <Row>
    <halfproducten ID="121">Bathymetrie-bestanden</halfproducten>
    <formaat ID="122">ASCII, x-y-z (20 x 20)</formaat>
    <datum_validiteit ID="123">Meest recent</datum_validiteit>
    <geografische_grenzen ID="124">Karteringsgebied</geografische_grenzen>
  </Row>
  <Row>
    <halfproducten ID="125">Object-selecties data bestanden:;Wrakken/Obstructies;Lichten;Boorplatforms/Boorputten;Boeien/Bakens</halfproducten>
    <formaat ID="126">Papier, ASCII, HOB, S57, SHAPE, GEOTIFF, GML</formaat>
    <datum_validiteit ID="127">Actueel</datum_validiteit>
    <geografische_grenzen ID="128">Nederlands Continentaal Plat + Territoriale zee</geografische_grenzen>
  </Row>
  <Row>
    <halfproducten ID="129">Maritieme (zone)grenzen (UNCLOS)</halfproducten>
    <formaat ID="130">ASCII, SHAPE, KML</formaat>
    <datum_validiteit ID="131">Actueel</datum_validiteit>
    <geografische_grenzen ID="132">Continentaal Plat + Territoriale zee van Nederland, het Caraibisch deel van het Koninkrijk der Nederlanden</geografische_grenzen>
  </Row>
</Data>

这里数据和行元素总是存在的,标签元素总是不同的标签名,标签的数量总是不同的。 只有 Row 元素都有相同的子元素,只是内部文本不同。

我想将此 xml 文件绑定到我的 DataGrid,以便如果 DataGrid 中的某些内容发生更改,它会在 xml 文件中自动更改。

到目前为止,我有这个:

<Grid.DataContext>
<XmlDataProvider x:Name="xmlDataProvider"/>
</Grid.DataContext> 

(我的 DataGrid 在 Grid 中)

<DataGrid AutoGenerateColumns="True" Name="DataGridXml" SelectionMode="Extended"
SelectionUnit="CellOrRowHeader" CanUserSortColumns="False"
CanUserReorderColumns="False" CanUserAddRows="False" CanUserDeleteRows="False"
VirtualizingStackPanel.IsVirtualizing="False" ItemsSource="{Binding}">

代码隐藏:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(path);
XmlDataProvider dataProvider = xmlDataProvider;
dataProvider.Document = xmlDoc;
dataProvider.XPath = "Data/Row";

使用以上所有代码,我的解决方案都可以工作,它还绑定到我的数据网格,只是它绑定到 Xml-Element 的属性,而不是将标签绑定到列。

所以说清楚,我想要的是这个:

__________________________________________
|     Tag1    |    Tag2     |    Tag3     |
|-------------|-------------|-------------|
|Lerum Ipsum11|Lerum Ipsum12|Lerum Ipsum13|
|-------------|-------------|-------------|
|Lerum Ipsum21|Lerum Ipsum22|Lerum Ipsum23|
|-------------|-------------|-------------|

提前感谢您帮助我;)

【问题讨论】:

  • 使用数据集:DataSet ds = new DataSet(); ds.ReadXml(路径); dataProvider dataProvider = ds.Tables[0];
  • 我试试,谢谢!

标签: c# xml wpf binding datagrid


【解决方案1】:

使用DataGird 列定义如:

<DataGrid AutoGenerateColumns="False"  Name="DataGridXml" SelectionMode="Extended" DataContext="{Binding dataProvider}"
            SelectionUnit="CellOrRowHeader" CanUserSortColumns="False"
            CanUserReorderColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" 
            VirtualizingStackPanel.IsVirtualizing="False" ItemsSource="{Binding XPath=/Data/Row}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Tag1" Binding="{Binding XPath=tag1/.}" />
        <DataGridTextColumn Header="Tag2" Binding="{Binding XPath=tag2/.}" />
        <DataGridTextColumn Header="Tag3" Binding="{Binding XPath=tag3/.}" />
    </DataGrid.Columns>

</DataGrid>

输出:

PS:我还更改了 DataContext 赋值和 AutoGenerateColumn 属性。并将dataProvider 设为property,这是您代码中的方法变量。

更新:如果想从XML生成DataGridColumns

XMAL:

<DataGrid AutoGenerateColumns="False"  Name="DataGridXml" SelectionMode="Extended" DataContext="{Binding dataProvider}"
        SelectionUnit="CellOrRowHeader" CanUserSortColumns="False"
        CanUserReorderColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" 
        VirtualizingStackPanel.IsVirtualizing="False" ItemsSource="{Binding}"
        local:XMLToColumn.GenerateColumnForGrid="True"/>

附加行为:

public class XMLToColumn
{
    public static bool GetGenerateColumnForGrid(DependencyObject obj)
    {
        return (bool)obj.GetValue(GenerateColumnForGridProperty);
    }

    public static void SetGenerateColumnForGrid(DependencyObject obj, bool value)
    {
        obj.SetValue(GenerateColumnForGridProperty, value);
    }

    // Using a DependencyProperty as the backing store for GenerateColumnForGrid.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty GenerateColumnForGridProperty =
        DependencyProperty.RegisterAttached("GenerateColumnForGrid", typeof(bool), typeof(XMLToColumn), new PropertyMetadata(GenerateColumnForGridChanged));

    public static void GenerateColumnForGridChanged(DependencyObject DO, DependencyPropertyChangedEventArgs e)
    {
        var dataGrid = DO as DataGrid;
        if (dataGrid != null && Convert.ToBoolean(e.NewValue) == true)
        {
            dataGrid.Loaded += dataGrid_Loaded;
        }
    }

    static void dataGrid_Loaded(object sender, RoutedEventArgs e)
    {
        var dataGrid = sender as DataGrid;
        if (dataGrid != null)
        {
            dataGrid.Columns.Clear();
            var dataprovider = dataGrid.DataContext as XmlDataProvider;
            if (dataprovider != null)
            {
                var mainNode = dataprovider.Document.SelectSingleNode(dataprovider.XPath);
                foreach (var item in mainNode.ChildNodes)
                {
                    var node=item as XmlNode;
                    var column = new DataGridTextColumn();
                    column.Binding = new Binding() { XPath = node.Name+"/." };
                    column.Header = node.Name;
                    dataGrid.Columns.Add(column);
                }
            }
        }
    }

}

输出:

ID 问题更新:

public class XMLToColumn
{
    public static bool GetGenerateColumnForGrid(DependencyObject obj)
    {
        return (bool)obj.GetValue(GenerateColumnForGridProperty);
    }

    public static void SetGenerateColumnForGrid(DependencyObject obj, bool value)
    {
        obj.SetValue(GenerateColumnForGridProperty, value);
    }

    // Using a DependencyProperty as the backing store for GenerateColumnForGrid.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty GenerateColumnForGridProperty =
        DependencyProperty.RegisterAttached("GenerateColumnForGrid", typeof(bool), typeof(XMLToColumn), new PropertyMetadata(GenerateColumnForGridChanged));

    public static void GenerateColumnForGridChanged(DependencyObject DO, DependencyPropertyChangedEventArgs e)
    {
        var dataGrid = DO as DataGrid;
        if (dataGrid != null && Convert.ToBoolean(e.NewValue) == true)
        {
            dataGrid.Loaded += dataGrid_Loaded;               
            dataGrid.RowEditEnding += new EventHandler<DataGridRowEditEndingEventArgs>(dataGrid_RowEditEnding);
        }
    }

    static void dataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
    {
         var dataGrid = sender as DataGrid;
         if (dataGrid != null)
         {                 
             var dataprovider = dataGrid.DataContext as XmlDataProvider;
             if (dataprovider != null)
             {
                 if (e.Row.GetIndex() == dataGrid.Items.Count - 1)
                 {
                     int maxID = Convert.ToInt32(dataprovider.Document.LastChild.LastChild.LastChild.Attributes["ID"].Value);
                     var rowElement = dataprovider.Document.CreateElement("Row");
                     foreach (var col in dataGrid.Columns)
                     {
                         var childElement = dataprovider.Document.CreateElement(col.Header.ToString());
                         childElement.SetAttribute("ID",(++maxID).ToString());
                         rowElement.AppendChild(childElement);                             
                     }
                     dataprovider.Document.DocumentElement.AppendChild(rowElement);
                     e.Cancel = true;
                 }
             }
         }            
    }        

    static void dataGrid_Loaded(object sender, RoutedEventArgs e)
    {
        var dataGrid = sender as DataGrid;
        if (dataGrid != null)
        {
            dataGrid.Columns.Clear();
            var dataprovider = dataGrid.DataContext as XmlDataProvider;
            if (dataprovider != null)
            {
                var mainNode = dataprovider.Document.SelectSingleNode(dataprovider.XPath);
                foreach (var item in mainNode.ChildNodes)
                {
                    var node = item as XmlNode;
                    var column = new DataGridTextColumn();
                    column.Binding = new Binding() { XPath = node.Name + "/." };
                    column.Header = node.Name;
                    dataGrid.Columns.Add(column);
                }
            }
        }
    }

}

一旦您结束对最后一行的最后一个单元格的编辑,该行为就会在您的datagrid 中添加一个新的row。代码也非常依赖于您的XML 限制。请仔细看看。

输出:

【讨论】:

  • 感谢您的回答!唯一的问题是,这次 xml 文件有 3 个“列”,但另一个文件可能有 15 个列。所以我不能像那样定义 xaml 中的列..
  • @NickGames 好的,我明白了。如果我发布一个带有附加行为的新解决方案来生成网格列,你可以吗?或者你不想要任何 c# 代码解决方案?
  • 感谢您的回复!那就太好了,谢谢!
  • 这是一个非常好的解决方案!感谢所有的努力!我会接受你的回答,但我只剩下一个问题了。行节点的每个子元素现在都有一个唯一的 ID 作为属性。我希望能够插入一个新行或一个新列,并为每个创建的新节点生成 id。当在另外两行之间的某处插入新行时,我也希望将其添加到 xml 中的该位置。这样可以吗?
  • @NickGames 你不能直接在数据网格设置中添加行(不是没有非常棘手的代码)。我们需要在我们的 XML 文档中添加将反映到数据网格的行,并且可以将 ID 逻辑放置在那里。希望它会有所帮助。
猜你喜欢
  • 2020-07-21
  • 2011-05-14
  • 2014-10-23
  • 2011-05-04
  • 2013-10-31
  • 1970-01-01
  • 2011-01-13
  • 2011-03-14
  • 2010-10-12
相关资源
最近更新 更多