WPF DataGrid Binding

John Peters - Feb 28 '21 - - Dev Community

The WPF DataGrid is the goto grid-like control for desktop development.

Create the columns first

<DataGrid x:Name="processListDataGrid"
          EnableRowVirtualization="True"
          AutoGenerateColumns="False"
          RowDetailsVisibilityMode="VisibleWhenSelected"
 >
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button Padding="5">Testing One Two Three</Button>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>


Enter fullscreen mode Exit fullscreen mode

The code above says: "For each item in the DataGrid create a Button that has the text shown".

This is the result.

Alt Text

These buttons have implicit binding to the Text shown inside the button tag. Similar to innerText in HTML this property is call 'content' instead.

In all of our DataGrid columns we prefer the DataGridTemplateColumn approach. We do this to take advantage of premade user controls like the Button. The current theme is applied as a result.

Binding to a Collection of Items

The data we show, in our case, is that of an ObservableCollection which is recommended in WPF land.

The binding can be done in the code behind as follows:

var content = new ObservableCollection<ProcessInfo>(new ProcessList());
processListDataGrid.ItemsSource = content;

Enter fullscreen mode Exit fullscreen mode

Alt Text

By setting the items source directly we are providing the data the grid needs. However, nothing showed until we told each column the property name to show.

 <DataGrid.Columns>
            <DataGridTemplateColumn Width="120">
                <DataGridTemplateColumn.CellTemplate>  
                    <DataTemplate>
                        <Button Tag="{Binding id}" Click="OnKillProcess" HorizontalAlignment="Stretch">Stop Process</Button>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Style="{DynamicResource gray}" Text="{Binding id}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Style="{DynamicResource gray}"  Text="{Binding windowtitle}"></TextBlock>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn >
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock  Style="{DynamicResource gray}" Text="{Binding processname}"></TextBlock>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>

Enter fullscreen mode Exit fullscreen mode

For first timers, none of this is intuitive, and even for those returning to WPF there's plenty of stumbling blocks. Keep in mind that our data model defines the fields.

Data Model

public class ProcessInfo {
    public string id { get; set; }
    public string windowtitle { get; set; }
    public string processname { get; set; }
}

Don't forget the getters and setters!
Enter fullscreen mode Exit fullscreen mode

Where did the data come from?

public class ProcessList : List<ProcessInfo> {
    public ProcessList()        {
        var items = Process.GetProcesses().Where(item => item.MainWindowTitle != string.Empty ||
        item.ProcessName.Contains("chromedriver")).ToList();
        items.ForEach(item =>
        {
            this.Add(new ProcessInfo()
            {
                id = item.Id.ToString(),
                windowtitle = item.MainWindowTitle,
                processname = item.ProcessName,
            });
        });
    }
}

Enter fullscreen mode Exit fullscreen mode

Of course, the System.Diagnostics.Process class!

The Button Click Handler

private async void OnKillProcess(object sender, RoutedEventArgs e)
{
    Button btn = (Button)sender;
    int id = int.Parse(btn.Tag.ToString());
    await Task.Run(() =>
    {
        var proc = Process.GetProcessById(id);
        proc.Kill();
    });
    this.RefreshView();
}

Enter fullscreen mode Exit fullscreen mode

Async first to stop any GUI lag.

It's all simple once we know how, it's easily remembered if we log how to do it on Dev.to.

JWP2021 WPF UserControl Process

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player