Skip to content

Nextended.UI

📚 Full API reference — every public type and member, generated from the compiled assembly.

🇩🇪 Diese Seite auf Deutsch

WPF and Windows Forms utilities for desktop application development.

Overview

Nextended.UI provides comprehensive utilities, behaviors, and helpers for building Windows desktop applications with WPF and Windows Forms.

Installation

bash
dotnet add package Nextended.UI

Note: This package is Windows-only and targets net8.0-windows and net9.0-windows.

Key Features

1. ViewUtility

Comprehensive utility class for UI operations and manipulations.

csharp
using Nextended.UI;

// UI helper operations
var element = ViewUtility.FindVisualChild<Button>(parent);
var parent = ViewUtility.FindVisualParent<Grid>(child);

2. WPF Behaviors

Custom behaviors for enhanced WPF functionality.

xaml
<TextBox>
    <i:Interaction.Behaviors>
        <behaviors:WatermarkBehavior Watermark="Enter text here..." />
    </i:Interaction.Behaviors>
</TextBox>

3. ViewModel Base Classes

Base classes for implementing MVVM pattern.

csharp
using Nextended.UI.ViewModels;

public class MainViewModel : ViewModelBase
{
    private string _title;
    
    public string Title
    {
        get => _title;
        set => SetProperty(ref _title, value);
    }
}

4. Theming Support

Built-in theming capabilities for WPF applications.

csharp
using Nextended.UI.Theming;

// Apply theme
ThemeManager.ApplyTheme(ThemeType.Dark);

Usage Examples

MVVM ViewModel

csharp
using Nextended.UI.ViewModels;
using System.Windows.Input;
using Nextended.Core.Extensions;

public class UserViewModel : ViewModelBase
{
    private string _name;
    private string _email;
    private bool _isLoading;
    
    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }
    
    public string Email
    {
        get => _email;
        set => SetProperty(ref _email, value);
    }
    
    public bool IsLoading
    {
        get => _isLoading;
        set => SetProperty(ref _isLoading, value);
    }
    
    public ICommand SaveCommand { get; }
    public ICommand CancelCommand { get; }
    
    public UserViewModel()
    {
        SaveCommand = new RelayCommand(SaveUser, CanSaveUser);
        CancelCommand = new RelayCommand(Cancel);
    }
    
    private bool CanSaveUser()
    {
        return !string.IsNullOrWhiteSpace(Name) && 
               !string.IsNullOrWhiteSpace(Email);
    }
    
    private async void SaveUser()
    {
        IsLoading = true;
        try
        {
            await SaveUserToDatabase();
            MessageBox.Show("User saved successfully!");
        }
        catch (Exception ex)
        {
            MessageBox.Show($"Error: {ex.Message}");
        }
        finally
        {
            IsLoading = false;
        }
    }
    
    private void Cancel()
    {
        // Reset or close
        Name = string.Empty;
        Email = string.Empty;
    }
}

Visual Tree Helper

csharp
using Nextended.UI;
using System.Windows;
using System.Windows.Controls;

public class ControlFinder
{
    public T FindChild<T>(DependencyObject parent, string childName = null) 
        where T : DependencyObject
    {
        return ViewUtility.FindVisualChild<T>(parent, childName);
    }
    
    public void FindAllButtons(DependencyObject parent)
    {
        var buttons = ViewUtility.FindVisualChildren<Button>(parent);
        foreach (var button in buttons)
        {
            Console.WriteLine($"Found button: {button.Name}");
        }
    }
    
    public T FindParent<T>(DependencyObject child) 
        where T : DependencyObject
    {
        return ViewUtility.FindVisualParent<T>(child);
    }
}

Custom Behavior Example

csharp
using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Controls;

public class NumericOnlyBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewTextInput += OnPreviewTextInput;
    }
    
    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.PreviewTextInput -= OnPreviewTextInput;
    }
    
    private void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        e.Handled = !IsTextNumeric(e.Text);
    }
    
    private static bool IsTextNumeric(string text)
    {
        return int.TryParse(text, out _);
    }
}
xaml
<TextBox>
    <i:Interaction.Behaviors>
        <local:NumericOnlyBehavior />
    </i:Interaction.Behaviors>
</TextBox>

Dialog Service

csharp
using System.Windows;

public class DialogService
{
    public bool? ShowDialog(Window dialog, Window owner = null)
    {
        if (owner != null)
        {
            dialog.Owner = owner;
            dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
        }
        else
        {
            dialog.WindowStartupLocation = WindowStartupLocation.CenterScreen;
        }
        
        return dialog.ShowDialog();
    }
    
    public MessageBoxResult ShowMessage(
        string message, 
        string title = "Information",
        MessageBoxButton buttons = MessageBoxButton.OK,
        MessageBoxImage icon = MessageBoxImage.Information)
    {
        return MessageBox.Show(message, title, buttons, icon);
    }
    
    public bool ShowConfirmation(string message, string title = "Confirm")
    {
        var result = MessageBox.Show(
            message, 
            title, 
            MessageBoxButton.YesNo, 
            MessageBoxImage.Question
        );
        return result == MessageBoxResult.Yes;
    }
}

Property Grid Searcher

csharp
using Nextended.UI.Helper;
using System.Windows.Controls;

public class PropertySearchExample
{
    private readonly PropertyGridSearcher _searcher;
    
    public PropertySearchExample()
    {
        _searcher = new PropertyGridSearcher();
    }
    
    public void SearchProperties(PropertyGrid propertyGrid, string searchText)
    {
        _searcher.Search(propertyGrid, searchText);
    }
}

Best Practices

1. Use MVVM Pattern

csharp
// ViewModel
public class MainViewModel : ViewModelBase
{
    private ObservableCollection<User> _users;
    
    public ObservableCollection<User> Users
    {
        get => _users;
        set => SetProperty(ref _users, value);
    }
}
xaml
<!-- View -->
<Window DataContext="{Binding Source={StaticResource MainViewModel}}">
    <ListBox ItemsSource="{Binding Users}" />
</Window>

2. Implement INotifyPropertyChanged

csharp
public class User : NotificationObject
{
    private string _name;
    
    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }
}

3. Use Commands for User Actions

csharp
public ICommand DeleteUserCommand { get; }

public MainViewModel()
{
    DeleteUserCommand = new RelayCommand<User>(
        user => DeleteUser(user),
        user => user != null
    );
}

4. Handle UI Thread Properly

csharp
public async Task LoadDataAsync()
{
    IsLoading = true;
    
    var data = await Task.Run(() => LoadFromDatabase());
    
    // Update UI on UI thread
    Application.Current.Dispatcher.Invoke(() =>
    {
        Users.Clear();
        foreach (var user in data)
        {
            Users.Add(user);
        }
    });
    
    IsLoading = false;
}

WPF-Specific Features

Resource Dictionaries

xaml
<ResourceDictionary>
    <Style x:Key="ModernButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="#2196F3"/>
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Padding" Value="10,5"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <!-- Custom template -->
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Data Templates

xaml
<DataTemplate x:Key="UserItemTemplate">
    <StackPanel Orientation="Horizontal" Margin="5">
        <TextBlock Text="{Binding Name}" FontWeight="Bold" Margin="0,0,10,0"/>
        <TextBlock Text="{Binding Email}" Foreground="Gray"/>
    </StackPanel>
</DataTemplate>

Configuration

App.xaml.cs

csharp
using System.Windows;

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        
        // Initialize services
        InitializeServices();
        
        // Set up exception handling
        DispatcherUnhandledException += OnDispatcherUnhandledException;
        
        // Show main window
        var mainWindow = new MainWindow();
        mainWindow.Show();
    }
    
    private void InitializeServices()
    {
        // Register services, set up DI, etc.
    }
    
    private void OnDispatcherUnhandledException(
        object sender, 
        DispatcherUnhandledExceptionEventArgs e)
    {
        MessageBox.Show(
            $"An error occurred: {e.Exception.Message}",
            "Error",
            MessageBoxButton.OK,
            MessageBoxImage.Error
        );
        
        e.Handled = true;
    }
}

Supported Frameworks

  • .NET 8.0 (Windows)
  • .NET 9.0 (Windows)
  • .NET 10.0 (Windows)

Platform Support

Windows Only - This package requires Windows and will not build or run on Linux or macOS.

Dependencies

  • Nextended.Core - Core utilities and extensions
  • Microsoft.Xaml.Behaviors.Wpf - WPF behaviors support
  • Nextended.Core - Foundation library with NotificationObject base classes