将数组/ XML绑定到WPF ListView / DataGrid

时间:2015-10-13 14:04:50

标签: c# arrays wpf powershell datagrid

我有一个PowerShell数组,如果我导出为XML,它将如下所示:

<?xml version="1.0"?>
<Objects>
   <Object>
      <Property Name="Server">Server1</Property>
      <Property Name="Issue">hard drive 0 failed</Property>
   </Object>
</Objects>

我想让这个数组在GUI中显示。在谷歌搜索之后,我发现可以使用WPF来达到这个目标,但我从来没有使用过它,所以我很难解决这个问题:

  1. 如何正确地将数组绑定到ViewList以获取自动创建的列并命名为属性名称(“Server”,“Issue”等)
  2. 我不需要编辑数据,但希望每行都有一个按钮,将当前行的数据作为新问题发送到Jira。我已经有一个代码如何使用PS和REST API创建Jira问题,但还不知道如何在ListView单元格中放置一个按钮
  3. 经过另一天的谷歌搜索后,我发现DataGrid更适合我的情况,因为根据传递的ItemsSource对象自动生成列数。

    现在我遇到了一个新问题,这是我的代码:

    $btn = New-Object System.Windows.Controls.Button
    $dt = New-Object System.Windows.DataTemplate
    $dt.VisualTree = New-Object System.Windows.FrameworkElementFactory($btn)
    $dgtc = New-Object System.Windows.Controls.DataGridTemplateColumn
    $dgtc.CellTemplate = $dt
    $faults = Get-UcsFault -Severity critical | select @{n=’Server’; e={$_.Dn}},
              @{n=’Issue’;e={$_.Issue}}, 
              @{n=’Create Ticket’;e={[System.Windows.Controls.DataGridTemplateColumn]$dgtc}}
    $result = New-Object System.Windows.Window -prop @{
       Content = New-Object System.Windows.Controls.DataGrid -prop @{ItemsSource=$faults};}
    $result.ShowDialog()
    

    但是我没有在实际按钮中看到最后一栏中的类名(即System.Windows.Controls.Button)

2 个答案:

答案 0 :(得分:0)

听起来你想根据XML对象创建一个类。

public class yourObject //Whatever you want to call it.
{
  public string Server {get;set;}
  public string Issue {get;set;}
  //ETC
}

完成类设置后,Id会浏览XML文件并将数据放入列表中。

        string filepath = Directory.GetParent(Environment.CurrentDirectory).Parent.FullName + @"\OBJECTS.xml"; 
       //Path to XML file

        List<yourObject> list = new List<yourObject>();
        var maps = from c in XElement.Load(filepath).Elements("Object")
                   select c;

        foreach (var item in maps)
        {
            var newObject= new yourObject();

            //Names of your nodes
            newObject.Server= item.Element("Server").Value;
            newObject.Issue= item.Element("Issue").Value;

            list.Add(newObject);
        }
        //Probably a good idea to make it an observable collection.
        objectList= new ObservableCollection<youtObject>();
        foreach (var item in list)
        {
            objectList.Add(item);
        }

一旦它在列表中,并且您不想绑定它,您只需将Datagrid的Item源或listview设置为该列表

答案 1 :(得分:0)

  1. 这是一种使用Linq to XML在Code Behind of window中读取数据的方法:
  2. public partial class MainWindow : Window
    {
        private ObservableCollection<ServerIssue> serverIssues;
    
        public MainWindow()
        {
    
            // Linq to XML for elegant Selections
            XElement doc = XElement.Load("serverissues.xml");
            var xmlServerIssues = from objectElt in doc.Descendants("Object")
                               let propertiesElts = objectElt.Elements("Property")
                               let serverElt = propertiesElts.FirstOrDefault(elt => elt.Attribute("Name").Value == "Server")
                               let issueElt = propertiesElts.FirstOrDefault(elt => elt.Attribute("Name").Value == "Issue")
                               select new ServerIssue {
                                   Server = ((serverElt.FirstNode) as XText).Value,
                                   Issue = ((issueElt.FirstNode) as XText).Value
                               };
            // store enumerated data in ObservableCollection<>
            // List<> would be fine but is less agile when adding/removing elements
            serverIssues = new ObservableCollection<ServerIssue>(xmlServerIssues);
            InitializeComponent();
            // Provide data to graphical Grid
            datagridIssues.ItemsSource = serverIssues;
        }
        private void SendToJIRA(object sender, RoutedEventArgs e)
        {
            // ...
        }
    }
    
    1. DataGrid布局代码,绑定属性:
    2. <Window x:Class="XmlToDataGrid.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Title="MainWindow" Height="350" Width="525">
          <Grid>
              <DataGrid x:Name="datagridIssues" CanUserAddRows="False" CanUserDeleteRows="False" AutoGenerateColumns="False">
                  <DataGrid.Columns>
                      <DataGridTextColumn Binding="{Binding Server}" IsReadOnly="true"/>
                      <DataGridTextColumn Binding="{Binding Issue}" IsReadOnly="true"/>
                      <DataGridTemplateColumn >
                          <DataGridTemplateColumn.CellTemplate>
                              <DataTemplate>
                                  <Button Content="Send to JIRA" Click="SendToJIRA" Margin="10 4" Padding="5 3"/>
                              </DataTemplate>
                          </DataGridTemplateColumn.CellTemplate>
                      </DataGridTemplateColumn>
                  </DataGrid.Columns>
              </DataGrid>
          </Grid>
      </Window>
      

      修改

      这是PowerShell中的翻译。即使在C#中,它也不那么明显。 我真的很鼓励你用C#编写这样的代码。您将拥有一个编译器,一个严肃的调试器。

      [reflection.assembly]::loadwithpartialname("PresentationFramework") | Out-Null
      
      # $faults = Get-UcsFault -Severity critical | select @{n=’Server’; e={$_.Dn}},                                               
                          # @{n=’Issue’;e={$_.Issue}}, 
                          # @{n=’Create Ticket’;e={$bt}}                        
                          ######################################################################################
      
      $serverIssue1 = New-Object psobject -Property @{ 
          Server="server1"
          Issue="issue1"
      }
      $serverIssue2 = New-Object psobject -Property @{ 
          Server="server2"
          Issue="issue2"
      }
      
      $serverIssues = New-Object System.Collections.Generic.List``1[Object]
      $serverIssues.Add( $serverIssue1  ) 
      $serverIssues.Add( $serverIssue2  ) 
      
      $datagrid = New-Object Windows.Controls.DataGrid -prop @{
          AutoGenerateColumns=$FALSE; ItemsSource = $serverIssues;
          CanUserAddRows=$FALSE
          CanUserDeleteRows=$FALSE
      }
      
      #$datagrid.ItemsSource=$faults
      # create the binding for a column
      $bindingIssue = New-Object System.Windows.Data.Binding -prop @{ Path='Issue'}
      # create the column
      $columnIssue = New-Object System.Windows.Controls.DataGridTextColumn -prop @{ IsReadOnly=$TRUE;Binding=$bindingIssue}
      $datagrid.Columns.Add($columnIssue)
      # create the binding for a column
      $bindingServer = New-Object System.Windows.Data.Binding -prop @{ Path='Server'}
      # create the column
      $columnServer = New-Object System.Windows.Controls.DataGridTextColumn -prop @{ IsReadOnly=$TRUE;Binding=$bindingServer}
      $datagrid.Columns.Add($columnServer)
      
      # create 3rd column : it s a template, more complicated ! Real WPF hardcore stuff
      # not easy in C#, hard tests in PS !
      
      $factory = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.Button])
      $factory.SetValue( [System.Windows.Controls.Button]::ContentProperty, "Send to Jira")
      $thickness  = New-Object System.Windows.Thickness(10,5,10,5)
      $factory.SetValue( [System.Windows.Controls.Button]::PaddingProperty, $thickness )
      $factory.SetValue( [System.Windows.Controls.Button]::MarginProperty, $thickness )
      # let's plug a callback when the button is clicked
      $factory.AddHandler([System.Windows.Controls.Button]::ClickEvent, [System.Windows.RoutedEventHandler]{
          PARAM ([Object]$sender, [Windows.RoutedEventArgs]$e)
              # replace with code that sends to Jira
              # the DataContext is for the current line of DataGrid. It 's inherited by every component of the line 
              # so the button has a serverIssue DataContext
              $serverIssue = $sender.DataContext
              [System.Windows.MessageBox]::Show($serverIssue.Server);
      })
      
      $dataTemplate = New-Object System.Windows.DataTemplate -prop @{ VisualTree = $factory }
      $columnButton = New-Object System.Windows.Controls.DataGridTemplateColumn -prop @{ IsReadOnly = $TRUE; CellTemplate = $dataTemplate }
      $datagrid.Columns.Add($columnButton)
      
      $result = New-Object System.Windows.Window -prop @{ Content = $datagrid }
      $result.ShowDialog()
      

      此致