GTK4 ColumnView with .NET 8
In this post I will make use of ColumnView to display list of data. ColumnView
is used to display 1-dimensional list with one or more columns. Foucus of this post will be to dispaly multiple columns.
Project Setup
Let’s start by setting up a new solution and project.
dotnet new sln --name ColumnView
dotnet new console -o ColumnView.App
dotnet sln add ColumnView.App/ColumnView.App.csproj
And add a reference to GirCore.Gtk-4.0
nuget package, the latest version is 0.5.0-preview.4
at the time of writing.
cd ColumnView.App
dotnet add package GirCore.Gtk-4.0 --version 0.5.0-preview.4
ColumnViewWindow
I will add a new class named ColumnViewWindow
inheriting from Gtk.Window
. This window will contain a ColumnView
widget to display tabular data.
Model
First let’s add a class that we will use to display our data and a static method to generate the sample data. We will inherit this model from GObject.Object
.
public class UserData : GObject.Object
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public UserData(int id, string firstName, string lastName, string username, string email)
: base(true, Array.Empty<GObject.ConstructArgument>())
{
Id = id;
FirstName = firstName;
LastName = lastName;
Username = username;
Email = email;
}
public static UserData[] SampleUserData()
{
return
[
new UserData(1, "Leanne", "Graham", "Bret", "Sincere@april.biz"),
new UserData(2, "Ervin", "Howell", "Antonette", "Shanna@melissa.tv"),
new UserData(3, "Patricia", "Lebsack", "Karianne", "Julianne.OConner@kory.org"),
new UserData(4, "Chelsey", "Dietrich", "Kamren", "Lucio_Hettinger@annie.ca"),
new UserData(5, "Clementine", "Bauch", "Samantha", "Nathan@yesenia.net"),
];
}
}
ColumnViewWindow
Next let’s update the ColumnViewWindow
to inherit from Gtk.Window
. And then initialise ListStore
and widgets to display the data.
First we will add a Gio.ListStore
and add our sample data to the list store. Then we will add a single seletion model using the model.
var model = Gio.ListStore.New(UserData.GetGType());
foreach (var userData in UserData.SampleUserData())
{
model.Append(userData);
}
var selectionModel = SingleSelection.New(model);
selectionModel.Autoselect = false;
selectionModel.CanUnselect = true;
Next we will add ColumnView
and add it to a ScrolledWindow
and add the scrolled window widget to ColumnViewWindow
.
var columnView = ColumnView.New(selectionModel);
columnView.AddCssClass("data-table");
var scrolledWindow = ScrolledWindow.New();
scrolledWindow.Child = columnView;
Child = scrolledWindow;
Text Columns
Next we will add text based columns displaying data using Label
widget.
// Id Column
var listItemFactory = SignalListItemFactory.New();
listItemFactory.OnSetup += (_, args) => OnSetupLabel(args, Align.End);
listItemFactory.OnBind += (_, args) => OnBindText(args, (ud) => ud.Id.ToString());
var idColumn = ColumnViewColumn.New(nameof(UserData.Id), listItemFactory);
columnView.AppendColumn(idColumn);
// Name Column
listItemFactory = SignalListItemFactory.New();
listItemFactory.OnSetup += (_, args) => OnSetupLabel(args, Align.Start);
listItemFactory.OnBind += (_, args) => OnBindText(args, (ud) => ud.Name);
var nameColumn = ColumnViewColumn.New(nameof(UserData.Name), listItemFactory);
columnView.AppendColumn(nameColumn);
// Sales Column
listItemFactory = SignalListItemFactory.New();
listItemFactory.OnSetup += (_, args) => OnSetupLabel(args, Align.End);
listItemFactory.OnBind += (_, args) => OnBindText(args, (ud) => $"{ud.Sales:C}");
var salesColumn = ColumnViewColumn.New(nameof(UserData.Sales), listItemFactory);
columnView.AppendColumn(salesColumn);
I have added helper methods to OnSetupLabel
and OnBindText
to reuse code to create Label
and set text when binding data.
private void OnSetupLabel(SetupSignalArgs args, Align align)
{
if (args.Object is not ListItem listItem)
{
return;
}
var label = Label.New(null);
label.Halign = align;
listItem.Child = label;
}
private void OnBindText(BindSignalArgs args, Func<UserData, string> getText)
{
if (args.Object is not ListItem listItem)
{
return;
}
if (listItem.Child is not Label label) return;
if (listItem.Item is not UserData userData) return;
label.SetText(getText(userData));
}
ProgressBar Column
This is just to display how to use the ProgressBar
widget and also to demonstrate that any widget can be used in the ColumnView
.
Code to add the column
// Percentage Column
listItemFactory = SignalListItemFactory.New();
listItemFactory.OnSetup += OnSetupProgress;
listItemFactory.OnBind += OnBindProgress;
var percentageColumn = ColumnViewColumn.New(nameof(UserData.ProgressPercentage), listItemFactory);
columnView.AppendColumn(percentageColumn);
And methods to create widget and set data
private void OnSetupProgress(SignalListItemFactory sender, SetupSignalArgs args)
{
if (args.Object is not ListItem listItem)
{
return;
}
var progressBar = ProgressBar.New();
progressBar.SetShowText(true);
listItem.Child = progressBar;
}
private void OnBindProgress(SignalListItemFactory sender, BindSignalArgs args)
{
if (args.Object is not ListItem listItem)
{
return;
}
if (listItem.Child is not ProgressBar progressBar) return;
if (listItem.Item is not UserData userData) return;
progressBar.SetFraction(userData.ProgressPercentage * 0.01);
}
Program.cs
Lets update Program.cs
to create and show our ColumnViewWindow
.
var application = Gtk.Application.New("org.kashif-code-samples.columnview.sample", Gio.ApplicationFlags.FlagsNone);
application.OnActivate += (sender, args) =>
{
var window = new ColumnViewWindow
{
Application = application
};
window.Show();
};
return application.RunWithSynchronizationContext(null);
Running the program will show us following window.
Source
Source code for the sample application is available on GitHub in gtk4-dotnet8-column-view.
References
In no particular order
Leave a Comment
Your email address will not be published. Required fields are marked *