Skip to content

Add unit converter WPF sample app #380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jan 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Docs/Images/logo-512.ico
Binary file not shown.
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,33 @@ RotationalSpeedUnit rpm2 == RotationalSpeed.ParseUnit("r/min"); // RotationalSp
string abbrevKg = Mass.GetAbbreviation(MassUnit.Kilogram); // "kg"
```

### <a name="example-app"></a>Example: Creating a unit converter app
### <a name="example-app"></a>Example: Creating a dynamic unit converter app

*TODO: Add actual sample app and link to it here with screenshot. See [#274](https://github.com/angularsen/UnitsNet/issues/274) for details.*
![image](https://user-images.githubusercontent.com/787816/34920961-9b697004-f97b-11e7-9e9a-51ff7142969b.png)

See [Samples/UnitConverter.Wpf](https://github.com/angularsen/UnitsNet/tree/master/Samples/UnitConverter.Wpf) for source code.

This example shows how you can create a dynamic unit converter, where the user selects the quantity to convert, such as `Length` or `Mass`, then selects to convert from `Meter` to `Centimeter` and types in a value for how many meters.

NOTE: There are still some limitations in the library that requires reflection to enumerate units for quantity and getting the abbreviation for a unit, when we want to dynamically enumerate and convert between units.

### <a name="example-app-hardcoded"></a>Example: Creating a unit converter app with hard coded quantities

If you can live with hard coding what quantities to convert between, then the following code snippet shows you one way to go about it:

```C#
// Get quantities for populating quantity UI selector
QuantityType[] quantityTypes = Enum.GetValues(typeof(QuantityType)).Cast<QuantityType>().ToArray();

// If Length is selected, get length units for populating from/to UI selectors
LengthUnit[] lengthUnits = Length.Units;

// Perform conversion by using .ToString() on the selected units
// Perform conversion using input value and selected from/to units
double inputValue; // Obtain from textbox
LengthUnit fromUnit, toUnit; // Obtain from ListBox selections
double resultValue = Length.From(inputValue, fromUnit).As(toUnit);

// Alternatively, you can also convert using string representations of units
double centimeters = UnitConverter.ConvertByName(5, "Length", "Meter", "Centimeter"); // 500
double centimeters2 = UnitConverter.ConvertByAbbreviation(5, "Length", "m", "cm"); // 500
```
Expand Down
19 changes: 19 additions & 0 deletions Samples/ConsoleApp-NetCore/ConsoleApp-NetCore.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
<AssemblyName>ConsoleApp-NetCore</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>ConsoleApp-NetCore</PackageId>
<RuntimeFrameworkVersion>1.0.4</RuntimeFrameworkVersion>
<PackageTargetFallback>$(PackageTargetFallback);dnxcore50</PackageTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="UnitsNet" Version="3.45.0" />
</ItemGroup>

</Project>
19 changes: 0 additions & 19 deletions Samples/ConsoleApp-NetCore/ConsoleApp-NetCore.xproj

This file was deleted.

20 changes: 0 additions & 20 deletions Samples/ConsoleApp-NetCore/project.json

This file was deleted.

21 changes: 18 additions & 3 deletions Samples/Samples.sln
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2020
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ConsoleApp-NetCore", "ConsoleApp-NetCore\ConsoleApp-NetCore.xproj", "{955A6CBF-C4E3-4C55-85C8-613E2CA4CCD7}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp-NetCore", "ConsoleApp-NetCore\ConsoleApp-NetCore.csproj", "{955A6CBF-C4E3-4C55-85C8-613E2CA4CCD7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitConverter.Wpf", "UnitConverter.Wpf\UnitConverter.Wpf\UnitConverter.Wpf.csproj", "{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfMVVMSample", "WpfMVVMSample\WpfMVVMSample\WpfMVVMSample.csproj", "{B72F9215-70FF-4155-89BC-9A02CC550447}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -15,8 +19,19 @@ Global
{955A6CBF-C4E3-4C55-85C8-613E2CA4CCD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{955A6CBF-C4E3-4C55-85C8-613E2CA4CCD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{955A6CBF-C4E3-4C55-85C8-613E2CA4CCD7}.Release|Any CPU.Build.0 = Release|Any CPU
{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}.Release|Any CPU.Build.0 = Release|Any CPU
{B72F9215-70FF-4155-89BC-9A02CC550447}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B72F9215-70FF-4155-89BC-9A02CC550447}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B72F9215-70FF-4155-89BC-9A02CC550447}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B72F9215-70FF-4155-89BC-9A02CC550447}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A78FD611-C7A6-472D-95CA-4B474F775CCA}
EndGlobalSection
EndGlobal
13 changes: 13 additions & 0 deletions Samples/UnitConverter.Wpf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Unit Converter WPF Sample App

This is a simple sample showing how UnitsNet can be used to create a generic unit converter, using all the quantities and units available in the UnitsNet library.

![image](https://user-images.githubusercontent.com/787816/34920961-9b697004-f97b-11e7-9e9a-51ff7142969b.png)

It allows you to convert a value from one unit to another, by first selecting the quantity (`Length`), then selecting the from/to units (`Meter` to `Centimeter`) and finally typing the numeric value (`15.3`).
The resulting value (`1530`) is computed instantly and reacts to whenever the numeric value or the from/to unit selection changes.

This sample also highlights a limitation in the library that requires reflection in order to enumerate units for a selected quantity and to get the abbreviation for a unit, since the library does not provide a generic means to retrieve these without referencing types like `Length` and `LengthUnit` directly. There is definitely room for improvement in the library here.

### Dependencies
http://mahapps.com/ - UI toolkit for WPF
25 changes: 25 additions & 0 deletions Samples/UnitConverter.Wpf/UnitConverter.Wpf.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2020
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitConverter.Wpf", "UnitConverter.Wpf\UnitConverter.Wpf.csproj", "{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D04EE35D-496A-4C83-A369-09B9B2BEAEEC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1A5C77D4-9765-41D3-9C68-AC307DED35E2}
EndGlobalSection
EndGlobal
2 changes: 2 additions & 0 deletions Samples/UnitConverter.Wpf/UnitConverter.Wpf.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=Wpf_005FGenericUnitConverter_002EAnnotations/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
6 changes: 6 additions & 0 deletions Samples/UnitConverter.Wpf/UnitConverter.Wpf/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
</configuration>
18 changes: 18 additions & 0 deletions Samples/UnitConverter.Wpf/UnitConverter.Wpf/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Application x:Class="UnitsNet.Samples.UnitConverter.Wpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<!-- Accent and AppTheme setting -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
23 changes: 23 additions & 0 deletions Samples/UnitConverter.Wpf/UnitConverter.Wpf/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Windows;

namespace UnitsNet.Samples.UnitConverter.Wpf
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// BEGIN WORKAROUND
// HACK to fix issue trying to type "1.5" in the Value textbox when bound to a decimal, since "1." is not a valid decimal value
// it will prevent you from typing that.
// We could use Delay=500 in the binding, but it feels weird to only see the updated result value some time after typing
// in a new value.
System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty = false;
// END WORKAROUND

base.OnStartup(e);
}
}
}
31 changes: 31 additions & 0 deletions Samples/UnitConverter.Wpf/UnitConverter.Wpf/DelegateCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Windows.Input;

namespace UnitsNet.Samples.UnitConverter.Wpf
{
/// <summary>
/// Simple <see cref="ICommand" /> implementation, that executes a callback upon executing the command, such as
/// when clicking a button.
/// </summary>
public sealed class DelegateCommand : ICommand
{
private readonly Action _commandDelegate;

public DelegateCommand(Action commandDelegate)
{
_commandDelegate = commandDelegate;
}

public bool CanExecute(object parameter)
{
return true;
}

public void Execute(object parameter)
{
_commandDelegate.Invoke();
}

public event EventHandler CanExecuteChanged;
}
}
30 changes: 30 additions & 0 deletions Samples/UnitConverter.Wpf/UnitConverter.Wpf/IMainWindowVm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;
using UnitsNet.Samples.UnitConverter.Wpf.Properties;

namespace UnitsNet.Samples.UnitConverter.Wpf
{
/// <summary>
/// This interface ensures that the view model and the design-time view model are consistent, since the XAML
/// intellisense only knows about the design-time type.
/// </summary>
public interface IMainWindowVm : INotifyPropertyChanged
{
ReadOnlyObservableCollection<QuantityType> Quantities { get; }
ReadOnlyObservableCollection<UnitListItem> Units { get; }
QuantityType SelectedQuantity { get; set; }

[CanBeNull]
UnitListItem SelectedFromUnit { get; set; }

[CanBeNull]
UnitListItem SelectedToUnit { get; set; }

string FromHeader { get; }
string ToHeader { get; }
decimal FromValue { get; set; }
decimal ToValue { get; }
ICommand SwapCommand { get; }
}
}
80 changes: 80 additions & 0 deletions Samples/UnitConverter.Wpf/UnitConverter.Wpf/MainWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<controls:MetroWindow
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
x:Class="UnitsNet.Samples.UnitConverter.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpf="clr-namespace:UnitsNet.Samples.UnitConverter.Wpf"
mc:Ignorable="d"
Title="UnitsNet - WPF unit converter sample app" Height="350" Width="525"
d:DataContext="{d:DesignInstance wpf:MainWindowDesignVm, IsDesignTimeCreatable=True}">

<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="80" />
</Grid.RowDefinitions>

<GroupBox Header="Quantity" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.RowSpan="2">
<ListBox
ItemsSource="{Binding Path=Quantities}"
SelectedItem="{Binding SelectedQuantity, Mode=TwoWay}"
SelectionChanged="Selector_OnSelectionChanged" />
</GroupBox>

<GroupBox Header="From" Grid.Row="0" Grid.Column="1">
<Grid>
<ListBox
ItemsSource="{Binding Path=Units}"
DisplayMemberPath="Text"
SelectedItem="{Binding SelectedFromUnit, Mode=TwoWay}" />
</Grid>
</GroupBox>

<GroupBox Header="To" Grid.Row="0" Grid.Column="3">
<Grid>
<ListBox
ItemsSource="{Binding Path=Units}"
DisplayMemberPath="Text"
SelectedItem="{Binding SelectedToUnit, Mode=TwoWay}" />
</Grid>
</GroupBox>


<WrapPanel Grid.Row="1" Grid.Column="0" Margin="10">
<!--Placeholder-->
</WrapPanel>

<GroupBox Header="{Binding FromHeader}" Grid.Row="1" Grid.Column="1">
<TextBox FontSize="16" FontWeight="DemiBold" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding FromValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</GroupBox>

<Grid Grid.Row="1" Grid.Column="2">
<Button Content="⇄" Style="{StaticResource MetroCircleButtonStyle}"
Width="50" Height="50"
FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="10"
Command="{Binding SwapCommand}"/>
</Grid>

<GroupBox Header="{Binding ToHeader}" Grid.Row="1" Grid.Column="3">
<TextBox FontSize="16" FontWeight="DemiBold" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding ToValue, Mode=OneWay}" IsReadOnly="true" />
</GroupBox>

</Grid>
</controls:MetroWindow>







Loading