WPF DataGrid Binding
John Peters
Posted on February 28, 2021
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>
The code above says: "For each item in the DataGrid create a Button that has the text shown".
This is the result.
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;
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>
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!
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,
});
});
}
}
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();
}
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
Posted on February 28, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 30, 2024