Adding Items to DataGrid WPF using Python

2k views Asked by At

I am writing an application using python.net. My objective is to fill a DataGrid programmatically with data. The code I am working in is below:

import clr
import System.Threading
System.Threading.Thread.CurrentThread.SetApartmentState(System.Threading.ApartmentState.STA)

clr.AddReference(r"wpf\PresentationFramework")
clr.AddReference(r"wpf\PresentationCore")
clr.AddReference("System.Xml")

from System.IO import StringReader
from System.Xml import XmlReader
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application, LogicalTreeHelper, MessageBox
from model import Model
from System.Windows.Media import Brushes
from random import random
from System.Windows.Controls import DataGridTextColumn, TextBox
from System.Windows.Data import Binding

xaml = """
<Window
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="panel1"
       Title="harpia.ml" Height="600" Width="800" Background="#FFFBFBFB">
    <Grid Margin="0,0,0,58">
        <DataGrid x:Name="dataGrid" IsReadOnly="True" Background="#FFAC5C5C" AutoGenerateColumns="False" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="206" Width="449">
            <DataGrid.Columns>

            </DataGrid.Columns>
          </DataGrid>
        <Button x:Name="refreshBtn" Content="Button" HorizontalAlignment="Left" Margin="10,221,0,0" VerticalAlignment="Top" Width="75"/>
        <Button x:Name="button1" Content="Button" HorizontalAlignment="Left" Margin="384,221,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="-0.033,-0.086"/>
        <Button x:Name="button2" Content="Button" HorizontalAlignment="Left" Height="21" Margin="10,266,0,-36" VerticalAlignment="Top" Width="75"/>
        <Button x:Name="button3" Content="Button" HorizontalAlignment="Left" Height="21" Margin="384,266,0,-36" VerticalAlignment="Top" Width="75"/>
        <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="21" Margin="117,266,0,-36" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="236"/>
    </Grid>
</Window>
"""

class Student(object):

    def __init__(self, name, branch, year):
            self.name = name
            self.branch = branch
            self.year = year
            print("A student object is created.")

    def print_details(self):
        """
        Prints the details of the student.
        """
        print("Name:", self.name)
        print("Branch:", self.branch)
        print("Year:", self.year)

def _button2_Click(s, e):
    textBox1 = LogicalTreeHelper.FindLogicalNode(win, 'textBox1')
    grid = LogicalTreeHelper.FindLogicalNode(win, 'dataGrid')

    col1 = DataGridTextColumn()
    col2 = DataGridTextColumn()
    col3 = DataGridTextColumn()

    grid.Columns.Add(col1)
    grid.Columns.Add(col2)
    grid.Columns.Add(col3)

    col1.Binding = Binding("name")
    col2.Binding = Binding("branch")
    col3.Binding = Binding("year")


    col1.Header = "name"
    col2.Header = "branch"
    col3.Header = "year"

    item = []

    item.append(Student("Andre", "Piratas", "1973"))
    item.append(Student("Andres", "Piratass", "1973s"))
    item.append(Student("Andre3", "Piratas3", "19733"))
    item.append(Student("Andre4", "Piratas4", "19734"))
    grid.ItemsSource = item
    textBox1.Text = str(grid.Items[0])

if __name__ == "__main__":
    xr = XmlReader.Create(StringReader(xaml))
    win = XamlReader.Load(xr)
    _button2 = LogicalTreeHelper.FindLogicalNode(win, 'button2')
    _button2.Click += _button2_Click
    Application().Run(win)

I was able to add the columns. However, the code is failing to add items(rows) to the DataGrid. Does anyone know how can I do this?

3

There are 3 answers

0
Ponciano On

Must be a bindings thing, try to add columns after defining their bindings.

col1.Binding = Binding("name")
col2.Binding = Binding("branch")
col3.Binding = Binding("year")

col1.Header = "name"
col2.Header = "branch"
col3.Header = "year"

grid.Columns.Add(col1)
grid.Columns.Add(col2)
grid.Columns.Add(col3)
0
Michael Scheper On

This is how I've successfully done it in IronPython under Windows. (I haven't tried exactly this code, so let me know if I've forgotten an import or made a typo or something.)

import wpf
import clr
clr.AddReference("System.Xml")
from System.Windows import Window

class MyItem:
    "An item to represent a row in your grid."

    def __init__(self, name, branch, year):
        self.name = name
        self.branch = branch
        self.year = year

class MyWindow(Window):
    "The window defined in your XAML."

    def __init__(self):
        # I keep XAML in separate files, instead of a string.
        wpf.LoadComponent(self, 'my_window.xaml')

        # Here are some items for the grid.
        my_items = [MyItem('me', 'b0', 2019), MyItem('you', 'b1', 2020)]

        # Since this class is the window defined in the XAML, it is self, and
        # the names in the XAML defines its members. Therefore, your 'dataGrid'
        # can be accessed like this:
        self.dataGrid.ItemsSource = my_items

BTW, since I write Python, I follow Python conventions (PEP8), and would call dataGrid data_grid instead, i.e. <DataGrid Name="data_grid">. This is just a convention, and it breaks down with things like ItemsSource, but I think it makes it clearer that the names in the XAML can actually be accessed as objects in Python.

1
Y.Wang On

I have the same problem as you do. My workaround is to create a DataTable and define the contents in the DataTable, then pass to DataGrid. Here is an example:

#Crate a DataTable
data_table = System.Data.DataTable("MyDataTable")
data_table.Columns.Add("name")
data_table.Columns.Add("branch")
data_table.Columns.Add("year")

#Add data 
data_table.Rows.Add("Andre", "Piratas", "1973")
data_table.Rows.Add("Andres", "Piratass", "1973s")

#DataTable to DataGrid
data_grid.DataContext = data_table.DefaultView

If you have found a better solution in these two years, I am very willing to know.