WinUI 3 Documentation: Data Handling

Introduction to Data Handling in WinUI 3

WinUI 3 provides a robust set of tools and patterns for managing data within your applications. Effective data handling is crucial for creating responsive, efficient, and user-friendly UIs. This section explores the core concepts and components involved in data operations in WinUI 3.

Key areas include:

  • Data Binding: Connecting UI elements to data sources.
  • Observable Collections: Collections that notify the UI of changes.
  • Data Validation: Ensuring data integrity.
  • Data Grids: Displaying tabular data efficiently.
  • Data Templates: Customizing the visual representation of data.

Data Binding

Data binding is a powerful mechanism in WinUI 3 that allows you to synchronize data between your UI elements and your data source. This eliminates the need for manual UI updates and reduces boilerplate code.

The fundamental syntax for data binding uses curly braces { }:


<TextBlock Text="{Binding PropertyName}" />
                

Binding Modes

Data binding supports various modes to control the direction and timing of data synchronization:

  • OneWay: Changes in the source update the target.
  • TwoWay: Changes in the source update the target, and changes in the target update the source.
  • OneTime: The value is set only once.
  • OneWayToSource: Changes in the target update the source.

The default mode for most properties is OneWay, while properties like TextBox.Text default to TwoWay.


<!-- Two-way binding for a text input -->
<TextBox Text="{Binding UserName, Mode=TwoWay}" />
                

Observable Collections

To enable data binding to collections, WinUI 3 utilizes observable collections. These collections implement the INotifyCollectionChanged and INotifyPropertyChanged interfaces, allowing the UI to be notified when items are added, removed, or replaced.

ObservableCollection<T>

The most common observable collection is ObservableCollection<T>, available in the System.Collections.ObjectModel namespace.


using System.Collections.ObjectModel;

public class MyViewModel
{
    public ObservableCollection<string> Items { get; } = new ObservableCollection<string>();

    public MyViewModel()
    {
        Items.Add("Item 1");
        Items.Add("Item 2");
    }

    public void AddItem(string newItem)
    {
        Items.Add(newItem);
    }
}
                

CollectionViewSource

For more advanced scenarios like grouping, filtering, and sorting of collections, CollectionViewSource can be used.

Data Validation

Ensuring data quality is paramount. WinUI 3 integrates with the data validation mechanisms provided by the .NET framework, particularly the INotifyDataErrorInfo interface.

Implementing INotifyDataErrorInfo

Create a class that implements INotifyDataErrorInfo to add validation logic to your data models or view models.


using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;

public class UserData : INotifyDataErrorInfo
{
    private string _name;
    private Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>();

    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            ValidateName();
        }
    }

    public bool HasErrors => _errors.Count > 0;

    public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;

    private void ValidateName()
    {
        ClearErrors(nameof(Name));
        if (string.IsNullOrWhiteSpace(Name))
        {
            AddError(nameof(Name), "Name cannot be empty.");
        }
        else if (Name.Length < 3)
        {
            AddError(nameof(Name), "Name must be at least 3 characters long.");
        }
    }

    private void AddError(string propertyName, string errorMessage)
    {
        if (!_errors.ContainsKey(propertyName))
        {
            _errors[propertyName] = new List<string>();
        }
        _errors[propertyName].Add(errorMessage);
        OnErrorsChanged(propertyName);
    }

    private void ClearErrors(string propertyName)
    {
        if (_errors.ContainsKey(propertyName))
        {
            _errors.Remove(propertyName);
            OnErrorsChanged(propertyName);
        }
    }

    private void OnErrorsChanged(string propertyName)
    {
        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
    }

    public IEnumerable GetErrors(string? propertyName)
    {
        if (string.IsNullOrEmpty(propertyName) || !_errors.ContainsKey(propertyName))
        {
            return new List<string>();
        }
        return _errors[propertyName];
    }
}
                

UI Feedback

WinUI 3 controls can automatically display validation errors. For example, using TextBox.HeaderTemplate or Control.ValidationStyle.


<TextBox Header="Name"
         Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
<!-- You would typically define ValidationStyle in App.xaml -->
                

Data Grids (DataGrid)

The DataGrid control is designed for displaying and editing tabular data. It's highly customizable and offers features like sorting, filtering, column reordering, and cell editing.

Basic Usage


<Page ...
      xmlns:controls="using:Microsoft.UI.Xaml.Controls"
      ... >

    <Grid>
        <controls:DataGrid ItemsSource="{Binding UserDataCollection}" />
    </Grid>
</Page>
                

Customizing Columns

You can define columns explicitly to control their display, binding, and behavior.


<controls:DataGrid ItemsSource="{Binding UserDataCollection}" AutoGenerateColumns="False">
    <controls:DataGrid.Columns>
        <controls:DataGridTextColumn Header="Name" Binding="{Binding Name}" />
        <controls:DataGridTextColumn Header="Email" Binding="{Binding Email}" />
        <controls:DataGridTemplateColumn Header="Actions">
            <controls:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button Content="Edit" />
                </DataTemplate>
            </controls:DataGridTemplateColumn.CellTemplate>
        </controls:DataGridTemplateColumn>
    </controls:DataGrid.Columns>
</controls:DataGrid>
                

Data Templates

Data templates allow you to define how individual data items are presented in UI elements like ListView, GridView, and DataGrid.

DataTemplate for List Items


<ListView ItemsSource="{Binding Products}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Product">
            <StackPanel Orientation="Horizontal" Spacing="10">
                <Image Source="{Binding ImageUrl}" Width="50" Height="50" />
                <StackPanel>
                    <TextBlock Text="{Binding Name}" FontWeight="Bold" />
                    <TextBlock Text="{Binding Price, StringFormat='C'}" />
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
                

x:DataType

Using x:DataType improves performance by allowing the XAML compiler to perform compile-time checking of data bindings.

Performance Considerations

Handling large amounts of data efficiently requires attention to performance. Here are some key strategies:

  • Virtualization: Ensure that UI elements that display lists or grids (like ListView, GridView, DataGrid) are configured for UI virtualization. This means only the visible items are loaded into memory.
  • Efficient Data Loading: Load data asynchronously to avoid blocking the UI thread. Use techniques like pagination or lazy loading for very large datasets.
  • Optimize Data Models: Use lightweight data models where possible. Avoid excessively complex object graphs if they are not needed for UI display.
  • Data Binding Performance: Be mindful of binding modes. Use OneWay binding when TwoWay is not strictly necessary. Use x:DataType for performance gains.
  • CollectionViewSource Optimization: For large collections, consider the performance implications of sorting and filtering.

Performance Tip:

For extremely large datasets that require server-side processing, consider implementing custom data virtualization providers or utilizing libraries designed for high-performance data handling.