Added cost details window.
This commit is contained in:
+8
-1
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using UCalc.Controls;
|
||||||
using UCalc.Data;
|
using UCalc.Data;
|
||||||
|
|
||||||
namespace UCalc
|
namespace UCalc
|
||||||
@@ -11,9 +12,15 @@ namespace UCalc
|
|||||||
public static readonly SolidColorBrush MainColor = Brushes.White;
|
public static readonly SolidColorBrush MainColor = Brushes.White;
|
||||||
public static readonly SolidColorBrush SubMainColor = new SolidColorBrush(Color.FromRgb(0x00, 0x7A, 0xCC));
|
public static readonly SolidColorBrush SubMainColor = new SolidColorBrush(Color.FromRgb(0x00, 0x7A, 0xCC));
|
||||||
|
|
||||||
public const string DecimalFormat = "0.00";
|
public const int InternalPrecision = 6;
|
||||||
|
public const int DisplayPrecision = 2;
|
||||||
public const string DateFormat = "dd.MM.yyyy";
|
public const string DateFormat = "dd.MM.yyyy";
|
||||||
|
|
||||||
|
public static readonly string InternalPrecisionFormat =
|
||||||
|
Helpers.PrecisionToFormat(InternalPrecision, InternalPrecision - 2);
|
||||||
|
|
||||||
|
public static readonly string DisplayPrecisionFormat = Helpers.PrecisionToFormat(DisplayPrecision);
|
||||||
|
|
||||||
public static readonly ImmutableList<string> SalutationStrs =
|
public static readonly ImmutableList<string> SalutationStrs =
|
||||||
((Salutation[]) Enum.GetValues(typeof(Salutation))).Select(value => value.AsString()).ToImmutableList();
|
((Salutation[]) Enum.GetValues(typeof(Salutation))).Select(value => value.AsString()).ToImmutableList();
|
||||||
|
|
||||||
|
|||||||
@@ -37,5 +37,10 @@ namespace UCalc.Controls
|
|||||||
{
|
{
|
||||||
return start1.IsBetween(start2, end2) || start2.IsBetween(start1, end1);
|
return start1.IsBetween(start2, end2) || start2.IsBetween(start1, end1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string PrecisionToFormat(int precision, int optional = 0)
|
||||||
|
{
|
||||||
|
return $"0.{new string('0', precision - optional)}{new string('#', optional)}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
<Window x:Class="UCalc.CostEntryDetailsWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:UCalc"
|
||||||
|
xmlns:controls="clr-namespace:UCalc.Controls"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="Details und Hilfswerkzeuge"
|
||||||
|
Width="340"
|
||||||
|
SizeToContent="Height"
|
||||||
|
ResizeMode="NoResize"
|
||||||
|
WindowStyle="ToolWindow"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
|
ShowInTaskbar="False"
|
||||||
|
Closed="OnClosed">
|
||||||
|
|
||||||
|
<StackPanel>
|
||||||
|
<TabControl x:Name="TabControl">
|
||||||
|
<TabItem Header="Taschenrechner">
|
||||||
|
<StackPanel Margin="8"
|
||||||
|
Height="250">
|
||||||
|
<TextBox Name="ResultTextBox"
|
||||||
|
MinHeight="22"
|
||||||
|
KeyUp="OnResultTextBoxKeyUp" />
|
||||||
|
|
||||||
|
<Grid Margin="0, 8, 0, 0">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="30" />
|
||||||
|
<RowDefinition Height="30" />
|
||||||
|
<RowDefinition Height="30" />
|
||||||
|
<RowDefinition Height="30" />
|
||||||
|
<RowDefinition Height="30" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button Grid.Row="0" Grid.Column="0" Content="CE" Click="OnCEClick" />
|
||||||
|
<Button Grid.Row="0" Grid.Column="1" Content="(" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="0" Grid.Column="2" Content=")" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="0" Grid.Column="3" Content="/" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="1" Grid.Column="0" Content="1" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="1" Grid.Column="1" Content="2" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="1" Grid.Column="2" Content="3" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="1" Grid.Column="3" Content="*" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="2" Grid.Column="0" Content="4" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="2" Grid.Column="1" Content="5" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="2" Grid.Column="2" Content="6" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="2" Grid.Column="3" Content="-" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="3" Grid.Column="0" Content="7" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="3" Grid.Column="1" Content="8" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="3" Grid.Column="2" Content="9" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="3" Grid.Column="3" Content="+" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="4" Grid.Column="0" Content="Aufrunden" Click="OnRoundClick" />
|
||||||
|
<Button Grid.Row="4" Grid.Column="1" Content="0" Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="4" Grid.Column="2" Content="," Click="OnButtonClick" />
|
||||||
|
<Button Grid.Row="4" Grid.Column="3" Content="=" Click="OnEvalClick" />
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="Einheitenrechner">
|
||||||
|
<StackPanel Margin="8"
|
||||||
|
Height="250">
|
||||||
|
<TextBlock
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Text="Dieser Rechner kann benutzt werden, um den Verbrauch von einem Preis pro Einheit umzurechnen (z.B. Wasserverbrauch)."
|
||||||
|
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||||
|
|
||||||
|
<DockPanel Margin="0, 12, 0, 0">
|
||||||
|
<Label DockPanel.Dock="Left"
|
||||||
|
Content="Gesamtbetrag:"
|
||||||
|
Width="160"
|
||||||
|
Foreground="{x:Static local:Constants.SubMainColor}"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<controls:ErrorIcon Margin="12, 0, 0, 0"
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Property="{Binding Path=Details.TotalAmount, RelativeSource={RelativeSource AncestorType=local:CostEntryDetailsWindow}}" />
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
MinHeight="22"
|
||||||
|
Text="{Binding Path=Details.TotalAmount.Value, RelativeSource={RelativeSource AncestorType=local:CostEntryDetailsWindow}, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
|
<DockPanel Margin="0, 4, 0, 0">
|
||||||
|
<Label DockPanel.Dock="Left"
|
||||||
|
Content="Gesamtverbrauch:"
|
||||||
|
Width="160"
|
||||||
|
Foreground="{x:Static local:Constants.SubMainColor}"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<controls:ErrorIcon Margin="12, 0, 0, 0"
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Property="{Binding Path=Details.UnitCount, RelativeSource={RelativeSource AncestorType=local:CostEntryDetailsWindow}}" />
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
MinHeight="22"
|
||||||
|
Text="{Binding Path=Details.UnitCount.Value, RelativeSource={RelativeSource AncestorType=local:CostEntryDetailsWindow}, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
|
<controls:HighlightButton Margin="0, 8, 0, 0"
|
||||||
|
HighlightForeground="{x:Static local:Constants.SubMainColor}"
|
||||||
|
HighlightBackground="{x:Static local:Constants.MainColor}"
|
||||||
|
Click="OnAddDiscountClick">
|
||||||
|
<Viewbox Width="16"
|
||||||
|
Height="16"
|
||||||
|
Margin="12, 8, 4, 8"
|
||||||
|
Stretch="Uniform">
|
||||||
|
<Canvas Width="512" Height="512">
|
||||||
|
<Canvas.RenderTransform>
|
||||||
|
<TranslateTransform X="0" Y="0" />
|
||||||
|
</Canvas.RenderTransform>
|
||||||
|
<Path>
|
||||||
|
<Path.Data>
|
||||||
|
<PathGeometry
|
||||||
|
Figures="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"
|
||||||
|
FillRule="NonZero" />
|
||||||
|
</Path.Data>
|
||||||
|
</Path>
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
|
||||||
|
<Label Content="Abzug hinzufügen"
|
||||||
|
Margin="0, 8, 12, 8" />
|
||||||
|
</controls:HighlightButton>
|
||||||
|
|
||||||
|
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
|
||||||
|
VerticalScrollBarVisibility="Visible"
|
||||||
|
Height="80">
|
||||||
|
<ItemsControl
|
||||||
|
ItemsSource="{Binding Path=Details.DiscountsInUnits, RelativeSource={RelativeSource AncestorType=local:CostEntryDetailsWindow}}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<DockPanel Margin="0, 0, 0, 4">
|
||||||
|
<Label DockPanel.Dock="Left"
|
||||||
|
Content="Abzug vom Verbrauch:"
|
||||||
|
Width="160"
|
||||||
|
Foreground="{x:Static local:Constants.SubMainColor}"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<controls:HighlightButton DockPanel.Dock="Right"
|
||||||
|
HighlightForeground="Red"
|
||||||
|
HighlightBackground="White"
|
||||||
|
Click="OnDiscountDeleteClick">
|
||||||
|
<Viewbox Width="16"
|
||||||
|
Height="16"
|
||||||
|
Margin="8, 6, 8, 6"
|
||||||
|
Stretch="Uniform">
|
||||||
|
<Canvas Width="448" Height="512">
|
||||||
|
<Canvas.RenderTransform>
|
||||||
|
<TranslateTransform X="0" Y="0" />
|
||||||
|
</Canvas.RenderTransform>
|
||||||
|
<Path>
|
||||||
|
<Path.Data>
|
||||||
|
<PathGeometry
|
||||||
|
Figures="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"
|
||||||
|
FillRule="NonZero" />
|
||||||
|
</Path.Data>
|
||||||
|
</Path>
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
</controls:HighlightButton>
|
||||||
|
|
||||||
|
<controls:ErrorIcon Margin="12, 0, 8, 0"
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Property="{Binding Path=.}" />
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
MinHeight="22"
|
||||||
|
Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</DockPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</ScrollViewer>
|
||||||
|
</StackPanel>
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
|
|
||||||
|
<DockPanel Margin="8">
|
||||||
|
<Button x:Name="ApplyButton"
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
Content="Übernehmen"
|
||||||
|
MinWidth="100"
|
||||||
|
MinHeight="24"
|
||||||
|
Click="OnApplyClick"
|
||||||
|
IsEnabled="False" />
|
||||||
|
|
||||||
|
<Label VerticalAlignment="Center"
|
||||||
|
Content="{Binding Path=ResultStr, RelativeSource={RelativeSource AncestorType=local:CostEntryDetailsWindow}}"
|
||||||
|
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||||
|
</DockPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</Window>
|
||||||
@@ -0,0 +1,346 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using UCalc.Annotations;
|
||||||
|
using UCalc.Controls;
|
||||||
|
using UCalc.Models;
|
||||||
|
|
||||||
|
namespace UCalc
|
||||||
|
{
|
||||||
|
public partial class CostEntryDetailsWindow : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
public CostEntryDetailsProperty Details { get; }
|
||||||
|
private decimal? _result;
|
||||||
|
|
||||||
|
public decimal? Result
|
||||||
|
{
|
||||||
|
get => _result;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (_result == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_result = value;
|
||||||
|
ApplyButton.IsEnabled = value != null;
|
||||||
|
OnPropertyChanged();
|
||||||
|
OnPropertyChanged("ResultStr");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ResultStr =>
|
||||||
|
_result != null ? $"Betrag: {_result.Value.ToString(Constants.DisplayPrecisionFormat)} €" : "";
|
||||||
|
|
||||||
|
public CostEntryDetailsWindow(CostEntryDetailsProperty details)
|
||||||
|
{
|
||||||
|
Details = details;
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
Details.TotalAmount.PropertyChanged += DetailsPropertyChanged;
|
||||||
|
Details.UnitCount.PropertyChanged += DetailsPropertyChanged;
|
||||||
|
Details.DiscountsInUnits.CollectionChanged += DetailsDiscountChanged;
|
||||||
|
|
||||||
|
DetailsPropertyChanged(null, null);
|
||||||
|
|
||||||
|
if (Details.TotalAmount.ConvertedValue != 0 || Details.UnitCount.ConvertedValue != 0 ||
|
||||||
|
Details.DiscountsInUnits.Count != 0)
|
||||||
|
{
|
||||||
|
TabControl.SelectedIndex = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetailsPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var totalAmount = Details.TotalAmount.ConvertedValue;
|
||||||
|
var unitCount = Details.UnitCount.ConvertedValue;
|
||||||
|
|
||||||
|
if (totalAmount == null || unitCount == null)
|
||||||
|
{
|
||||||
|
Result = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
decimal totalDiscount = 0;
|
||||||
|
foreach (var discount in Details.DiscountsInUnits)
|
||||||
|
{
|
||||||
|
var n = discount.ConvertedValue;
|
||||||
|
if (n == null)
|
||||||
|
{
|
||||||
|
Result = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalDiscount += n.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = unitCount != 0
|
||||||
|
? totalAmount / unitCount * (unitCount - totalDiscount)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DetailsDiscountChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
foreach (var discount in Details.DiscountsInUnits)
|
||||||
|
{
|
||||||
|
discount.PropertyChanged -= DetailsPropertyChanged;
|
||||||
|
discount.PropertyChanged += DetailsPropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCEClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
ResultTextBox.Text = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
ResultTextBox.Text += (string) ((Button) sender).Content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRoundClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
ResultTextBox.Text = "ceil(" + ResultTextBox.Text + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEvalClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Result = Calc(ResultTextBox.Text);
|
||||||
|
|
||||||
|
ResultTextBox.Text = Result.Value.ToString(Constants.InternalPrecisionFormat);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Result = null;
|
||||||
|
|
||||||
|
ResultTextBox.Text = "Ungültig!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnResultTextBoxKeyUp(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Enter)
|
||||||
|
{
|
||||||
|
OnEvalClick(sender, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static decimal Calc(string str)
|
||||||
|
{
|
||||||
|
var tokens = Tokenize(str);
|
||||||
|
var pos = 0;
|
||||||
|
|
||||||
|
var result = CalcPlus(tokens, ref pos);
|
||||||
|
if (pos != tokens.Count)
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static decimal CalcPlus(List<string> tokens, ref int pos)
|
||||||
|
{
|
||||||
|
var result = CalcMul(tokens, ref pos);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// + or - might follow
|
||||||
|
if (pos >= tokens.Count)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var op = tokens[pos];
|
||||||
|
if (op != "+" && op != "-")
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++pos;
|
||||||
|
|
||||||
|
var result2 = CalcMul(tokens, ref pos);
|
||||||
|
if (op == "+")
|
||||||
|
{
|
||||||
|
result += result2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result -= result2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static decimal CalcMul(List<string> tokens, ref int pos)
|
||||||
|
{
|
||||||
|
var result = CalcSimple(tokens, ref pos);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// * or / might follow
|
||||||
|
if (pos >= tokens.Count)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var op = tokens[pos];
|
||||||
|
if (op != "*" && op != "/")
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++pos;
|
||||||
|
|
||||||
|
var result2 = CalcSimple(tokens, ref pos);
|
||||||
|
if (op == "*")
|
||||||
|
{
|
||||||
|
result *= result2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result /= result2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static decimal CalcSimple(List<string> tokens, ref int pos)
|
||||||
|
{
|
||||||
|
var token = tokens[pos];
|
||||||
|
++pos;
|
||||||
|
|
||||||
|
decimal result;
|
||||||
|
|
||||||
|
switch (token)
|
||||||
|
{
|
||||||
|
case "(":
|
||||||
|
result = CalcPlus(tokens, ref pos);
|
||||||
|
if (tokens[pos] != ")")
|
||||||
|
throw new Exception();
|
||||||
|
++pos;
|
||||||
|
return result;
|
||||||
|
case "ceil":
|
||||||
|
result = CalcPlus(tokens, ref pos);
|
||||||
|
return Math.Round(result, 2);
|
||||||
|
default:
|
||||||
|
return decimal.Parse(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> Tokenize(string str)
|
||||||
|
{
|
||||||
|
var tokens = new List<string>();
|
||||||
|
var token = "";
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
while (i < str.Length)
|
||||||
|
{
|
||||||
|
var c = str[i];
|
||||||
|
++i;
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
case ',':
|
||||||
|
token += c;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
case '*':
|
||||||
|
case '/':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
if (token != "")
|
||||||
|
{
|
||||||
|
tokens.Add(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.Add(c.ToString());
|
||||||
|
token = "";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Must be ceil
|
||||||
|
if (token != "")
|
||||||
|
{
|
||||||
|
tokens.Add(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.Substring(i - 1, 4) == "ceil")
|
||||||
|
{
|
||||||
|
tokens.Add("ceil");
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token != "")
|
||||||
|
{
|
||||||
|
tokens.Add(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
[NotifyPropertyChangedInvocator]
|
||||||
|
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnApplyClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAddDiscountClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Details.DiscountsInUnits.Add();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDiscountDeleteClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var discount = (DiscountProperty) ((HighlightButton) sender).DataContext;
|
||||||
|
|
||||||
|
Details.DiscountsInUnits.Remove(discount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClosed(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Details.TotalAmount.PropertyChanged -= DetailsPropertyChanged;
|
||||||
|
Details.UnitCount.PropertyChanged -= DetailsPropertyChanged;
|
||||||
|
Details.DiscountsInUnits.CollectionChanged -= DetailsDiscountChanged;
|
||||||
|
|
||||||
|
foreach (var discount in Details.DiscountsInUnits)
|
||||||
|
{
|
||||||
|
discount.PropertyChanged -= DetailsPropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+55
-22
@@ -177,28 +177,61 @@
|
|||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<controls:HighlightButton DockPanel.Dock="Right"
|
<Grid DockPanel.Dock="Right">
|
||||||
HighlightForeground="Red"
|
<Grid.RowDefinitions>
|
||||||
HighlightBackground="White"
|
<RowDefinition Height="*" />
|
||||||
Click="OnCostEntryDeleteClick">
|
<RowDefinition Height="*" />
|
||||||
<Viewbox Width="24"
|
</Grid.RowDefinitions>
|
||||||
Height="24"
|
|
||||||
Margin="8, 12, 8, 12"
|
<controls:HighlightButton
|
||||||
Stretch="Uniform">
|
HighlightForeground="{x:Static local:Constants.SubMainColor}"
|
||||||
<Canvas Width="448" Height="512">
|
HighlightBackground="{x:Static local:Constants.MainColor}"
|
||||||
<Canvas.RenderTransform>
|
Grid.Row="0"
|
||||||
<TranslateTransform X="0" Y="0" />
|
ToolTip="Details und Hilfswerkzeuge zur Berechnung"
|
||||||
</Canvas.RenderTransform>
|
Click="OnCostEntryDetailsClick">
|
||||||
<Path>
|
|
||||||
<Path.Data>
|
<Viewbox Width="24"
|
||||||
<PathGeometry
|
Height="24"
|
||||||
Figures="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"
|
Margin="8, 12, 8, 12"
|
||||||
FillRule="NonZero" />
|
Stretch="Uniform">
|
||||||
</Path.Data>
|
<Canvas Width="512" Height="512">
|
||||||
</Path>
|
<Canvas.RenderTransform>
|
||||||
</Canvas>
|
<TranslateTransform X="0" Y="0" />
|
||||||
</Viewbox>
|
</Canvas.RenderTransform>
|
||||||
</controls:HighlightButton>
|
<Path>
|
||||||
|
<Path.Data>
|
||||||
|
<PathGeometry
|
||||||
|
Figures="M328 256c0 39.8-32.2 72-72 72s-72-32.2-72-72 32.2-72 72-72 72 32.2 72 72zm104-72c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72zm-352 0c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72z"
|
||||||
|
FillRule="NonZero" />
|
||||||
|
</Path.Data>
|
||||||
|
</Path>
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
</controls:HighlightButton>
|
||||||
|
|
||||||
|
<controls:HighlightButton HighlightForeground="Red"
|
||||||
|
HighlightBackground="White"
|
||||||
|
Grid.Row="1"
|
||||||
|
Click="OnCostEntryDeleteClick">
|
||||||
|
<Viewbox Width="24"
|
||||||
|
Height="24"
|
||||||
|
Margin="8, 12, 8, 12"
|
||||||
|
Stretch="Uniform">
|
||||||
|
<Canvas Width="448" Height="512">
|
||||||
|
<Canvas.RenderTransform>
|
||||||
|
<TranslateTransform X="0" Y="0" />
|
||||||
|
</Canvas.RenderTransform>
|
||||||
|
<Path>
|
||||||
|
<Path.Data>
|
||||||
|
<PathGeometry
|
||||||
|
Figures="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"
|
||||||
|
FillRule="NonZero" />
|
||||||
|
</Path.Data>
|
||||||
|
</Path>
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
</controls:HighlightButton>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<StackPanel Margin="0, 8, 8, 8">
|
<StackPanel Margin="0, 8, 8, 8">
|
||||||
<DockPanel Margin="0, 0, 0, 2">
|
<DockPanel Margin="0, 0, 0, 2">
|
||||||
|
|||||||
@@ -51,5 +51,16 @@ namespace UCalc
|
|||||||
{
|
{
|
||||||
Cost.Entries.Add();
|
Cost.Entries.Add();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCostEntryDetailsClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var entry = (CostEntryProperty) ((HighlightButton) sender).DataContext;
|
||||||
|
|
||||||
|
var detailsWindow = new CostEntryDetailsWindow(entry.Details) {Owner = this};
|
||||||
|
if (detailsWindow.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
entry.Amount.Value = detailsWindow.Result!.Value.ToString(Constants.DisplayPrecisionFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,8 @@ namespace UCalc.Models
|
|||||||
|
|
||||||
public void Add()
|
public void Add()
|
||||||
{
|
{
|
||||||
|
using var validator = Model.BeginValidation(true);
|
||||||
|
|
||||||
var entry = new CostEntryProperty(Model, this, new CostEntry());
|
var entry = new CostEntryProperty(Model, this, new CostEntry());
|
||||||
entry.StartDate.Value = null;
|
entry.StartDate.Value = null;
|
||||||
entry.EndDate.Value = null;
|
entry.EndDate.Value = null;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UCalc.Controls;
|
using UCalc.Controls;
|
||||||
using UCalc.Data;
|
using UCalc.Data;
|
||||||
@@ -69,19 +70,148 @@ namespace UCalc.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TotalAmountProperty : PositiveDecimalProperty
|
||||||
|
{
|
||||||
|
public TotalAmountProperty(Model model, Property parent, string name, decimal value) : base(model, parent, name,
|
||||||
|
value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string ValidateValue()
|
||||||
|
{
|
||||||
|
var entry = (CostEntryDetailsProperty) Parent;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var error = base.ValidateValue();
|
||||||
|
if (error != "")
|
||||||
|
{
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((entry.UnitCount.ConvertedValue ?? 1) != 0 || entry.DiscountsInUnits.Count > 0) &&
|
||||||
|
ConvertedValue == 0)
|
||||||
|
{
|
||||||
|
return $"{Name}: Der Wert muss größer als 0 sein.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
using var validator = Model.BeginValidation();
|
||||||
|
validator.Validate(entry.UnitCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UnitCountProperty : PositiveMoreExactDecimalProperty
|
||||||
|
{
|
||||||
|
public UnitCountProperty(Model model, Property parent, string name, decimal value) : base(model, parent, name,
|
||||||
|
value, Constants.InternalPrecision)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string ValidateValue()
|
||||||
|
{
|
||||||
|
var entry = (CostEntryDetailsProperty) Parent;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var error = base.ValidateValue();
|
||||||
|
if (error != "")
|
||||||
|
{
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((entry.TotalAmount.ConvertedValue ?? 1) != 0 || entry.DiscountsInUnits.Count > 0) &&
|
||||||
|
ConvertedValue == 0)
|
||||||
|
{
|
||||||
|
return $"{Name}: Der Wert muss größer als 0 sein.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
using var validator = Model.BeginValidation();
|
||||||
|
validator.Validate(entry.TotalAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscountProperty : PositiveDecimalProperty
|
||||||
|
{
|
||||||
|
public DiscountProperty(Model model, Property parent, string name, decimal value) : base(model, parent, name,
|
||||||
|
value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string ValidateValue()
|
||||||
|
{
|
||||||
|
var error = base.ValidateValue();
|
||||||
|
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiscountsProperty : MultiProperty<DiscountProperty>
|
||||||
|
{
|
||||||
|
public DiscountsProperty(Model model, Property parent, IEnumerable<decimal> data) : base(model, parent)
|
||||||
|
{
|
||||||
|
foreach (var discount in data)
|
||||||
|
{
|
||||||
|
Add(new DiscountProperty(Model, this, "Abzug", discount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add()
|
||||||
|
{
|
||||||
|
using var validator = Model.BeginValidation();
|
||||||
|
|
||||||
|
Add(new DiscountProperty(Model, this, "Abzug", 0));
|
||||||
|
|
||||||
|
validator.Validate(((CostEntryDetailsProperty) Parent).UnitCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Remove(DiscountProperty discount)
|
||||||
|
{
|
||||||
|
using var validator = Model.BeginValidation();
|
||||||
|
|
||||||
|
base.Remove(discount);
|
||||||
|
|
||||||
|
validator.Validate(((CostEntryDetailsProperty) Parent).UnitCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CostEntryDetailsProperty : NestedProperty
|
||||||
|
{
|
||||||
|
public TotalAmountProperty TotalAmount { get; }
|
||||||
|
public UnitCountProperty UnitCount { get; }
|
||||||
|
public DiscountsProperty DiscountsInUnits { get; }
|
||||||
|
|
||||||
|
public CostEntryDetailsProperty(Model model, Property parent, CostEntryDetails data) : base(model, parent)
|
||||||
|
{
|
||||||
|
TotalAmount = Add(new TotalAmountProperty(model, this, "Gesamtbetrag", data.TotalAmount));
|
||||||
|
UnitCount = Add(new UnitCountProperty(model, this, "Gesamtverbrauch", data.UnitCount));
|
||||||
|
DiscountsInUnits = Add(new DiscountsProperty(model, this, data.DiscountsInUnits));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class CostEntryProperty : NestedProperty
|
public class CostEntryProperty : NestedProperty
|
||||||
{
|
{
|
||||||
public DateProperty StartDate { get; }
|
public DateProperty StartDate { get; }
|
||||||
public EndDateProperty EndDate { get; }
|
public EndDateProperty EndDate { get; }
|
||||||
public PositiveDecimalProperty Amount { get; }
|
public PositiveDecimalProperty Amount { get; }
|
||||||
|
public CostEntryDetailsProperty Details { get; }
|
||||||
// TODO: Details
|
|
||||||
|
|
||||||
public CostEntryProperty(Model model, Property parent, CostEntry data) : base(model, parent)
|
public CostEntryProperty(Model model, Property parent, CostEntry data) : base(model, parent)
|
||||||
{
|
{
|
||||||
StartDate = Add(new DateProperty(model, this, "Startdatum", data.StartDate));
|
StartDate = Add(new DateProperty(model, this, "Startdatum", data.StartDate));
|
||||||
EndDate = Add(new EndDateProperty(model, this, "Enddatum", data.EndDate));
|
EndDate = Add(new EndDateProperty(model, this, "Enddatum", data.EndDate));
|
||||||
Amount = Add(new PositiveDecimalProperty(model, this, "Betrag", data.Amount));
|
Amount = Add(new PositiveDecimalProperty(model, this, "Betrag", data.Amount));
|
||||||
|
Details = Add(new CostEntryDetailsProperty(model, this, data.Details));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+24
-10
@@ -14,6 +14,7 @@ namespace UCalc.Models
|
|||||||
{
|
{
|
||||||
private readonly Model _model;
|
private readonly Model _model;
|
||||||
private int _counter;
|
private int _counter;
|
||||||
|
private int _postPoneCounter;
|
||||||
private readonly HashSet<Property> _validated;
|
private readonly HashSet<Property> _validated;
|
||||||
private readonly HashSet<Tuple<Property, string>> _notifications;
|
private readonly HashSet<Tuple<Property, string>> _notifications;
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ namespace UCalc.Models
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_validated.Add(property) && !_model._loading)
|
if (_validated.Add(property) && _postPoneCounter == 0)
|
||||||
{
|
{
|
||||||
property.Validate();
|
property.Validate();
|
||||||
}
|
}
|
||||||
@@ -63,15 +64,33 @@ namespace UCalc.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void IncValidationCounter()
|
public void IncValidationCounter(bool postPone)
|
||||||
{
|
{
|
||||||
++_counter;
|
++_counter;
|
||||||
|
|
||||||
|
if (postPone || _postPoneCounter != 0)
|
||||||
|
{
|
||||||
|
++_postPoneCounter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
--_counter;
|
--_counter;
|
||||||
|
|
||||||
|
if (_postPoneCounter > 0)
|
||||||
|
{
|
||||||
|
--_postPoneCounter;
|
||||||
|
|
||||||
|
if (_postPoneCounter == 0)
|
||||||
|
{
|
||||||
|
var queue = new List<Property>(_validated);
|
||||||
|
_validated.Clear();
|
||||||
|
|
||||||
|
ValidateRange(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_counter == 0)
|
if (_counter == 0)
|
||||||
{
|
{
|
||||||
_validated.Clear();
|
_validated.Clear();
|
||||||
@@ -140,7 +159,6 @@ namespace UCalc.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly Validator _validator;
|
private readonly Validator _validator;
|
||||||
private readonly bool _loading;
|
|
||||||
public DateTime StartDate { get; }
|
public DateTime StartDate { get; }
|
||||||
public DateTime EndDate { get; }
|
public DateTime EndDate { get; }
|
||||||
public BillingProperty Root { get; }
|
public BillingProperty Root { get; }
|
||||||
@@ -151,17 +169,13 @@ namespace UCalc.Models
|
|||||||
StartDate = billing.StartDate;
|
StartDate = billing.StartDate;
|
||||||
EndDate = billing.EndDate;
|
EndDate = billing.EndDate;
|
||||||
|
|
||||||
_loading = true;
|
using var validator = BeginValidation(true);
|
||||||
Root = new BillingProperty(this, null, billing);
|
Root = new BillingProperty(this, null, billing);
|
||||||
_loading = false;
|
|
||||||
|
|
||||||
using var validator = BeginValidation();
|
|
||||||
validator.Validate(Root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Validator BeginValidation()
|
public Validator BeginValidation(bool postPone = false)
|
||||||
{
|
{
|
||||||
_validator.IncValidationCounter();
|
_validator.IncValidationCounter(postPone);
|
||||||
return _validator;
|
return _validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.ComponentModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using UCalc.Annotations;
|
using UCalc.Annotations;
|
||||||
|
using UCalc.Controls;
|
||||||
|
|
||||||
namespace UCalc.Models
|
namespace UCalc.Models
|
||||||
{
|
{
|
||||||
@@ -181,30 +182,49 @@ namespace UCalc.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PositiveDecimalProperty : ValueProperty<string>
|
public class PositiveMoreExactDecimalProperty : ValueProperty<string>
|
||||||
{
|
{
|
||||||
public PositiveDecimalProperty(Model model, Property parent, string name, decimal value) : base(model, parent,
|
private readonly int _decimals;
|
||||||
name,
|
public decimal? ConvertedValue { get; private set; }
|
||||||
value.ToString(Constants.DecimalFormat))
|
|
||||||
|
public PositiveMoreExactDecimalProperty(Model model, Property parent, string name, decimal value, int decimals)
|
||||||
|
: base(model, parent, name, value.ToString(Helpers.PrecisionToFormat(decimals, decimals - 2)))
|
||||||
{
|
{
|
||||||
|
_decimals = decimals;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string ValidateValue()
|
protected override string ValidateValue()
|
||||||
{
|
{
|
||||||
if (!decimal.TryParse(Value, out var n) || n < 0)
|
ConvertedValue = null;
|
||||||
|
|
||||||
|
if (!decimal.TryParse(Value, out var n))
|
||||||
{
|
{
|
||||||
return $"{Name}: Der eingegebene Wert ist kein gültiger Betrag.";
|
return $"{Name}: Der eingegebene Wert ist ungültig.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.Round(n, 2) != n)
|
if (n < 0)
|
||||||
{
|
{
|
||||||
return $"{Name}: Der eingegebene Wert besitzt mehr als 2 Nachkommastellen.";
|
return $"{Name}: Der eingegebene Wert darf nicht negativ sein.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Math.Round(n, _decimals) != n)
|
||||||
|
{
|
||||||
|
return $"{Name}: Der eingegebene Wert besitzt mehr als {_decimals} Nachkommastellen.";
|
||||||
|
}
|
||||||
|
|
||||||
|
ConvertedValue = n;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PositiveDecimalProperty : PositiveMoreExactDecimalProperty
|
||||||
|
{
|
||||||
|
public PositiveDecimalProperty(Model model, Property parent, string name, decimal value) : base(model, parent,
|
||||||
|
name, value, Constants.DisplayPrecision)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public abstract class NestedProperty : Property
|
public abstract class NestedProperty : Property
|
||||||
{
|
{
|
||||||
private readonly List<Property> _properties;
|
private readonly List<Property> _properties;
|
||||||
|
|||||||
@@ -46,6 +46,9 @@
|
|||||||
<Page Update="CostWindow.xaml">
|
<Page Update="CostWindow.xaml">
|
||||||
<Generator></Generator>
|
<Generator></Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Update="CostEntryDetailsWindow.xaml">
|
||||||
|
<Generator></Generator>
|
||||||
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -88,6 +91,9 @@
|
|||||||
<Compile Update="CostWindow.xaml.cs">
|
<Compile Update="CostWindow.xaml.cs">
|
||||||
<DependentUpon>CostWindow.xaml</DependentUpon>
|
<DependentUpon>CostWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="CostEntryDetailsWindow.xaml.cs">
|
||||||
|
<DependentUpon>CostEntryDetailsWindow.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user