A validation model
Signing and validating the estimate
This commit is contained in:
parent
b7c2c5a3ff
commit
044f145035
28 changed files with 492 additions and 190 deletions
|
|
@ -387,9 +387,9 @@
|
|||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Yavsc.Client\Yavsc.Client.csproj">
|
||||
<ProjectReference Include="..\..\YavscLib\YavscLib.csproj">
|
||||
<Project>{67f9d3a8-f71e-4428-913f-c37ae82cdb24}</Project>
|
||||
<Name>Yavsc.Client</Name>
|
||||
<Name>YavscLib</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\BookAStar\BookAStar.csproj">
|
||||
<Project>{A0815650-0A0A-47B0-8826-771F0E1AD137}</Project>
|
||||
|
|
|
|||
|
|
@ -171,10 +171,6 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Yavsc.Client\Yavsc.Client.csproj">
|
||||
<Project>{67F9D3A8-F71E-4428-913F-C37AE82CDB24}</Project>
|
||||
<Name>Yavsc.Client</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\BookAStar\BookAStar.csproj">
|
||||
<Project>{A0815650-0A0A-47B0-8826-771F0E1AD137}</Project>
|
||||
<Name>BookAStar</Name>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
<Color x:Key="PageForegroundColor">#000000</Color>
|
||||
<Color x:Key="TextColor">#000000</Color>
|
||||
<Color x:Key="LabelColor">#000000</Color>
|
||||
<Color x:Key="ErrorTextColor">#500000</Color>
|
||||
|
||||
<Color x:Key="HeadingTextColor">Black</Color>
|
||||
<Color x:Key="NormalTextColor">Blue</Color>
|
||||
<Color x:Key="GroupingTextColor">#5050ff</Color>
|
||||
|
|
@ -43,9 +45,16 @@
|
|||
<Setter Property="VerticalOptions" Value="Start" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ErrorLabelStyle" BasedOn="{StaticResource InputLabelStyle}" TargetType="Label">
|
||||
<Setter Property="FontSize" Value="Large" />
|
||||
<Setter Property="FontAttributes" Value="Bold" />
|
||||
<Setter Property="TextColor" Value="{StaticResource ErrorTextColor}" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="LabelStyle" TargetType="Label">
|
||||
<Setter Property="TextColor" Value="{StaticResource LabelColor}" />
|
||||
<Setter Property="LineBreakMode" Value="WordWrap" />
|
||||
<Setter Property="HorizontalOptions" Value="FillAndExpand" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="BigLabel" BasedOn="{StaticResource LabelStyle}" TargetType="Label">
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ namespace BookAStar
|
|||
using Data;
|
||||
using Interfaces;
|
||||
using Model;
|
||||
using Model.UI;
|
||||
using Pages;
|
||||
using Plugin.Connectivity;
|
||||
using Model.Social.Messaging;
|
||||
|
|
@ -28,6 +27,7 @@ namespace BookAStar
|
|||
using Pages.UserProfile;
|
||||
using ViewModels.EstimateAndBilling;
|
||||
using Pages.EstimatePages;
|
||||
using ViewModels;
|
||||
|
||||
public partial class App : Application // superclass new in 1.3
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,12 +5,17 @@ namespace BookAStar.Behaviors
|
|||
{
|
||||
public class EditorMaxLengthValidator : Behavior<Editor>
|
||||
{
|
||||
public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create("MaxLength", typeof(int), typeof(EditorMaxLengthValidator), 0);
|
||||
public static readonly BindableProperty MinLengthProperty = BindableProperty.Create("MinLength", typeof(int), typeof(EditorMaxLengthValidator), 0);
|
||||
|
||||
public static readonly BindableProperty MaxLengthProperty =
|
||||
BindableProperty.Create("MaxLength", typeof(int), typeof(EditorMaxLengthValidator), 0);
|
||||
public static readonly BindableProperty MinLengthProperty =
|
||||
BindableProperty.Create("MinLength", typeof(int), typeof(EditorMaxLengthValidator), 0);
|
||||
public static readonly BindableProperty IsValidProperty =
|
||||
BindableProperty.Create("IsValid", typeof(bool), typeof(EditorMaxLengthValidator), false);
|
||||
public static readonly BindableProperty ErrorProperty =
|
||||
BindableProperty.Create("Error", typeof(string), typeof(EditorMaxLengthValidator), null);
|
||||
public int MaxLength
|
||||
{
|
||||
get { return (int)GetValue(MaxLengthProperty); }
|
||||
get { return (int) GetValue(MaxLengthProperty); }
|
||||
set { SetValue(MaxLengthProperty, value); }
|
||||
}
|
||||
public int MinLength
|
||||
|
|
@ -24,13 +29,40 @@ namespace BookAStar.Behaviors
|
|||
bindable.TextChanged += bindable_TextChanged;
|
||||
}
|
||||
|
||||
public bool IsValid { get; set; }
|
||||
public bool IsValid {
|
||||
get { return (bool)GetValue(IsValidProperty); }
|
||||
set { SetValue(IsValidProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string Error
|
||||
{
|
||||
get {
|
||||
return (string)GetValue(ErrorProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(ErrorProperty, value);
|
||||
}
|
||||
}
|
||||
private void bindable_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
IsValid = e.NewTextValue == null? false : ( e.NewTextValue.Length >= MinLength && e.NewTextValue.Length <= MaxLength ) ;
|
||||
if (!IsValid) if (e.NewTextValue!=null) if (e.NewTextValue.Length > MaxLength)
|
||||
((Editor)sender).Text = e.NewTextValue.Substring(0, MaxLength);
|
||||
if (e.NewTextValue != null && e.NewTextValue.Length >= MinLength)
|
||||
{
|
||||
if (e.NewTextValue.Length > MaxLength)
|
||||
{
|
||||
((Editor)sender).Text = e.NewTextValue.Substring(0, MaxLength);
|
||||
Error = Strings.YourTextWasTooLong;
|
||||
}
|
||||
else Error = "";
|
||||
IsValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error = string.Format(Strings.MinMaxStringValidationError,
|
||||
MinLength, MaxLength);
|
||||
IsValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDetachingFrom(Editor bindable)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ namespace BookAStar.Behaviors
|
|||
{
|
||||
public static readonly BindableProperty MinProperty = BindableProperty.Create("Min", typeof(int), typeof(IntegerEntryBehavior), 0);
|
||||
public static readonly BindableProperty MaxProperty = BindableProperty.Create("Max", typeof(int), typeof(IntegerEntryBehavior), 0);
|
||||
|
||||
public static readonly BindableProperty IsValidProperty =
|
||||
BindableProperty.Create("IsValid", typeof(bool), typeof(IntegerEntryBehavior), false);
|
||||
public static readonly BindableProperty ErrorProperty =
|
||||
BindableProperty.Create("Error", typeof(string), typeof(IntegerEntryBehavior), null);
|
||||
public int Min
|
||||
{
|
||||
get { return (int)GetValue(MinProperty); }
|
||||
|
|
@ -30,8 +33,13 @@ namespace BookAStar.Behaviors
|
|||
if (int.TryParse(e.NewTextValue, out val))
|
||||
{
|
||||
IsValid = (Min > Max) || (Max >= val && val >= Min);
|
||||
Error = string.Format(Strings.MinMaxIntError, Min, Max);
|
||||
}
|
||||
else
|
||||
{
|
||||
IsValid = false;
|
||||
Error = "";
|
||||
}
|
||||
else IsValid = false;
|
||||
}
|
||||
|
||||
protected override void OnDetachingFrom(Entry bindable)
|
||||
|
|
@ -39,6 +47,26 @@ namespace BookAStar.Behaviors
|
|||
bindable.TextChanged -= bindable_TextChanged;
|
||||
|
||||
}
|
||||
public bool IsValid { get; private set; }
|
||||
public bool IsValid
|
||||
{
|
||||
get {
|
||||
return (bool) GetValue(IsValidProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(IsValidProperty, value);
|
||||
}
|
||||
}
|
||||
public string Error
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string) GetValue(ErrorProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(ErrorProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,9 @@
|
|||
<Compile Include="Model\Settings\SignatureSettings.cs" />
|
||||
<Compile Include="Model\Social\Messaging\ChatStatus.cs" />
|
||||
<Compile Include="Model\Social\Messaging\PrivateMessage.cs" />
|
||||
<Compile Include="Model\UI\PageState.cs" />
|
||||
<Compile Include="ViewModels\Validation\Error.cs" />
|
||||
<Compile Include="ViewModels\Validation\ModelState.cs" />
|
||||
<Compile Include="ViewModels\PageState.cs" />
|
||||
<Compile Include="Pages\EstimatePages\EstimateSigningPage.xaml.cs">
|
||||
<DependentUpon>EstimateSigningPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
|
@ -91,7 +93,7 @@
|
|||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Strings.en.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ViewModels\EditingViewModel.cs" />
|
||||
<Compile Include="ViewModels\Validation\EditingViewModel.cs" />
|
||||
<Compile Include="Pages\DocSigning.xaml.cs">
|
||||
<DependentUpon>DocSigning.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
|
@ -99,6 +101,7 @@
|
|||
<Compile Include="ViewModels\Signing\SignaturePadConfigViewModel.cs" />
|
||||
<Compile Include="ViewModels\UserProfile\UserProfileViewModel.cs" />
|
||||
<Compile Include="ViewModels\UserProfile\DirectoryInfoViewModel.cs" />
|
||||
<Compile Include="ViewModels\Validation\ErrorSeverity.cs" />
|
||||
<Compile Include="Views\EnumPicker.cs" />
|
||||
<Compile Include="Converters\BooleanToObjectConverter.cs" />
|
||||
<Compile Include="Converters\EnumConverter.cs" />
|
||||
|
|
@ -250,6 +253,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Model\Billing\" />
|
||||
<Folder Include="Model\UI\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="ExifLib, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
|
|
@ -363,12 +367,6 @@
|
|||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Yavsc.Client\Yavsc.Client.csproj">
|
||||
<Project>{67f9d3a8-f71e-4428-913f-c37ae82cdb24}</Project>
|
||||
<Name>Yavsc.Client</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Pages\EstimatePages\EditEstimatePage.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
|
|
@ -496,6 +494,12 @@
|
|||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\YavscLib\YavscLib.csproj">
|
||||
<Project>{67f9d3a8-f71e-4428-913f-c37ae82cdb24}</Project>
|
||||
<Name>YavscLib</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<Import Project="..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@
|
|||
using Model;
|
||||
using Model.Blog;
|
||||
using Model.Workflow;
|
||||
using Model.UI;
|
||||
using Model.Social.Messaging;
|
||||
using Model.FileSystem;
|
||||
using ViewModels.EstimateAndBilling;
|
||||
using NonCrUD;
|
||||
using ViewModels;
|
||||
|
||||
public class DataManager
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,31 +65,25 @@ namespace BookAStar.Pages
|
|||
if (editEstimateViewModel == null)
|
||||
{
|
||||
// First search for an existing estimate
|
||||
var estimateToEdit = DataManager.Current.Estimates.FirstOrDefault(
|
||||
estimate=> estimate.CommandId == bookQueryViewModel.Id
|
||||
editEstimateViewModel = DataManager.Current.EstimationCache.FirstOrDefault(
|
||||
estimate=> estimate.Query.Id == bookQueryViewModel.Id
|
||||
);
|
||||
if (estimateToEdit == null)
|
||||
if (editEstimateViewModel == null)
|
||||
{
|
||||
DataManager.Current.Contacts.Merge(BookQuery.Client);
|
||||
DataManager.Current.Contacts.SaveEntity();
|
||||
estimateToEdit = new Estimate
|
||||
editEstimateViewModel = new EditEstimateViewModel( new Estimate
|
||||
{
|
||||
ClientId = BookQuery.Client.UserId,
|
||||
CommandId = BookQuery.Id,
|
||||
OwnerId = MainSettings.CurrentUser.Id,
|
||||
Id = 0
|
||||
};
|
||||
editEstimateViewModel = new EditEstimateViewModel(estimateToEdit);
|
||||
});
|
||||
DataManager.Current.EstimationCache.Add(editEstimateViewModel);
|
||||
}
|
||||
else
|
||||
editEstimateViewModel = new EditEstimateViewModel(estimateToEdit);
|
||||
|
||||
DataManager.Current.EstimationCache.Add(editEstimateViewModel);
|
||||
}
|
||||
App.NavigationService.NavigateTo<EditEstimatePage>(true,
|
||||
editEstimateViewModel);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private async void OnViewEstimate(object sender, EventArgs ev)
|
||||
|
|
|
|||
|
|
@ -44,12 +44,16 @@
|
|||
<StackLayout x:Name="mainStackLayout">
|
||||
<Label Text="Description de la ligne de facture"
|
||||
Style="{StaticResource InputLabelStyle}"></Label>
|
||||
<StackLayout Orientation="Horizontal" VerticalOptions="FillAndExpand">
|
||||
<Editor HorizontalOptions="FillAndExpand" Text="{Binding Description, Mode=TwoWay}">
|
||||
<Editor HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Text="{Binding Description, Mode=TwoWay}">
|
||||
<Editor.Behaviors>
|
||||
<behaviors:EditorMaxLengthValidator x:Name="descriptionLenValidator" MaxLength="512" MinLength="3" />
|
||||
<behaviors:EditorMaxLengthValidator x:Name="descriptionLenValidator" MaxLength="12" MinLength="3" />
|
||||
</Editor.Behaviors>
|
||||
</Editor>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<Image x:Name="descriptionSuccessErrorImage"
|
||||
Style="{Binding Source={x:Reference descriptionLenValidator}, Path=IsValid, Converter={StaticResource boolToStyleImage}}" />
|
||||
<Label Text="{Binding Source={x:Reference descriptionLenValidator}, Path=Error}"
|
||||
Style="{StaticResource ErrorLabelStyle}"></Label>
|
||||
</StackLayout>
|
||||
|
||||
<Label Text="Durée de la prestation"
|
||||
|
|
@ -74,18 +78,21 @@
|
|||
</StackLayout>
|
||||
|
||||
<Label Text="Quantité facturée" Style="{StaticResource InputLabelStyle}"></Label>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
|
||||
<Entry Text="{Binding Count, Mode=TwoWay}" Placeholder="Quantité" Keyboard="Numeric"
|
||||
Style="{StaticResource BigEntry}">
|
||||
<Entry.Behaviors>
|
||||
<behaviors:IntegerEntryBehavior x:Name="countValidator" Min="0" Max="10" />
|
||||
</Entry.Behaviors>
|
||||
</Entry>
|
||||
<Image x:Name="countSuccessErrorImage"
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<Image x:Name="countSuccessErrorImage"
|
||||
Style="{Binding Source={x:Reference countValidator},
|
||||
Path=IsValid,
|
||||
Converter={StaticResource boolToStyleImage}}" />
|
||||
</StackLayout>
|
||||
<Label Text="{Binding Source={x:Reference countValidator}, Path=Error}"
|
||||
Style="{StaticResource ErrorLabelStyle}"></Label>
|
||||
</StackLayout>
|
||||
|
||||
<Label Text="Prix unitaire" Style="{StaticResource InputLabelStyle}"></Label>
|
||||
<StackLayout Orientation="Horizontal">
|
||||
|
|
@ -106,7 +113,7 @@
|
|||
Command="{Binding ValidateCommand}"
|
||||
Clicked="OnValidateClicked"></Button>
|
||||
<Button Text="Supprimer"
|
||||
Command="{Binding DeleteCommand}"
|
||||
Command="{Binding RemoveCommand}"
|
||||
Clicked="OnDeleteClicked"></Button>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
|
|
|
|||
|
|
@ -17,14 +17,17 @@ namespace BookAStar.Pages
|
|||
picker.Items.Add(du);
|
||||
BindingContext = model;
|
||||
}
|
||||
|
||||
public void OnDeleteClicked(object sender, EventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
this.Navigation.PopAsync();
|
||||
}
|
||||
|
||||
public void OnValidateClicked (object sender, EventArgs e)
|
||||
{
|
||||
this.Navigation.PopAsync();
|
||||
}
|
||||
|
||||
protected override bool OnBackButtonPressed()
|
||||
{
|
||||
var bvm = (BillingLineViewModel)BindingContext;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@
|
|||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="BookAStar.Pages.EditEstimatePage"
|
||||
xmlns:converters="clr-namespace:BookAStar.Converters;assembly=BookAStar"
|
||||
xmlns:views="clr-namespace:BookAStar.Views;assembly=BookAStar"
|
||||
xmlns:local="clr-namespace:BookAStar;assembly=BookAStar"
|
||||
xmlns:behaviors="clr-namespace:BookAStar.Behaviors;assembly=BookAStar"
|
||||
xmlns:extensions="clr-namespace:BookAStar.Extensions;assembly=BookAStar"
|
||||
Style="{StaticResource PageStyle}">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
|
|
@ -14,14 +16,32 @@
|
|||
<Style TargetType="Button">
|
||||
<Setter Property="Style" Value="{StaticResource ButtonStyle}" />
|
||||
</Style>
|
||||
<converters:BooleanToObjectConverter x:Key="boolToStyleImage" x:TypeArguments="Style">
|
||||
|
||||
<converters:BooleanToObjectConverter.FalseObject>
|
||||
<Style TargetType="Image">
|
||||
<Setter Property="HeightRequest" Value="20" />
|
||||
<Setter Property="Source"
|
||||
Value="{extensions:ImageResource BookAStar.Images.Validation.error.png}" />
|
||||
</Style>
|
||||
</converters:BooleanToObjectConverter.FalseObject>
|
||||
|
||||
<converters:BooleanToObjectConverter.TrueObject>
|
||||
<Style TargetType="Image">
|
||||
<Setter Property="HeightRequest" Value="20" />
|
||||
<Setter Property="Source"
|
||||
Value="{extensions:ImageResource BookAStar.Images.Validation.success.png}" />
|
||||
</Style>
|
||||
</converters:BooleanToObjectConverter.TrueObject>
|
||||
|
||||
</converters:BooleanToObjectConverter>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
<ContentPage.Content>
|
||||
<ScrollView>
|
||||
<StackLayout Padding="10,10,10,10" x:Name="mainLayout">
|
||||
<Grid MinimumHeightRequest="12">
|
||||
<Grid HeightRequest="120">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="2*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
|
|
@ -35,9 +55,7 @@
|
|||
<Entry Placeholder="Saisissez un titre pour ce devis" Text="{Binding Title, Mode=TwoWay}" />
|
||||
<views:MarkdownView x:Name="mdview"
|
||||
Editable="True"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
Markdown="{Binding Description, Mode=TwoWay}"
|
||||
VerticalOptions="Start" >
|
||||
Markdown="{Binding Description, Mode=TwoWay}">
|
||||
<views:MarkdownView.Behaviors>
|
||||
<behaviors:MarkdownViewLengthValidator x:Name="descriptionLenValidator" MaxLength="512" MinLength="3" />
|
||||
|
||||
|
|
@ -45,13 +63,12 @@
|
|||
</views:MarkdownView>
|
||||
<StackLayout x:Name="biAnVaLayout">
|
||||
<ListView x:Name="BillListView" ItemsSource="{Binding Bill}"
|
||||
MinimumHeightRequest="40" HasUnevenRows="true" VerticalOptions="FillAndExpand"
|
||||
HeightRequest="40" ItemTapped="OnEditLine">
|
||||
HasUnevenRows="true" ItemTapped="OnEditLine">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate >
|
||||
<ViewCell>
|
||||
<ViewCell.View>
|
||||
<Grid MinimumHeightRequest="12">
|
||||
<ViewCell.View Padding="5,5,5,5" >
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
|
@ -60,6 +77,7 @@
|
|||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width="90" />
|
||||
<ColumnDefinition Width="16" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Text="{Binding Description}"
|
||||
Grid.Row="0" Grid.Column="0" ></Label>
|
||||
|
|
@ -70,6 +88,9 @@
|
|||
<Label Text="{Binding UnitaryCost}"
|
||||
Grid.Row="0" Grid.Column="3"
|
||||
FontFamily="Monospace"></Label>
|
||||
<Image Grid.Row="0" Grid.Column="4" Style="{Binding
|
||||
Path=ViewModelState.IsValid,
|
||||
Converter={StaticResource boolToStyleImage}}" ></Image>
|
||||
</Grid>
|
||||
</ViewCell.View>
|
||||
</ViewCell>
|
||||
|
|
@ -83,6 +104,5 @@
|
|||
</StackLayout>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
|
|
@ -57,11 +57,20 @@ namespace BookAStar.Pages
|
|||
protected void OnEditLine(object sender, ItemTappedEventArgs e)
|
||||
{
|
||||
var line = (BillingLineViewModel)e.Item;
|
||||
// update the validation command, that
|
||||
// was creating a new line in the bill at creation time,
|
||||
// now one only wants to update the line
|
||||
line.ValidateCommand = new Command(() =>
|
||||
{
|
||||
DataManager.Current.EstimationCache.SaveEntity();
|
||||
});
|
||||
|
||||
// and setup a removal command, that was not expected at creation time
|
||||
var evm = (EditEstimateViewModel)BindingContext;
|
||||
line.RemoveCommand = new Command(() =>
|
||||
{
|
||||
evm.Bill.Remove(line);
|
||||
DataManager.Current.EstimationCache.SaveEntity();
|
||||
});
|
||||
App.NavigationService.NavigateTo<EditBillingLinePage>(
|
||||
true, line );
|
||||
}
|
||||
|
|
@ -78,7 +87,9 @@ namespace BookAStar.Pages
|
|||
}
|
||||
await thisPage.Navigation.PopAsync();
|
||||
});
|
||||
var response = await App.DisplayActionSheet(Strings.SignOrNot, Strings.DonotsignEstimate, Strings.CancelValidation, new string[] { Strings.Sign });
|
||||
var response = await App.DisplayActionSheet(
|
||||
Strings.SignOrNot, Strings.DonotsignEstimate,
|
||||
Strings.CancelValidation, new string[] { Strings.Sign });
|
||||
if (response == Strings.Sign)
|
||||
{
|
||||
App.NavigationService.NavigateTo<EstimateSigningPage>(true,
|
||||
|
|
|
|||
45
BookAStar/BookAStar/Strings.Designer.cs
generated
45
BookAStar/BookAStar/Strings.Designer.cs
generated
|
|
@ -142,6 +142,42 @@ namespace BookAStar {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Valeur invalide.
|
||||
/// </summary>
|
||||
public static string InvalidValue {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidValue", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Veuillez saisir une valeur entre {0} et {1}..
|
||||
/// </summary>
|
||||
public static string MinMaxIntError {
|
||||
get {
|
||||
return ResourceManager.GetString("MinMaxIntError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Veuillez saisir une description (entre {0} et {1} caractères)..
|
||||
/// </summary>
|
||||
public static string MinMaxStringValidationError {
|
||||
get {
|
||||
return ResourceManager.GetString("MinMaxStringValidationError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Pas de description.
|
||||
/// </summary>
|
||||
public static string NoDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("NoDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Un artiste.
|
||||
/// </summary>
|
||||
|
|
@ -231,5 +267,14 @@ namespace BookAStar {
|
|||
return ResourceManager.GetString("ViewEstimate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recherche une chaîne localisée semblable à Votre texte a été taillé car il était trop long..
|
||||
/// </summary>
|
||||
public static string YourTextWasTooLong {
|
||||
get {
|
||||
return ResourceManager.GetString("YourTextWasTooLong", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,4 +176,19 @@
|
|||
<data name="UpdateFailed" xml:space="preserve">
|
||||
<value>La mise à jour a échoué.</value>
|
||||
</data>
|
||||
<data name="MinMaxStringValidationError" xml:space="preserve">
|
||||
<value>Veuillez saisir une description (entre {0} et {1} caractères).</value>
|
||||
</data>
|
||||
<data name="YourTextWasTooLong" xml:space="preserve">
|
||||
<value>Votre texte a été taillé car il était trop long.</value>
|
||||
</data>
|
||||
<data name="NoDescription" xml:space="preserve">
|
||||
<value>Pas de description</value>
|
||||
</data>
|
||||
<data name="InvalidValue" xml:space="preserve">
|
||||
<value>Valeur invalide</value>
|
||||
</data>
|
||||
<data name="MinMaxIntError" xml:space="preserve">
|
||||
<value>Veuillez saisir une valeur entre {0} et {1}.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
using BookAStar.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using XLabs.Forms.Mvvm;
|
||||
|
||||
namespace BookAStar.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to make the DataManager know how
|
||||
/// to sync local and remote data
|
||||
/// </summary>
|
||||
public class EditingViewModel: ViewModel
|
||||
{
|
||||
bool existsRemotely;
|
||||
public bool ExistsRemotely
|
||||
{
|
||||
get
|
||||
{
|
||||
return existsRemotely;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetProperty<bool>(ref existsRemotely, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool isValid;
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
return isValid;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetProperty<bool>(ref isValid, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool isDirty;
|
||||
public bool IsDirty
|
||||
{
|
||||
get
|
||||
{
|
||||
return isDirty;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetProperty<bool>(ref isDirty, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,54 @@
|
|||
using BookAStar.Attributes;
|
||||
using BookAStar.Interfaces;
|
||||
using BookAStar.Model.Workflow;
|
||||
using BookAStar.ViewModels.Validation;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Input;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace BookAStar.ViewModels.EstimateAndBilling
|
||||
{
|
||||
public class BillingLineViewModel : EditingViewModel, IBillingLine
|
||||
public class BillingLineViewModel : EditingViewModel<BillingLine>, IBillingLine
|
||||
{
|
||||
BillingLine data;
|
||||
public ICommand RemoveCommand { get; set; }
|
||||
public ICommand ValidateCommand { set; get; }
|
||||
|
||||
public BillingLineViewModel(BillingLine data)
|
||||
public BillingLineViewModel(BillingLine data): base(data)
|
||||
{
|
||||
this.Data = data;
|
||||
CheckCommand = new Action<BillingLine, ModelState>(
|
||||
(l,s) => {
|
||||
if (string.IsNullOrWhiteSpace(l.Description))
|
||||
{
|
||||
s.AddError("Description",Strings.NoDescription);
|
||||
}
|
||||
if (l.UnitaryCost < 0) { s.AddError("UnitaryCost", Strings.InvalidValue); }
|
||||
if (l.Count < 0) { s.AddError("Count", Strings.InvalidValue); }
|
||||
});
|
||||
SyncData();
|
||||
}
|
||||
|
||||
private void SyncData()
|
||||
{
|
||||
if (Data != null)
|
||||
{
|
||||
// set durationValue, durationUnit
|
||||
Duration = Data.Duration;
|
||||
// other redondant representation
|
||||
count = Data.Count;
|
||||
description = Data.Description;
|
||||
unitaryCostText = Data.UnitaryCost.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
CheckCommand(Data, ViewModelState);
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (e.PropertyName=="Data")
|
||||
{
|
||||
SyncData();
|
||||
}
|
||||
}
|
||||
|
||||
private int count;
|
||||
|
|
@ -27,7 +62,7 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
set
|
||||
{
|
||||
SetProperty<int>(ref count, value);
|
||||
data.Count = count;
|
||||
Data.Count = count;
|
||||
}
|
||||
}
|
||||
private string description;
|
||||
|
|
@ -41,10 +76,10 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
set
|
||||
{
|
||||
SetProperty<string>(ref description, value);
|
||||
data.Description = description;
|
||||
IsValid = !string.IsNullOrWhiteSpace(description);
|
||||
Data.Description = description;
|
||||
}
|
||||
}
|
||||
|
||||
decimal unitaryCost;
|
||||
public decimal UnitaryCost
|
||||
{
|
||||
|
|
@ -56,7 +91,7 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
set
|
||||
{
|
||||
SetProperty<decimal>(ref unitaryCost, value);
|
||||
data.UnitaryCost = unitaryCost;
|
||||
Data.UnitaryCost = unitaryCost;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +106,7 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
set
|
||||
{
|
||||
SetProperty<int>(ref durationValue, value, "DurationValue");
|
||||
data.Duration = this.Duration;
|
||||
Data.Duration = this.Duration;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +129,7 @@ pour décrire la quantité de travail associée à ce type de service")]
|
|||
set
|
||||
{
|
||||
SetProperty<DurationUnits>(ref durationUnit, value, "DurationUnit");
|
||||
data.Duration = this.Duration;
|
||||
Data.Duration = this.Duration;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +155,6 @@ pour décrire la quantité de travail associée à ce type de service")]
|
|||
}
|
||||
}
|
||||
|
||||
public ICommand ValidateCommand { set; get; }
|
||||
|
||||
public TimeSpan Duration
|
||||
{
|
||||
|
|
@ -161,26 +195,5 @@ pour décrire la quantité de travail associée à ce type de service")]
|
|||
}
|
||||
}
|
||||
|
||||
public BillingLine Data
|
||||
{
|
||||
get
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
SetProperty<BillingLine>(ref data, value);
|
||||
if (data != null)
|
||||
{
|
||||
// sets durationValue & durationUnit
|
||||
count = data.Count;
|
||||
description = data.Description;
|
||||
|
||||
Duration = data.Duration;
|
||||
unitaryCostText = data.UnitaryCost.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,18 +6,13 @@ using Xamarin.Forms;
|
|||
using BookAStar.Data;
|
||||
using Newtonsoft.Json;
|
||||
using System.Linq;
|
||||
using BookAStar.ViewModels.Validation;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace BookAStar.ViewModels.EstimateAndBilling
|
||||
{
|
||||
public class EditEstimateViewModel : EditingViewModel
|
||||
public class EditEstimateViewModel : EditingViewModel<Estimate>
|
||||
{
|
||||
/// <summary>
|
||||
/// For deserialization
|
||||
/// </summary>
|
||||
public EditEstimateViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a new view model on estimate,
|
||||
|
|
@ -25,11 +20,37 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="localState"></param>
|
||||
public EditEstimateViewModel(Estimate data)
|
||||
public EditEstimateViewModel(Estimate data) : base(data)
|
||||
{
|
||||
Data = data;
|
||||
SyncData();
|
||||
}
|
||||
|
||||
private void SyncData()
|
||||
{
|
||||
if (Data.AttachedFiles == null) Data.AttachedFiles = new List<string>();
|
||||
if (Data.AttachedGraphics == null) Data.AttachedGraphics = new List<string>();
|
||||
if (Data.Bill == null) Data.Bill = new List<BillingLine>();
|
||||
AttachedFiles = new ObservableCollection<string>(Data.AttachedFiles);
|
||||
AttachedGraphicList = new ObservableCollection<string>(Data.AttachedGraphics);
|
||||
Bill = new ObservableCollection<BillingLineViewModel>(Data.Bill.Select(
|
||||
l => new BillingLineViewModel(l)
|
||||
));
|
||||
Bill.CollectionChanged += Bill_CollectionChanged;
|
||||
Title = Data.Title;
|
||||
Description = Data.Description;
|
||||
NotifyPropertyChanged("FormattedTotal");
|
||||
NotifyPropertyChanged("Query");
|
||||
NotifyPropertyChanged("CLient");
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (e.PropertyName == "Data")
|
||||
{
|
||||
SyncData();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
|
@ -42,25 +63,6 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
NotifyPropertyChanged("Bill");
|
||||
}
|
||||
|
||||
private Estimate data;
|
||||
public Estimate Data { get { return data; } set {
|
||||
SetProperty<Estimate>(ref data, value);
|
||||
if (data.AttachedFiles == null) data.AttachedFiles = new List<string>();
|
||||
if (data.AttachedGraphics == null) data.AttachedGraphics = new List<string>();
|
||||
if (data.Bill == null) data.Bill = new List<BillingLine>();
|
||||
AttachedFiles = new ObservableCollection<string>(data.AttachedFiles);
|
||||
AttachedGraphicList = new ObservableCollection<string>(data.AttachedGraphics);
|
||||
Bill = new ObservableCollection<BillingLineViewModel>(data.Bill.Select(
|
||||
l => new BillingLineViewModel(l)
|
||||
));
|
||||
Bill.CollectionChanged += Bill_CollectionChanged;
|
||||
Title = Data.Title;
|
||||
Description = Data.Description;
|
||||
NotifyPropertyChanged("FormattedTotal");
|
||||
NotifyPropertyChanged("Query");
|
||||
NotifyPropertyChanged("CLient");
|
||||
} }
|
||||
|
||||
[JsonIgnore]
|
||||
public ObservableCollection<string> AttachedFiles
|
||||
{
|
||||
|
|
@ -124,7 +126,7 @@ namespace BookAStar.ViewModels.EstimateAndBilling
|
|||
{
|
||||
get
|
||||
{
|
||||
OnPlatform<Font> lfs = (OnPlatform<Font>)App.Current.Resources["LargeFontSize"];
|
||||
OnPlatform<Font> lfs = (OnPlatform<Font>)App.Current.Resources["MediumFontSize"];
|
||||
OnPlatform<Color> etc = (OnPlatform<Color>)App.Current.Resources["EmphasisTextColor"];
|
||||
|
||||
return new FormattedString
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using XLabs.Forms.Mvvm;
|
||||
|
||||
namespace BookAStar.Model.UI
|
||||
namespace BookAStar.ViewModels
|
||||
{
|
||||
internal class PageState
|
||||
{
|
||||
|
|
@ -6,9 +6,8 @@ namespace BookAStar.ViewModels.Signing
|
|||
{
|
||||
public class EstimateSigningViewModel: EditEstimateViewModel
|
||||
{
|
||||
public EstimateSigningViewModel(Estimate document)
|
||||
public EstimateSigningViewModel(Estimate document): base(document)
|
||||
{
|
||||
Data = document;
|
||||
}
|
||||
public Command<bool> ValidationCommand { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
using BookAStar.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using XLabs.Forms.Mvvm;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace BookAStar.ViewModels.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to make the DataManager know how
|
||||
/// to sync local and remote data
|
||||
/// </summary>
|
||||
public class EditingViewModel<DataType>: ViewModel
|
||||
{
|
||||
|
||||
public Action<DataType, ModelState> CheckCommand { set; get; }
|
||||
|
||||
public DataType Data { get; set; }
|
||||
|
||||
private ModelState viewModelState = new ModelState();
|
||||
|
||||
public ModelState ViewModelState
|
||||
{
|
||||
get
|
||||
{
|
||||
return viewModelState;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetProperty<ModelState>(ref viewModelState, value);
|
||||
}
|
||||
}
|
||||
|
||||
public EditingViewModel(DataType data)
|
||||
{
|
||||
this.Data = data;
|
||||
ViewModelState = new ModelState();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (CheckCommand != null)
|
||||
{
|
||||
ViewModelState.Clear();
|
||||
CheckCommand(Data, ViewModelState);
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE : I had a dream.
|
||||
|
||||
bool existsRemotely;
|
||||
public bool ExistsRemotely
|
||||
{
|
||||
get
|
||||
{
|
||||
return existsRemotely;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetProperty<bool>(ref existsRemotely, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool isDirty;
|
||||
public bool IsDirty
|
||||
{
|
||||
get
|
||||
{
|
||||
return isDirty;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetProperty<bool>(ref isDirty, value);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
13
BookAStar/BookAStar/ViewModels/Validation/Error.cs
Normal file
13
BookAStar/BookAStar/ViewModels/Validation/Error.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
namespace BookAStar.ViewModels.Validation
|
||||
{
|
||||
public class InputError
|
||||
{
|
||||
public InputError(string errorMessage, ErrorSeverity severity)
|
||||
{
|
||||
Text = errorMessage;
|
||||
Severity = severity;
|
||||
}
|
||||
public string Text { get; set; }
|
||||
public ErrorSeverity Severity { get; set; }
|
||||
}
|
||||
}
|
||||
14
BookAStar/BookAStar/ViewModels/Validation/ErrorSeverity.cs
Normal file
14
BookAStar/BookAStar/ViewModels/Validation/ErrorSeverity.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BookAStar.ViewModels.Validation
|
||||
{
|
||||
public enum ErrorSeverity
|
||||
{
|
||||
Crippling,
|
||||
Bearable
|
||||
}
|
||||
}
|
||||
66
BookAStar/BookAStar/ViewModels/Validation/ModelState.cs
Normal file
66
BookAStar/BookAStar/ViewModels/Validation/ModelState.cs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace BookAStar.ViewModels.Validation
|
||||
{
|
||||
public class ModelState : BindableObject
|
||||
{
|
||||
public static readonly BindableProperty IsValidProperty =
|
||||
BindableProperty.Create("IsValid", typeof(bool), typeof(ModelState), false);
|
||||
|
||||
public static readonly BindableProperty ErrorsProperty =
|
||||
BindableProperty.Create("Errors", typeof(Dictionary<string,List<InputError>>), typeof(ModelState), null);
|
||||
|
||||
public ModelState()
|
||||
{
|
||||
Errors = new Dictionary<string, List<InputError>>();
|
||||
}
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool) GetValue(IsValidProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, List<InputError>> Errors
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Dictionary<string, List<InputError>>)GetValue(ErrorsProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(ErrorsProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void AddError(string propertyName, string errorMessage, ErrorSeverity severity = ErrorSeverity.Crippling)
|
||||
{
|
||||
InputError e = new InputError(errorMessage, severity) ;
|
||||
if (Errors.ContainsKey(propertyName))
|
||||
{
|
||||
var errList = Errors[propertyName];
|
||||
errList.Add(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
Errors.Add(propertyName, new List<InputError>(new InputError [] { e }));
|
||||
}
|
||||
if (e.Severity < ErrorSeverity.Bearable)
|
||||
SetValue(IsValidProperty, false);
|
||||
}
|
||||
|
||||
public virtual void Clear ()
|
||||
{
|
||||
Errors.Clear();
|
||||
SetValue(IsValidProperty, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue