Hi.Core
3.2.0
dotnet add package Hi.Core --version 3.2.0
NuGet\Install-Package Hi.Core -Version 3.2.0
<PackageReference Include="Hi.Core" Version="3.2.0" />
<PackageVersion Include="Hi.Core" Version="3.2.0" />
<PackageReference Include="Hi.Core" />
paket add Hi.Core --version 3.2.0
#r "nuget: Hi.Core, 3.2.0"
#:package Hi.Core@3.2.0
#addin nuget:?package=Hi.Core&version=3.2.0
#tool nuget:?package=Hi.Core&version=3.2.0
HiLibrary.CSharp
A comprehensive C# utility library providing common helpers, extensions, and WPF components for .NET applications.
Features
HiLibrary.CSharp is organized into two main packages:
- HiLibrary - Core utilities, extensions, and helpers for any .NET application
- HiLibrary.Wpf - WPF-specific components including animations, dialogs, popups, and converters
Supported Frameworks
| Framework | Version |
|---|---|
| .NET Framework | 4.5.1, 4.7.2 |
| .NET Core | 3.1 |
| .NET | 6.0, 8.0, 9.0 |
| .NET Standard | 2.0 |
Installation
# Install core library
dotnet add package Hi.Core
# Install WPF library (for WPF projects)
dotnet add package Hi.Wpf
HiLibrary (Core)
Commands
Powerful command implementations for MVVM pattern with synchronous and asynchronous support.
BindingCommand
// Simple command
public ICommand SaveCommand => new BindingCommand(() => Save());
// Command with CanExecute
public ICommand DeleteCommand => new BindingCommand(
() => Delete(),
() => SelectedItem != null
);
// Implicit conversion from Action
BindingCommand command = () => DoSomething();
// Global exception handling
BindingCommand.SetGlobalCommandExceptionCallback(ex =>
{
Logger.LogError(ex, "Command execution failed");
});
BindingCommandAsync
// Async command
public IBindingCommandAsync LoadCommand => new BindingCommandAsync(
async () => await LoadDataAsync(),
() => !IsLoading
);
// Check if command is executing
if (LoadCommand.IsExecuting)
{
// Show loading indicator
}
Generic Commands with Parameters
// Command with parameter
public ICommand SelectCommand => new BindingCommand<Item>(item => Select(item));
// Async command with parameter
public IBindingCommandAsync<int> FetchCommand => new BindingCommandAsync<int>(
async id => await FetchAsync(id)
);
Event Manager
A flexible pub/sub event aggregator supporting synchronous and asynchronous events with channel-based messaging.
// Create event manager
IEventManager eventManager = new EventManager();
// Subscribe to events
IUnsubscrible subscription = eventManager.GetEvent<UserLoggedInEvent>()
.Subscribe(e => HandleUserLogin(e), EventThreadPolicy.Current);
// Publish events
eventManager.GetEvent<UserLoggedInEvent>().Publish(new UserLoggedInEvent(user));
// Channel-based messaging
eventManager.GetEvent<NotificationEvent>()
.Subscribe("alerts", notification => ShowAlert(notification));
eventManager.GetEvent<NotificationEvent>()
.Publish("alerts", new NotificationEvent("New message"));
// Async events
var asyncEvent = eventManager.GetAsyncEvent<DataChangedEvent>();
await asyncEvent.PublishAsync(new DataChangedEvent());
// Unsubscribe when done
subscription.Unsubscribe();
Thread Policies:
EventThreadPolicy.Current- Execute on the subscriber's original threadEventThreadPolicy.PublishThread- Execute on the publisher's threadEventThreadPolicy.NewThread- Execute on a new thread pool thread
Context
Type-safe context containers for storing and retrieving values.
// Application-wide context
IApplicationContext appContext = new ApplicationContext();
// Store values by type
appContext.SetValue(new UserSettings());
appContext.SetValue("theme", "dark");
// Retrieve values
var settings = appContext.GetValue<UserSettings>();
var theme = appContext.GetValue<string>("theme");
// Safe retrieval
if (appContext.TryGetValue<UserSettings>(out var userSettings))
{
// Use settings
}
Deferred Execution
Execute actions after a specified delay with debouncing support.
// Simple deferred action
IDeferredToken token = Defer.Deferred(500) // 500ms delay
.Invoke(() => SearchAsync(query));
// Restart the timer (debouncing)
token.Restart();
// With TimeSpan
IDeferredToken token2 = Defer.Deferred(TimeSpan.FromSeconds(1))
.Invoke(async () => await SaveChangesAsync());
// With context information
Defer.Deferred(1000).Invoke(context =>
{
Console.WriteLine($"Executed on thread {context.ThreadId}");
Console.WriteLine($"Was abandoned: {context.IsAbandoned}");
});
// Execute on UI thread
Defer.Deferred(500).Invoke(
() => UpdateUI(),
invokeInCurrentThread: true
);
// Dispose to cancel
token.Dispose();
Awaiter (Semaphore Wrapper)
A simple wrapper around SemaphoreSlim for resource management.
// Create awaiter with initial and max count
var awaiter = new Awaiter(initialCount: 3, maxCount: 5);
// Wait for resource
await awaiter.WaitAsync();
try
{
// Use resource
}
finally
{
awaiter.Release();
}
// Extension methods for locked execution
await awaiter.LockInvokeAsync(async () =>
{
await DoWorkAsync();
});
// With timeout
bool acquired = await awaiter.WaitAsync(
millisecondsTimeout: 5000,
cancellationToken: cts.Token
);
Extension Methods
Enumerable Extensions
// Null/empty checks
if (collection.IsNullOrEmpty()) { }
if (collection.IsNotNullOrEmpty()) { }
// Conditional filtering
var filtered = items.WhereIf(includeDeleted, x => x.IsDeleted);
// Find index
int index = items.IndexOf(x => x.Id == targetId);
// Pagination
var page = items.Paginate(pageIndex: 2, pageSize: 10);
// ForEach with action
items.ForEach(item => Process(item));
items.ForEach((item, index) => Process(item, index));
// Async ForEach
await items.ForEachAsync(async item => await ProcessAsync(item));
// Join to string
string csv = items.Join(x => x.Name, ", ");
// To read-only collections
IReadOnlyList<T> readOnlyList = items.ToReadOnlyList();
IReadOnlyDictionary<K, V> readOnlyDict = dict.ToReadOnlayDictionary();
// Chunking (for older frameworks)
var chunks = items.Chunk(100);
Task Extensions
// Await TaskCompletionSource directly
var tcs = new TaskCompletionSource<int>();
int result = await tcs;
// Await multiple TaskCompletionSources
var sources = new[] { tcs1, tcs2, tcs3 };
int[] results = await sources;
// Await TimeSpan as delay
await TimeSpan.FromSeconds(1);
// Await collection of tasks
var tasks = items.Select(x => ProcessAsync(x));
await tasks;
String Extensions
// Various string utility methods
string formatted = text.ToTitleCase();
bool isEmpty = text.IsNullOrEmpty();
DateTime Extensions
// DateTime utility methods
var startOfDay = date.StartOfDay();
var endOfMonth = date.EndOfMonth();
Type Conversion
Flexible type conversion with custom converter registration.
// Convert using registered converters
int number = "123".ConvertTo<int>();
DateTime date = "2024-01-01".ConvertTo<DateTime>();
// Register custom converter
TypeConverterExtensions.ConvertRegister<string, CustomType>(
str => CustomType.Parse(str)
);
// Use custom converter
var custom = "value".ConvertTo<CustomType>();
Thrower (Argument Validation)
Utility methods for argument validation with detailed exception messages.
public void Process(string input, object data)
{
Thrower.IsNullOrEmpty(input, nameof(input));
Thrower.IsNullOrWhiteSpace(input, nameof(input));
Thrower.IsNull(data, nameof(data));
}
HiLibrary.Wpf
Animations
Fluent API for creating WPF property animations.
// Create animation
var handler = element.BeginAnimation(UIElement.OpacityProperty)
.From(0.0)
.To(1.0)
.Duration(TimeSpan.FromMilliseconds(300))
.EasingFunction(new CubicEase())
.Delay(TimeSpan.FromMilliseconds(100))
.AutoReverse(true)
.RepeatBehavior(RepeatBehavior.Forever)
.Completed(() => Console.WriteLine("Animation completed"))
.Build();
// Start animation
handler.Begin();
// Supported property types:
// - Numeric: byte, short, int, long, float, double, decimal
// - Geometry: Point, Point3D, Vector, Vector3D, Rect, Size
// - Other: Color, Quaternion, Rotation3D
Dialog Service
Show modal and non-modal dialogs.
IDialogService dialogService = new DialogService();
// Show non-modal dialog
dialogService.Show(new MyDialogView(), new DialogParameter
{
Title = "Settings",
Width = 400,
Height = 300
});
// Show modal dialog
bool? result = dialogService.ShowDialog(new ConfirmView(), new DialogParameter
{
Title = "Confirm Action"
});
Popup Service
Display popups for messages, confirmations, and custom content.
IPopupService popupService = new PopupService();
// Show message
await popupService.ShowAsync("Operation completed successfully", "Success");
// Show confirmation
ButtonResult result = await popupService.ConfirmAsync(
"Are you sure you want to delete this item?",
"Confirm Delete"
);
if (result == ButtonResult.OK)
{
// Delete item
}
// Show custom popup
var customResult = await popupService.PopupAsync<CustomResult>(
new CustomPopupView(),
new PopupParameter { /* options */ }
);
// Show in specific host
await popupService.ShowAsyncIn("DialogHost", "Message", "Title");
Notification Service
Display toast-style notifications.
INotificationService notificationService = new NotificationService();
// Show notification
await notificationService.NotifyAsync(
"File saved successfully",
TimeSpan.FromSeconds(3)
);
// Show in specific host
await notificationService.NotifyAsyncIn(
"NotificationHost",
"New message received",
TimeSpan.FromSeconds(5)
);
Converters
Pre-built value converters for common scenarios.
// Boolean converters
Converters.BooleanReverse // true -> false, false -> true
Converters.BooleanToVisibility // true -> Visible, false -> Collapsed
Converters.BooleanToVisibilityReverse // true -> Collapsed, false -> Visible
// Null check converters
Converters.IsNull // null -> true
Converters.IsNotNull // not null -> true
Converters.IsNullOrEmpty // null/empty -> true
Converters.IsNotNullOrEmpty // not null/empty -> true
Converters.IsNullOrWhiteSpace // null/whitespace -> true
Converters.IsNotNullOrWhiteSpace // not null/whitespace -> true
// Visibility converters
Converters.IsNullToVisibility
Converters.IsNotNullToVisibility
Converters.IsNullOrEmptyToVisibility
Converters.IsNotNullOrEmptyToVisibility
// Comparison converters (to Visibility)
Converters.EqualToVisibility
Converters.NotEqualToVisibility
Converters.GreaterThanToVisibility
Converters.GreaterThanOrEqualToVisibility
Converters.LessThanToVisibility
Converters.LessThanOrEqualToVisibility
// Enum converters
Converters.GetEnumDescription // Get [Description] attribute
Converters.GetEnumDisplayName // Get [Display] attribute
// Color converters
Converters.StringToColor // "#FF0000" -> Color
Converters.StringToBrush // "#FF0000" -> Brush
Usage in XAML:
<Window xmlns:hi="clr-namespace:HiLibrary;assembly=HiLibrary.Wpf">
<Button Visibility="{Binding HasItems,
Converter={x:Static hi:Converters.BooleanToVisibility}}" />
<TextBlock Visibility="{Binding Name,
Converter={x:Static hi:Converters.IsNotNullOrEmptyToVisibility}}" />
</Window>
UI Dispatcher
Create background UI threads with their own Dispatcher.
// Create async
Dispatcher backgroundDispatcher = await UIDispatcher.RunNewAsync("RenderThread");
// Create sync
Dispatcher dispatcher = UIDispatcher.RunNew("BackgroundUI");
// Execute on background dispatcher
backgroundDispatcher.InvokeAsync(() =>
{
// This runs on the background UI thread
var visual = CreateVisual();
});
Controls
TransitioningControl
A content control that animates content changes.
<hi:TransitioningControl Content="{Binding CurrentView}">
</hi:TransitioningControl>
EnumComboBox
A ComboBox that automatically populates with enum values.
<hi:EnumComboBox EnumType="{x:Type local:MyEnum}"
SelectedValue="{Binding SelectedOption}" />
Performance Utilities
Tools for performance monitoring and UI optimization.
// Color animation performer
var colorPerformer = new ColorPerformer();
// Transition performer
var transitionPerformer = new TransitionPerformer();
Examples
MVVM ViewModel with Commands
public class MainViewModel : INotifyPropertyChanged
{
public IBindingCommand SaveCommand { get; }
public IBindingCommandAsync LoadCommand { get; }
public MainViewModel()
{
SaveCommand = new BindingCommand(Save, () => CanSave);
LoadCommand = new BindingCommandAsync(LoadAsync, () => !IsLoading);
}
private void Save() { /* ... */ }
private async Task LoadAsync() { /* ... */ }
}
Event-Driven Architecture
public class OrderService
{
private readonly IEventManager _eventManager;
public OrderService(IEventManager eventManager)
{
_eventManager = eventManager;
}
public async Task PlaceOrderAsync(Order order)
{
await ProcessOrderAsync(order);
// Notify other parts of the application
_eventManager.GetEvent<OrderPlacedEvent>()
.Publish(new OrderPlacedEvent(order));
}
}
public class NotificationHandler
{
public NotificationHandler(IEventManager eventManager)
{
eventManager.GetEvent<OrderPlacedEvent>()
.Subscribe(OnOrderPlaced, EventThreadPolicy.Current);
}
private void OnOrderPlaced(OrderPlacedEvent e)
{
ShowNotification($"Order {e.Order.Id} placed successfully");
}
}
Debounced Search
public class SearchViewModel
{
private IDeferredToken? _searchToken;
public string SearchText
{
get => _searchText;
set
{
_searchText = value;
DebouncedSearch();
}
}
private void DebouncedSearch()
{
_searchToken?.Restart();
_searchToken ??= Defer.Deferred(300)
.Invoke(async () => await SearchAsync(_searchText),
invokeInCurrentThread: true);
}
}
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Author
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 is compatible. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net451 is compatible. net452 was computed. net46 was computed. net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETCoreApp 3.1
- No dependencies.
-
.NETFramework 4.5.1
- No dependencies.
-
.NETFramework 4.7.2
- No dependencies.
-
.NETStandard 2.0
- No dependencies.
-
net6.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.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.