ARSoft.WinForms.CustomControls
3.0.3
dotnet add package ARSoft.WinForms.CustomControls --version 3.0.3
NuGet\Install-Package ARSoft.WinForms.CustomControls -Version 3.0.3
<PackageReference Include="ARSoft.WinForms.CustomControls" Version="3.0.3" />
<PackageVersion Include="ARSoft.WinForms.CustomControls" Version="3.0.3" />
<PackageReference Include="ARSoft.WinForms.CustomControls" />
paket add ARSoft.WinForms.CustomControls --version 3.0.3
#r "nuget: ARSoft.WinForms.CustomControls, 3.0.3"
#:package ARSoft.WinForms.CustomControls@3.0.3
#addin nuget:?package=ARSoft.WinForms.CustomControls&version=3.0.3
#tool nuget:?package=ARSoft.WinForms.CustomControls&version=3.0.3
ARSoft.WinForms.CustomControls
A comprehensive Windows Forms control library that extends standard WinForms controls with enhanced validation, formatting, and user experience features. Perfect for building robust desktop applications with professional input handling and document validation capabilities.
🌟 Features
- Enhanced Text Controls - Smart text boxes with built-in validation and formatting
- Document Validation - Support for Brazilian documents (CPF, CNPJ, CEP)
- Specialized Input Controls - Currency, numeric, email, and integer input handling
- Improved Labels - Temporary message display with auto-restore functionality
- Async Loading Overlay - Centered loading indicator for async workflows
- Settings Management - Easy import/export of application settings
- Validation Framework - Consistent validation across all controls
- Culture Support - Localization-ready with culture-aware formatting
- Smart Placeholder Handling - Intelligent placeholder text that doesn't interfere with validation
📦 Installation
# Via NuGet Package Manager
Install-Package ARSoft.WinForms.CustomControls
# Via .NET CLI
dotnet add package ARSoft.WinForms.CustomControls
🆕 What's New in v3.0.3
Major Improvements
Async Loading Overlay
- Added
ARSLoadingOverlaywith centered spinner and message rendering - Restored
OnLeaveAsync,LoadingMessage,ShowLoadingOnAsync, andAsyncOperationCompletedcompatibility - Added
LoadingOverlayTargetso consumers can choose the exact container used by the loading overlay - Restored
AsyncLoadingOverlayandAsyncLoadingExtensionscompatibility APIs
CEP Async Lookup
- Added
CEPTextBox.OnCepLookupAsync - Added
CEPTextBox.AutoLookupAddress - Added
CEPTextBox.AddressFound - Added
CEPTextBox.LookupAddressAsync()
Reliability Fixes
- Numeric controls now honor
MinValueandMaxValue - Double parsing no longer changes the current thread culture
- Invalid input restores caret position without exceeding text length
SetPlaceholderno longer duplicates focus event handlers when called more than once
🎯 Smart Placeholder Validation
- Placeholder text is now properly ignored during validation
IsEmptyproperty correctly returnstruewhen placeholder is displayedTypedValueproperties return appropriate empty values when showing placeholders- Required field validation no longer treats placeholder as valid input
🔍 Enhanced Type Safety
- All numeric controls (
DoubleTextBox,IntegerTextBox,ARSCurrencyTextBox) now check for placeholder before parsing - Document controls (
CPFTextBox,CNPJTextBox,CEPTextBox) returnnullwhen placeholder is shown - Email validation skips format checking when placeholder is displayed
🛡️ Improved Validation Logic
DocumentTextBoxbase class now handles placeholder state correctly- Format validation only runs on actual user input
- Required field checks properly distinguish between empty input and placeholder text
Breaking Changes
None - This is a backward-compatible patch release.
🚀 Quick Start
Basic Text Input with Validation
using ARSoft.WinForms.CustomControls;
// Create a required text box with validation
var nameTextBox = new ARSTextBox
{
IsRequired = true,
RequiredFieldLabel = nameLabel // Label turns red if validation fails
};
// Add placeholder text (properly handled in validation)
nameTextBox.SetPlaceholder("Enter your full name");
// Check validation - placeholder is considered empty
if (nameTextBox.IsValid)
{
Console.WriteLine($"Valid input: {nameTextBox.Text}");
}
// IsEmpty returns true when showing placeholder
if (nameTextBox.IsEmpty)
{
Console.WriteLine("Field is empty (or showing placeholder)");
}
Document Validation Controls
CPF Input
var cpfTextBox = new CPFTextBox
{
IsRequired = true,
ApplyMaskOnFocusLeave = true // Automatically formats as XXX.XXX.XXX-XX
};
// Add placeholder for better UX
cpfTextBox.SetPlaceholder("000.000.000-00");
// Get clean CPF value (numbers only)
// Returns null if invalid OR if showing placeholder
string cleanCpf = cpfTextBox.TypedValue;
CNPJ Input
var cnpjTextBox = new CNPJTextBox
{
IsRequired = true,
ApplyMaskOnFocusLeave = true // Formats as XX.XXX.XXX/XXXX-XX
};
cnpjTextBox.SetPlaceholder("00.000.000/0000-00");
// Validate and get clean value
if (cnpjTextBox.IsValid)
{
string cleanCnpj = cnpjTextBox.TypedValue; // null if placeholder shown
}
Brazilian Postal Code (CEP)
var cepTextBox = new CEPTextBox
{
IsRequired = true,
ApplyMaskOnFocusLeave = true // Formats as XXXXX-XXX
};
cepTextBox.SetPlaceholder("00000-000");
// Returns numbers only, or null if placeholder/invalid
string cleanCep = cepTextBox.TypedValue;
Numeric Input Controls
Currency Input
var priceTextBox = new ARSCurrencyTextBox
{
MinValue = 0,
MaxValue = 999999.99,
Culture = new CultureInfo("pt-BR") // Brazilian currency format
};
priceTextBox.SetPlaceholder("R$ 0,00");
// Set and get currency values
priceTextBox.TypedValue = 1250.75; // Displays as R$ 1.250,75
// Returns double.MinValue if showing placeholder or invalid
double price = priceTextBox.TypedValue;
Integer Input
var quantityTextBox = new IntegerTextBox
{
MinValue = 1,
MaxValue = 1000,
IsRequired = true
};
quantityTextBox.SetPlaceholder("Quantity");
// Returns int.MinValue if showing placeholder or invalid
int quantity = quantityTextBox.TypedValue;
Double/Decimal Input
var weightTextBox = new DoubleTextBox
{
MinValue = 0.1,
MaxValue = 999.99
};
weightTextBox.SetPlaceholder("0.00");
// Returns double.MinValue if showing placeholder or invalid
double weight = weightTextBox.TypedValue;
Email Validation
var emailTextBox = new EmailTextBox
{
IsRequired = true,
RequiredFieldLabel = emailLabel
};
emailTextBox.SetPlaceholder("user@example.com");
// Email format is automatically validated on focus leave
// Placeholder is properly ignored during validation
// Invalid emails revert to previous value and show in red
Enhanced Labels with Temporary Messages
Standard Label with Auto-Restore
var statusLabel = new ARSLabel
{
InitialText = "Ready",
RestoreInitialTextAfterTimeout = true,
TextTimeout = 3000 // 3 seconds
};
// Show temporary message with optional color
statusLabel.ShowTemporary("Processing...", Color.Blue);
// Automatically reverts to "Ready" after 3 seconds
ToolStrip Label
var toolStripStatus = new ARSToolStripLabel
{
InitialText = "Ready",
RestoreInitialTextAfterTimeout = true,
TextTimeout = 5000
};
toolStripStatus.ShowTemporary("File saved successfully!");
Temporary Visibility Mode
var notificationLabel = new ARSLabel
{
TemporaryVisibility = true, // Hides after timeout
TextTimeout = 2000
};
// Label becomes visible, then auto-hides after 2 seconds
notificationLabel.ShowTemporary("Upload complete!", Color.Green);
Password Input with Reveal Feature
var passwordTextBox = new ARSTextBox
{
UseSystemPasswordChar = true,
ShowPasswordOnMouseOver = true // Reveals password on hover
};
passwordTextBox.SetPlaceholder("Enter password");
Async Loading Overlay
var loading = ARSLoadingOverlay.ShowOver(panelContent, "Consultando CEP...");
try
{
await ConsultarCepAsync();
}
finally
{
loading.CloseOverlay();
}
Async TextBox Leave Operation
var cepTextBox = new CEPTextBox
{
LoadingOverlayTarget = panelContent,
LoadingMessage = "Consultando CEP...",
OnLeaveAsync = async cep => await ConsultarCepAsync(cep)
};
cepTextBox.AsyncOperationCompleted += (sender, args) =>
{
if (!args.Success)
{
MessageBoxHelper.ShowWarning("Nao foi possivel consultar o CEP.");
}
};
CEP Address Lookup
var cepTextBox = new CEPTextBox
{
AutoLookupAddress = true,
LoadingOverlayTarget = panelContent,
CepLookupMessage = "Consultando CEP...",
OnCepLookupAsync = async cep => await BuscarEnderecoAsync(cep)
};
cepTextBox.AddressFound += (sender, args) =>
{
ruaTextBox.Text = args.Address.Street;
bairroTextBox.Text = args.Address.District;
cidadeTextBox.Text = args.Address.City;
ufTextBox.Text = args.Address.State;
};
Settings Management
Export Settings
var settingsManager = new SettingsManager();
try
{
settingsManager.Export(@"C:\backup\app-settings.config");
MessageBoxHelper.ShowInfo("Settings exported successfully!");
}
catch (Exception ex)
{
MessageBoxHelper.ShowError($"Failed to export settings: {ex.Message}");
}
Import Settings
var settingsManager = new SettingsManager();
try
{
settingsManager.Import(
@"C:\backup\app-settings.config",
"MyApp.Properties.Settings"
);
MessageBoxHelper.ShowInfo("Settings imported successfully!");
}
catch (Exception ex)
{
MessageBoxHelper.ShowError($"Failed to import settings: {ex.Message}");
}
🛠️ Utility Classes
Message Box Helpers
// Simplified message boxes
MessageBoxHelper.ShowError("Something went wrong!");
MessageBoxHelper.ShowWarning("Please check your input");
MessageBoxHelper.ShowInfo("Operation completed successfully");
String Utilities
// Convert to title case
string title = Util.ToTitleCase("hello world"); // "Hello World"
// Capitalize first letter only
string name = Util.FirstLetterToUpper("john"); // "John"
Document Validation
// Validate documents without UI controls
bool isValidCpf = DocumentValidations.IsCPF("123.456.789-00");
bool isValidCnpj = DocumentValidations.IsCNPJ("12.345.678/0001-95");
bool isValidCep = DocumentValidations.IsCep("12345-678");
bool isValidEmail = DocumentValidations.IsEmail("user@example.com");
🎨 Advanced Features
Form-Wide Validation
private bool ValidateForm()
{
var controls = this.GetAllControls<ICustomControlsARS>();
// All controls properly handle placeholder validation
return controls.All(control => control.IsValid);
}
private void SaveButton_Click(object sender, EventArgs e)
{
if (!ValidateForm())
{
MessageBoxHelper.ShowWarning("Please fix validation errors before saving.");
return;
}
// Proceed with save operation
SaveData();
}
Working with TypedValue Properties
// TypedValue now correctly handles placeholder state
private void ProcessForm()
{
// Returns null if placeholder is shown
string cpf = cpfTextBox.TypedValue;
// Returns double.MinValue if placeholder is shown
double price = priceTextBox.TypedValue;
// Returns int.MinValue if placeholder is shown
int quantity = quantityTextBox.TypedValue;
// Check for valid input before processing
if (cpf != null && price > 0 && quantity > 0)
{
// Process valid data
ProcessOrder(cpf, price, quantity);
}
}
Cultural Formatting
var currencyBox = new ARSCurrencyTextBox();
// Brazilian format
currencyBox.Culture = new CultureInfo("pt-BR");
currencyBox.SetPlaceholder("R$ 0,00");
currencyBox.TypedValue = 1000; // Displays: R$ 1.000,00
// US format
currencyBox.Culture = new CultureInfo("en-US");
currencyBox.SetPlaceholder("$0.00");
currencyBox.TypedValue = 1000; // Displays: $1,000.00
Readonly After Input
var confirmationTextBox = new ARSTextBox
{
ReadonlyWhenTextChagend = true // Becomes readonly after input
};
confirmationTextBox.SetPlaceholder("Enter confirmation code");
// Once user enters text, field becomes readonly
🔧 Interface Overview
| Interface | Purpose |
|---|---|
ICustomControlsARS |
Base interface for validation and required field handling |
ICustomLabelARS |
Interface for labels with temporary message capabilities |
INumericRangeControlARS |
Interface for controls with min/max value constraints |
IDocumentField |
Interface for document input controls with masking |
📋 Control Summary
| Control | Purpose | Key Features |
|---|---|---|
ARSTextBox |
Enhanced text input | Validation, placeholders, password reveal |
CPFTextBox |
Brazilian CPF input | Auto-masking, validation, clean value extraction |
CNPJTextBox |
Brazilian CNPJ input | Auto-masking, validation, clean value extraction |
CEPTextBox |
Brazilian postal code | Auto-masking, validation |
EmailTextBox |
Email address input | Format validation, error highlighting |
DoubleTextBox |
Decimal number input | Range validation, culture-aware parsing |
IntegerTextBox |
Integer input | Range validation, input restriction |
ARSCurrencyTextBox |
Currency input | Culture-aware formatting, range validation |
ARSLabel |
Enhanced label | Temporary messages, auto-restore, color changes |
ARSToolStripLabel |
Enhanced ToolStrip label | Temporary messages for status bars |
ARSLoadingOverlay |
Async loading overlay | Centered spinner, message, container targeting |
AsyncLoadingOverlay |
Compatibility loading helper | Legacy async loading API backed by ARSLoadingOverlay |
💡 Best Practices
Placeholder Usage
// ✅ DO: Use descriptive placeholders
emailTextBox.SetPlaceholder("usuario@exemplo.com.br");
cpfTextBox.SetPlaceholder("000.000.000-00");
// ❌ DON'T: Rely on placeholder for validation
// The control now properly handles this, but placeholders should guide, not validate
Validation Patterns
// ✅ DO: Check IsEmpty before processing
if (!customerNameBox.IsEmpty)
{
string name = customerNameBox.Text;
ProcessCustomer(name);
}
// ✅ DO: Use TypedValue for numeric/document controls
if (priceBox.TypedValue != double.MinValue)
{
decimal price = (decimal)priceBox.TypedValue;
CalculateTotal(price);
}
// ✅ DO: Check for null on document controls
string cpf = cpfBox.TypedValue;
if (cpf != null)
{
ValidateCustomer(cpf);
}
Required Field Handling
// ✅ DO: Assign labels to show validation state
var nameBox = new ARSTextBox
{
IsRequired = true,
RequiredFieldLabel = nameLabel
};
// The label automatically turns red when validation fails
// Placeholder is properly considered as "empty" for required fields
🤝 Contributing
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🆘 Support
If you encounter any issues or have questions, please:
- Check the documentation and examples above
- Search existing issues on GitHub
- Create a new issue with detailed information about your problem
📝 Changelog
v3.0.3 (Current)
- Added centered
ARSLoadingOverlay - Restored async compatibility APIs from previous package versions
- Added
LoadingOverlayTargetfor correct overlay placement in consumer UIs - Added CEP async lookup support through
OnCepLookupAsync,AutoLookupAddress,AddressFound, andLookupAddressAsync() - Fixed numeric range enforcement, double parsing culture handling, caret positioning, and duplicated placeholder event handlers
v3.0.1
- ✨ Smart placeholder validation - placeholders no longer interfere with validation
- 🐛 Fixed
IsEmptyproperty to correctly identify placeholder state - 🐛 Fixed
TypedValueproperties to return appropriate empty values when placeholder is shown - 🐛 Improved
DocumentTextBoxvalidation to skip format checking on placeholders - 🐛 Enhanced
ARSCurrencyTextBoxto skip formatting when placeholder is displayed - 🔧 All numeric controls now check for placeholder before parsing values
v3.0.0
- Initial public release
- Full suite of enhanced WinForms controls
- Document validation for Brazilian documents
- Settings management utilities
- Comprehensive validation framework
Made with ❤️ for the WinForms community
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows7.0 is compatible. net9.0-windows was computed. net10.0-windows was computed. |
-
net8.0-windows7.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Fixes async loading overlay centering, restores OnLeaveAsync compatibility, and adds CEP async lookup support.