MatthL.PhysicalUnits.WPF 1.0.0

dotnet add package MatthL.PhysicalUnits.WPF --version 1.0.0
                    
NuGet\Install-Package MatthL.PhysicalUnits.WPF -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MatthL.PhysicalUnits.WPF" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MatthL.PhysicalUnits.WPF" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="MatthL.PhysicalUnits.WPF" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MatthL.PhysicalUnits.WPF --version 1.0.0
                    
#r "nuget: MatthL.PhysicalUnits.WPF, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MatthL.PhysicalUnits.WPF@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MatthL.PhysicalUnits.WPF&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=MatthL.PhysicalUnits.WPF&version=1.0.0
                    
Install as a Cake Tool

MatthL.PhysicalUnits.WPF

Professional WPF controls for dynamic physical unit manipulation in .NET applications. A complete UI toolkit that brings the power of MatthL.PhysicalUnits directly to your users.

NuGet License

🎯 Key Features

Production-ready WPF controls that your users will love:

  • βœ… Smart Unit Builder - Interactive control for building complex units with double click simplicity
  • βœ… Intelligent Suggestions - Context-aware unit recommendations based on mathematical operations
  • βœ… One-Click Unit Selection - Beautiful interfaces with search and filtering
  • βœ… Live Unit Conversion - Real-time conversion between compatible units
  • βœ… Equation-Based Selection - Automatically suggest units based on dimensional formulas
  • βœ… MVVM-Ready - Full two-way binding support with ViewModels
  • βœ… Customizable Repository - Filter units by system (SI, Imperial, US, etc.)
  • βœ… Professional UI/UX - Polished controls ready for enterprise applications

πŸ“¦ Installation

dotnet add package MatthL.PhysicalUnits.WPF

πŸš€ Quick Start

Basic Unit Selection

The simplest way to let users select a physical unit:

<Window xmlns:puw="clr-namespace:MatthL.PhysicalUnits.UI.ViewsButtons.PhysicalUnitBuilderButtonViews;assembly=MatthL.PhysicalUnits.UI">
    
    <puw:PhysicalUnitBuilderButtonView 
        SelectedUnit="{Binding MyUnit, Mode=TwoWay}" />
        
</Window>
using MatthL.PhysicalUnits.Core.Models;

public class MyViewModel : INotifyPropertyChanged
{
    private PhysicalUnit _myUnit;
    public PhysicalUnit MyUnit
    {
        get => _myUnit;
        set { _myUnit = value; OnPropertyChanged(); }
    }
}

🎨 Available Controls

1. PhysicalUnitBuilderButtonView

The most powerful control - a button that opens a comprehensive unit builder popup.

PhysicalUnitBuilderButton

Features:

  • Search through 400+ units
  • Filter by domain (Mechanics, Electricity, etc.)
  • Build custom composite units
  • Convert between compatible units
  • Real-time unit preview

XAML Usage:

<puw:PhysicalUnitBuilderButtonView 
    SelectedUnit="{Binding SelectedUnit, Mode=TwoWay}"
    IsPopupOpen="{Binding IsBuilderOpen, Mode=TwoWay}" />

Properties:

  • SelectedUnit (PhysicalUnit) - The selected/built unit
  • IsPopupOpen (bool) - Controls popup visibility
  • UnitToConvert (PhysicalUnit) - When set, shows only compatible units for conversion
  • IsOnlyConvertion (bool) - Restricts to conversion mode only

Conversion Mode:


<puw:PhysicalUnitBuilderButtonView 
    SelectedUnit="{Binding TargetUnit, Mode=TwoWay}"
    UnitToConvert="{Binding SourceUnit}"
    IsOnlyConvertion="True" />

2. PhysicalUnitEquationResultButtonView

Intelligent unit selection based on dimensional formulas and mathematical operations.

FormulaResult

Features:

  • Automatic unit suggestions from equations
  • Relevance scoring (prioritizes most common units)
  • Context-aware explanations
  • Formula display

XAML Usage:

<puw:PhysicalUnitEquationResultButtonView 
    EquationTerms="{Binding MyEquation}"
    SelectedUnit="{Binding ResultUnit, Mode=TwoWay}"
    MaxSuggestions="10" />

Code Example:

using MatthL.PhysicalUnits.Core.EquationModels;
using MatthL.PhysicalUnits.Infrastructure.Library;
using Fractions;

// Force Γ— Distance = Energy
var force = StandardUnits.Newton();
var distance = StandardUnits.Meter();

var equation = new EquationTerms(
    new PhysicalUnitTerm(force, new Fraction(1)),
    new PhysicalUnitTerm(distance, new Fraction(1))
);

MyEquation = equation;
// Automatically suggests: Joule, NewtonΒ·Meter, WattΒ·Hour, etc.

Properties:

  • EquationTerms (EquationTerms) - The equation to analyze
  • SelectedUnit (PhysicalUnit) - The chosen suggested unit
  • MaxSuggestions (int) - Maximum suggestions to display (default: 10)
  • IsPopupOpen (bool) - Controls popup visibility

3. PhysicalUnitBuilderView

The full-featured builder control (used internally by the button version).

XAML Usage:

<puv:PhysicalUnitBuilderView 
    SelectedUnit="{Binding MyUnit, Mode=TwoWay}"
    Height="600" />

Features:

  • Complete search and filtering
  • Category and type selection
  • Building mode with unit composition
  • Base unit management
  • Real-time dimensional formula display

4. PhysicalUnitView

Display a physical unit with all its details.

XAML Usage:

<puv:PhysicalUnitView 
    PhysicalUnitViewModel="{Binding UnitViewModel}"
    IsEditing="False" />

Features:

  • Shows unit name, symbol, and dimensional formula
  • Displays all base units with their exponents
  • Optional editing mode
  • Clean, professional presentation

5. SpecificUnitSelectorView

Simplified selector for specific unit categories.

XAML Usage:

<pus:SpecificUnitSelectorView 
    Category="Time"
    SelectedUnit="{Binding TimeUnit, Mode=TwoWay}" />

Available Categories:

  • Time - Second, Minute, Hour, Day, Week, Month, Year
  • Electric - Ampere, Volt (with prefixes)

Perfect for: Dedicated time/frequency selectors, electrical parameter inputs

6. RepositorySettingButtonView

Configure which unit systems are available to users.

XAML Usage:

<purs:RepositorySettingButtonView />

Features:

  • Toggle SI/Metric units
  • Toggle Imperial units
  • Toggle US customary units
  • Toggle Astronomical units
  • Toggle Other systems

Changes are applied globally through PhysicalUnitRepository.Settings.

πŸ“‹ Complete Example: Unit Conversion App

Here's a complete example showing multiple controls working together:

<Window x:Class="MyApp.MainWindow"
        xmlns:puw="clr-namespace:MatthL.PhysicalUnits.UI.ViewsButtons.PhysicalUnitBuilderButtonViews;assembly=MatthL.PhysicalUnits.UI"
        xmlns:pue="clr-namespace:MatthL.PhysicalUnits.UI.ViewsButtons.PhysicalUnitEquationResultButtonViews;assembly=MatthL.PhysicalUnits.UI">
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        
        <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="10">
            <TextBox Text="{Binding Value1, UpdateSourceTrigger=PropertyChanged}" 
                     Width="100" Margin="0,0,10,0"/>
            <puw:PhysicalUnitBuilderButtonView 
                SelectedUnit="{Binding Unit1, Mode=TwoWay}" 
                Width="200"/>
        </StackPanel>
        
        
        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="10">
            <TextBox Text="{Binding Value2, UpdateSourceTrigger=PropertyChanged}" 
                     Width="100" Margin="0,0,10,0"/>
            <puw:PhysicalUnitBuilderButtonView 
                SelectedUnit="{Binding Unit2, Mode=TwoWay}" 
                Width="200"/>
        </StackPanel>
        
        
        <StackPanel Grid.Row="2" Orientation="Horizontal" Margin="10">
            <TextBlock Text="Result Unit:" Margin="0,0,10,0" 
                       VerticalAlignment="Center"/>
            <pue:PhysicalUnitEquationResultButtonView 
                EquationTerms="{Binding EquationTerms}"
                SelectedUnit="{Binding ResultUnit, Mode=TwoWay}"
                Width="200"/>
        </StackPanel>
        
        
        <StackPanel Grid.Row="3" Orientation="Horizontal" Margin="10">
            <TextBlock Text="Convert to:" Margin="0,0,10,0" 
                       VerticalAlignment="Center"/>
            <puw:PhysicalUnitBuilderButtonView 
                SelectedUnit="{Binding TargetUnit, Mode=TwoWay}"
                UnitToConvert="{Binding ResultUnit}"
                Width="200"/>
            <TextBlock Text="{Binding ConvertedValue}" 
                       Margin="10,0,0,0"
                       VerticalAlignment="Center"/>
        </StackPanel>
    </Grid>
</Window>
using CommunityToolkit.Mvvm.ComponentModel;
using MatthL.PhysicalUnits.Core.Models;
using MatthL.PhysicalUnits.Core.EquationModels;
using MatthL.PhysicalUnits.Computation.Extensions;
using Fractions;

public partial class MainViewModel : ObservableObject
{
    [ObservableProperty] private double _value1 = 100;
    [ObservableProperty] private double _value2 = 50;
    [ObservableProperty] private PhysicalUnit _unit1;
    [ObservableProperty] private PhysicalUnit _unit2;
    [ObservableProperty] private PhysicalUnit _resultUnit;
    [ObservableProperty] private PhysicalUnit _targetUnit;
    [ObservableProperty] private double _convertedValue;
    
    public EquationTerms EquationTerms { get; private set; }
    
    partial void OnUnit1Changed(PhysicalUnit value) => UpdateEquation();
    partial void OnUnit2Changed(PhysicalUnit value) => UpdateEquation();
    partial void OnResultUnitChanged(PhysicalUnit value) => UpdateConversion();
    partial void OnTargetUnitChanged(PhysicalUnit value) => UpdateConversion();
    
    private void UpdateEquation()
    {
        if (Unit1 == null || Unit2 == null) return;
        
        EquationTerms = new EquationTerms(
            new PhysicalUnitTerm(Unit1, new Fraction(1)),
            new PhysicalUnitTerm(Unit2, new Fraction(1))
        );
        OnPropertyChanged(nameof(EquationTerms));
    }
    
    private void UpdateConversion()
    {
        if (ResultUnit == null || TargetUnit == null) return;
        
        var resultValue = Value1 * Value2; // Simplified
        ConvertedValue = ResultUnit.ConvertValue(TargetUnit, resultValue);
    }
}

🎬 Real-World Use Cases

Engineering Calculator


<StackPanel>
    <TextBlock Text="Force (F):" />
    <StackPanel Orientation="Horizontal">
        <TextBox Text="{Binding Force}" Width="100"/>
        <puw:PhysicalUnitBuilderButtonView SelectedUnit="{Binding ForceUnit}"/>
    </StackPanel>
    
    <TextBlock Text="Area (A):" />
    <StackPanel Orientation="Horizontal">
        <TextBox Text="{Binding Area}" Width="100"/>
        <puw:PhysicalUnitBuilderButtonView SelectedUnit="{Binding AreaUnit}"/>
    </StackPanel>
    
    <TextBlock Text="Stress (Οƒ):" />
    <pue:PhysicalUnitEquationResultButtonView 
        EquationTerms="{Binding StressEquation}"
        SelectedUnit="{Binding StressUnit}"/>
    
</StackPanel>

Scientific Data Entry


<DataGrid ItemsSource="{Binding Measurements}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Value" Binding="{Binding Value}"/>
        <DataGridTemplateColumn Header="Unit">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <puw:PhysicalUnitBuilderButtonView 
                        SelectedUnit="{Binding Unit, Mode=TwoWay}"
                        UnitToConvert="{Binding DataContext.RequiredUnit, 
                                       RelativeSource={RelativeSource AncestorType=DataGrid}}"
                        IsOnlyConvertion="True"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGrid.Columns>
    </DataGrid.Columns>
</DataGrid>

Physics Problem Solver


<StackPanel>
    <TextBlock Text="Mass:" />
    <puw:PhysicalUnitBuilderButtonView SelectedUnit="{Binding Mass}"/>
    
    <TextBlock Text="Velocity:" />
    <puw:PhysicalUnitBuilderButtonView SelectedUnit="{Binding Velocity}"/>
    
    <TextBlock Text="Energy Result:" />
    <pue:PhysicalUnitEquationResultButtonView 
        EquationTerms="{Binding EnergyEquation}"
        SelectedUnit="{Binding EnergyUnit}"/>
    
</StackPanel>

🎨 Customization

Styling the Controls

All controls support standard WPF styling:

<puw:PhysicalUnitBuilderButtonView 
    SelectedUnit="{Binding MyUnit}"
    Background="LightBlue"
    Foreground="DarkBlue"
    FontSize="14"
    Padding="10,5"/>

Repository Settings

Configure available unit systems programmatically:

using MatthL.PhysicalUnits.Infrastructure.Repositories;

// Show only SI and Metric units
PhysicalUnitRepository.Settings.ShowMetrics = true;
PhysicalUnitRepository.Settings.ShowImperial = false;
PhysicalUnitRepository.Settings.ShowUS = false;
PhysicalUnitRepository.Settings.ShowAstronomic = false;
PhysicalUnitRepository.Settings.ShowOther = false;

Custom Suggestions

Control the suggestion behavior:

<pue:PhysicalUnitEquationResultButtonView 
    EquationTerms="{Binding Equation}"
    SelectedUnit="{Binding Unit}"
    MaxSuggestions="5"/>  

πŸ”§ Advanced Scenarios

Building Custom Units

Enable building mode to let users create composite units:

// In your ViewModel
public void EnableUnitBuilding()
{
    // When IsInBuilding is true, users can double-click units to combine them
    BuilderViewModel.IsInBuilding = true;
}

Working with ViewModels

The package provides ready-to-use ViewModels:

using MatthL.PhysicalUnits.UI.ViewModels;

// PhysicalUnitViewModel - wraps a PhysicalUnit with observable properties
var unitViewModel = new PhysicalUnitViewModel(myUnit);
unitViewModel.CanEdit = true;
unitViewModel.GotModified += OnUnitModified;

// BaseUnitViewModel - wraps individual base units
var baseUnitViewModel = new BaseUnitViewModel(baseUnit);
baseUnitViewModel.Prefix = Prefix.kilo;

Event Handling

All controls expose useful events:

builderButtonView.SelectedUnitChanged += (sender, unit) =>
{
    Console.WriteLine($"User selected: {unit.Name}");
};

πŸ“Š Control Comparison

Control Use Case Complexity Best For
PhysicalUnitBuilderButtonView General unit selection Medium Most applications
PhysicalUnitEquationResultButtonView Formula-based selection Low Calculators, physics apps
SpecificUnitSelectorView Limited predefined units Low Simple dropdowns
PhysicalUnitBuilderView Advanced unit building High Power users, custom units
RepositorySettingButtonView System configuration Low App settings

🎯 Design Principles

These controls follow WPF best practices:

  • MVVM-Friendly - Full support for data binding and commands
  • Dependency Properties - All key properties are bindable
  • Reusable - Drop into any WPF application
  • Performant - Optimized for smooth UI interactions
  • Accessible - Keyboard navigation and screen reader support

🀝 Contributing

Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ’€ Author

MatthL

πŸ™ Acknowledgments

  • Built with ❀️ for WPF developers who need professional unit handling
  • Powered by MatthL.PhysicalUnits
  • Thanks to the WPF community for feedback and support

<div align="center">

Ready to give your users powerful unit manipulation capabilities?

Install now: dotnet add package MatthL.PhysicalUnits.WPF


Made with ❀️ by Matthieu L

</div>

Product Compatible and additional computed target framework versions.
.NET net8.0-windows7.0 is compatible.  net9.0-windows was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 245 10/7/2025