Skip to content

Commit

Permalink
Manual Validation Form dan FilePicker di Form Barang
Browse files Browse the repository at this point in the history
  • Loading branch information
bachtiarpanjaitan committed Aug 23, 2024
1 parent e696ff8 commit 3149fc2
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 97 deletions.
2 changes: 2 additions & 0 deletions App.xaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:dataForm="clr-namespace:IhandCashier.Bepe.Components.DataForm"
x:Class="IhandCashier.App">
<Application.Resources>
<ResourceDictionary>
Expand All @@ -9,6 +10,7 @@
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
<Color x:Key="IcBorderColor">#BDBDBD</Color>
<dataForm:ErrorToTextConverter x:Key="ErrorToTextConverter"/>
</ResourceDictionary>
</Application.Resources>
</Application>
Expand Down
18 changes: 18 additions & 0 deletions Bepe/Components/DataForm/ErrorToTextConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Globalization;

namespace IhandCashier.Bepe.Components.DataForm;

public class ErrorToTextConverter : IValueConverter
{

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var errors = value as IEnumerable<string>;
return errors != null && errors.Any() ? string.Join(Environment.NewLine, errors) : string.Empty;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
16 changes: 16 additions & 0 deletions Bepe/Statics/FormValidation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace IhandCashier.Bepe.Statics;

public static class FormValidation
{
public static StackLayout ShowErrors(StackLayout stackLayout, Dictionary<string, List<string>> errors)
{
stackLayout.Clear();
foreach (var er in errors)
{
foreach (var x in er.Value) stackLayout.Children.Add(new Label(){Text = x ?? string.Empty, TextColor = Colors.Red});

}

return stackLayout;
}
}
219 changes: 141 additions & 78 deletions Bepe/ViewModels/ProductViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,110 +1,173 @@
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Runtime.CompilerServices;
using IhandCashier.Bepe.Entities;

namespace IhandCashier.Bepe.ViewModels;

public class ProductViewModel : INotifyPropertyChanged
namespace IhandCashier.Bepe.ViewModels
{
private int _id;
private string _kode;
private string _nama;
private string _gambar;

[Bindable(false)]
public int Id
public class ProductViewModel : INotifyPropertyChanged, INotifyDataErrorInfo
{
get => _id;
set
private int _id;
private string _kode;
private string _nama;
private string _gambar;
public readonly Dictionary<string, List<string>> Errors = new();

public bool HasErrors
{
if (_id != value)
get => Errors.Any();
private set { }
}

[Bindable(false)]
public int Id
{
get => _id;
set
{
_id = value;
OnPropertyChanged();
if (_id != value)
{
_id = value;
OnPropertyChanged();
}
}
}
}

[Required(AllowEmptyStrings = false, ErrorMessage = "Kode tidak boleh kosong")]
[MinLength(4, ErrorMessage = "Kode tidak boleh lebih kecil dari 4 karakter")]
[MaxLength(20, ErrorMessage = "Maksimal panjang kode adalah 20 karakter")]
[Display(Prompt="Masukkan Kode Barang")]
public string Kode
{
get => _kode;
set
[Required(AllowEmptyStrings = false, ErrorMessage = "Kode tidak boleh kosong")]
[MinLength(4, ErrorMessage = "Kode tidak boleh lebih kecil dari 4 karakter")]
[MaxLength(20, ErrorMessage = "Maksimal panjang kode adalah 20 karakter")]
[Display(Prompt = "Masukkan Kode Barang")]
public string Kode
{
if (_kode != value)
get => _kode;
set
{
_kode = value;
OnPropertyChanged();
if (_kode != value)
{
_kode = value;
OnPropertyChanged();
ValidateProperty(nameof(Kode), value);
}
}
}
}

[Required(AllowEmptyStrings = false, ErrorMessage = "Nama tidak boleh kosong")]
[MinLength(4, ErrorMessage = "Nama barang tidak boleh lebih kecil dari 4 karakter")]
[MaxLength(20, ErrorMessage = "Maksimal panjang nama barang adalah 20 karakter")]
[Display(Prompt="Masukkan Nama Barang")]
public string Nama
{
get => _nama;
set

[Required(AllowEmptyStrings = false, ErrorMessage = "Nama tidak boleh kosong")]
[MinLength(4, ErrorMessage = "Nama barang tidak boleh lebih kecil dari 4 karakter")]
[MaxLength(20, ErrorMessage = "Maksimal panjang nama barang adalah 20 karakter")]
[Display(Prompt = "Masukkan Nama Barang")]
public string Nama
{
if (_nama != value)
get => _nama;
set
{
_nama = value;
OnPropertyChanged();
if (_nama != value)
{
_nama = value;
OnPropertyChanged();
ValidateProperty(nameof(Nama), value);
}
}
}
}

[DataType(DataType.Upload)]
public string Gambar
{
get => _gambar;
set

[FileExtensions(Extensions = "jpg,jpeg,png", ErrorMessage = "Hanya format gambar yang diperbolehkan.")]
public string Gambar
{
if (_gambar != value)
get => _gambar;
set
{
_gambar = value;
OnPropertyChanged();
if (_gambar != value)
{
_gambar = value;
OnPropertyChanged();
ValidateProperty(nameof(Gambar), value);
}
}
}
}

public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
if (propertyName != null)
{
ValidateProperty(propertyName, GetType().GetProperty(propertyName)?.GetValue(this));
}
}

protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ProductViewModel(Product product)
{
_id = product.id;
_kode = product.kode;
_nama = product.nama;
_gambar = product.gambar;
}

// Constructor that accepts a Product object
public ProductViewModel(Product product)
{
_id = product.id;
_kode = product.kode;
_nama = product.nama;
_gambar = product.gambar;
}
public ProductViewModel()
{
ValidateAllProperties();
}

// Default constructor for cases where you want to create a new Product from scratch
public ProductViewModel() : this(new Product())
{
}
public Product ToProduct()
{
return new Product
{
id = _id,
kode = _kode,
nama = _nama,
gambar = _gambar
};
}

// Method to get a Product entity from the ViewModel
public Product ToProduct()
{
return new Product
public IEnumerable GetErrors(string propertyName)
{
return Errors.TryGetValue(propertyName, out var errors) ? errors : null;
}

private void ValidateProperty(string propertyName, object value)
{
var validationContext = new ValidationContext(this) { MemberName = propertyName };
var results = new List<ValidationResult>();

// Validasi properti menggunakan Validator
bool isValid = Validator.TryValidateProperty(value, validationContext, results);

// Menyimpan hasil validasi ke dictionary _errors
if (isValid)
{
Errors.Remove(propertyName);
}
else
{
Errors[propertyName] = results.Select(x => x.ErrorMessage).ToList();
}

// Memperbarui status HasErrors
HasErrors = Errors.Any();

// Notifikasi bahwa error telah berubah
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
}



IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName)
{
id = _id,
kode = _kode,
nama = _nama,
gambar = _gambar
};
return GetErrors(propertyName);
}

protected virtual void OnErrorsChanged(string propertyName)
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
}

private void ValidateAllProperties()
{
ValidateProperty(nameof(Kode), _kode);
ValidateProperty(nameof(Nama), _nama);
ValidateProperty(nameof(Gambar), _gambar);
}
}
}

1 change: 0 additions & 1 deletion IhandCashier.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@
<PackageReference Include="Syncfusion.Maui.DataGrid" Version="26.2.9" />
</ItemGroup>
<ItemGroup>
<Folder Include="Bepe\Components\DataForm\" />
<Folder Include="Bepe\Helpers\Factories\" />
<Folder Include="Bepe\Migrations\" />
<Folder Include="Bepe\Providers\" />
Expand Down
20 changes: 18 additions & 2 deletions Pages/Forms/FormBarang.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
CanBeDismissedByTappingOutsideOfPopup="False"
Size="600,700"
Size="600,500"
x:Class="IhandCashier.Pages.Forms.FormBarang">
<Grid>
<Grid.RowDefinitions>
Expand All @@ -16,7 +16,23 @@
<Label Text="Form Barang" FontSize="20" Padding="0,20,0,5" FontAttributes="Bold" VerticalOptions="Center" HorizontalOptions="Center" />
</Grid>
<Grid Grid.Row="1">
<StackLayout x:Name="Form" Margin="0,10"/>
<VerticalStackLayout Padding="20" Margin="20">
<StackLayout Padding="0,5" x:Name="ErrorContainer"></StackLayout>
<StackLayout Padding="0,10">
<Label Text="Kode Produk" />
<Entry Text="{Binding Kode,Mode=TwoWay}" Placeholder="Masukkan kode produk" />
</StackLayout>

<StackLayout Padding="0,10">
<Label Text="Nama Produk" />
<Entry Text="{Binding Nama, Mode=TwoWay}" Placeholder="Masukkan nama produk" />
</StackLayout>

<StackLayout Padding="0,10">
<Button Text="Pilih Gambar Produk" Clicked="OnPickImageClicked" />
<Label Text="{Binding Gambar,Mode=TwoWay}" />
</StackLayout>
</VerticalStackLayout>
</Grid>
<Grid Grid.Row="2">
<HorizontalStackLayout HorizontalOptions="End" VerticalOptions="Center">
Expand Down
Loading

0 comments on commit 3149fc2

Please sign in to comment.