Hi.Core 3.2.0

dotnet add package Hi.Core --version 3.2.0
                    
NuGet\Install-Package Hi.Core -Version 3.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Hi.Core" Version="3.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Hi.Core" Version="3.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Hi.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Hi.Core --version 3.2.0
                    
#r "nuget: Hi.Core, 3.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Hi.Core@3.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Hi.Core&version=3.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Hi.Core&version=3.2.0
                    
Install as a Cake Tool

HiLibrary.CSharp

A comprehensive C# utility library providing common helpers, extensions, and WPF components for .NET applications.

License

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 thread
  • EventThreadPolicy.PublishThread - Execute on the publisher's thread
  • EventThreadPolicy.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"
});

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");
    }
}
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

XtremlyRed

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .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.

Version Downloads Last Updated
3.2.0 273 12/14/2025
Loading failed