Welcome to the CodingDad.NET.Common class library! This repository contains a collection of commonly used classes and utilities designed to streamline and enhance your .NET projects. As a developer, you often encounter repetitive tasks and patterns across different projects. The CodingDad.NET.Common library aims to provide a reusable, well-structured set of tools to help you write cleaner, more efficient code, and reduce redundancy.
You can consume the CodingDad.NET.Common library in two ways:
If you're using the .nupkg file from the Releases section:
- Download
CodingDad.NET.Common.1.0.0.nupkgto a target folder. - In Visual Studio:
- Right-click on your solution and select Manage NuGet Packages for Solution...
- Click the gear icon âš™ in the top-right and choose Add Package Source
- Add a new source to the path of the folder containing the
.nupkg
- Search for
CodingDad.NET.Commonin the Browse tab and install it
- Download the following from the Releases page:
CodingDad.NET.Common.dllCodingDad.NET.Common.pdb(optional for debugging)CodingDad.NET.Common.xml(optional for IntelliSense docs)
- In your project:
- Right-click References → Add Reference...
- Browse to and select the DLL
⚠️ Dependencies likeMicrosoft.Extensions.LoggingandNewtonsoft.Jsonmust be installed manually via NuGet.
The CodingDad.NET.Common library is a versatile and comprehensive set of components built to support a wide range of .NET applications. Whether you're developing web applications, desktop applications, or services, this library offers essential utilities to simplify your development process.
- Overview
- Behaviors
- Commands
- CustomControls
- DbHelpers
- Factories
- InputOutput
- Locators
- Loggers
- StorageLocationManager
- User Creation and Login
- MefJsonUtility
- BaseViewModel
- Attributions
The BehaviorAttacher class is a static helper class designed to dynamically attach behaviors to WPF UIElement controls using attached properties. This is particularly useful for scenarios where you want to declaratively add behaviors to your UI elements in XAML without having to explicitly define them in the code-behind.
AttachBehaviorsProperty: An attached property of typeboolused to trigger the attachment of behaviors.BehaviorTypesProperty: An attached property of typestringthat specifies a comma-separated list of behavior types to attach to the target element.
GetBehaviorTypes(DependencyObject element): Retrieves the value of theBehaviorTypesPropertyattached property.SetAttachBehaviors(DependencyObject element, bool value): Sets the value of theAttachBehaviorsPropertyattached property.SetBehaviorTypes(DependencyObject element, string value): Sets the value of theBehaviorTypesPropertyattached property.
FindExistingBehavior(BehaviorCollection behaviors, Type behaviorType): Searches for an existing behavior of the specified type within a givenBehaviorCollection.OnAttachBehaviorsChanged(DependencyObject element, DependencyPropertyChangedEventArgs e): Callback method that gets invoked when the attached properties change. It parses the behavior types, creates instances of the specified behaviors, and attaches them to the target element.
To use the BehaviorAttacher class in your XAML, follow these steps:
-
Include the necessary namespaces:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:local="clr-namespace:YourNamespace"
-
Attach the behaviors to your
UIElementusing the attached properties:<Button Content="Click Me" local:BehaviorAttacher.AttachBehaviors="True" local:BehaviorAttacher.BehaviorTypes="NamespaceOfBehavior1.Behavior1, NamespaceOfBehavior2.Behavior2" />
In this example, replace NamespaceOfBehavior1.Behavior1 and NamespaceOfBehavior2.Behavior2 with the fully qualified names of the behaviors you want to attach to the Button.
Here's a complete example in context:
<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:YourNamespace"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Click Me"
local:BehaviorAttacher.AttachBehaviors="True"
local:BehaviorAttacher.BehaviorTypes="NamespaceOfBehavior1.Behavior1, NamespaceOfBehavior2.Behavior2" />
</Grid>
</Window>This setup allows you to dynamically attach multiple behaviors to UI elements by specifying the behavior types in a comma-separated string. The BehaviorAttacher class will handle the creation and attachment of these behaviors at runtime.
The MefSafeBehaviorAttacher class is a static helper class designed to dynamically attach behaviors to XAML elements using MEF (Managed Extensibility Framework) for dependency injection. This class is useful for scenarios where you want to declaratively add behaviors to your UI elements in XAML without having to explicitly define them in the code-behind, and to leverage MEF for creating behavior instances.
AttachBehaviorsProperty: An attached property of typeboolused to trigger the attachment of behaviors.BehaviorTypesProperty: An attached property of typestringthat specifies a comma-separated list of behavior types to attach to the target element.
GetBehaviorTypes(DependencyObject element): Retrieves the value of theBehaviorTypesPropertyattached property.SetAttachBehaviors(DependencyObject element, bool value): Sets the value of theAttachBehaviorsPropertyattached property.SetBehaviorTypes(DependencyObject element, string value): Sets the value of theBehaviorTypesPropertyattached property.
FindExistingBehavior(BehaviorCollection behaviors, Type behaviorType): Searches for an existing behavior of the specified type within a givenBehaviorCollection.OnAttachBehaviorsChanged(DependencyObject element, DependencyPropertyChangedEventArgs e): Callback method that gets invoked when the attached properties change. It parses the behavior types, creates instances of the specified behaviors using MEF, and attaches them to the target element.
To use the MefSafeBehaviorAttacher class in your XAML, follow these steps:
-
Include the necessary namespaces:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:local="clr-namespace:YourNamespace"
-
Attach the behaviors to your
UIElementusing the attached properties:<Button Content="Click Me" local:MefSafeBehaviorAttacher.AttachBehaviors="True" local:MefSafeBehaviorAttacher.BehaviorTypes="NamespaceOfBehavior1.Behavior1, NamespaceOfBehavior2.Behavior2" />
In this example, replace NamespaceOfBehavior1.Behavior1 and NamespaceOfBehavior2.Behavior2 with the fully qualified names of the behaviors you want to attach to the Button.
Here's a complete example in context:
<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:YourNamespace"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Click Me"
local:MefSafeBehaviorAttacher.AttachBehaviors="True"
local:MefSafeBehaviorAttacher.BehaviorTypes="NamespaceOfBehavior1.Behavior1, NamespaceOfBehavior2.Behavior2" />
</Grid>
</Window>This setup allows you to dynamically attach multiple behaviors to UI elements by specifying the behavior types in a comma-separated string. The MefSafeBehaviorAttacher class will handle the creation and attachment of these behaviors at runtime, leveraging MEF for dependency injection.
The WindowCloseBehavior class is a static helper class designed to bind a command to the closing of a WPF window. This allows you to perform custom actions when a window is closed, such as saving state or cleaning up resources.
CloseCommandProperty: An attached property of typeICommandused to bind a command to the window's close event.
GetCloseCommand(DependencyObject obj): Retrieves the value of theCloseCommandPropertyattached property.SetCloseCommand(DependencyObject obj, ICommand value): Sets the value of theCloseCommandPropertyattached property.
OnCloseCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e): Callback method that gets invoked when theCloseCommandPropertychanges. It attaches or detaches the window's Closed event handler based on the property value.OnWindowClosed(object sender, EventArgs e): Handles the Closed event of the window and executes the bound command.
To use the WindowCloseBehavior class in your XAML, follow these steps:
-
Include the necessary namespace:
xmlns:local="clr-namespace:YourNamespace"
-
Bind the
CloseCommandproperty to a command in your view model:<Window x:Class="YourNamespace.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourNamespace" Title="MainWindow" Height="350" Width="525" local:WindowCloseBehavior.CloseCommand="{Binding CloseCommand}"> <!-- Window content --> </Window>
In this example, replace YourNamespace with the appropriate namespace for your project. The CloseCommand property is bound to a command in your view model that will be executed when the window is closed.
Here's a complete example in context:
<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourNamespace"
Title="MainWindow" Height="350" Width="525"
local:WindowCloseBehavior.CloseCommand="{Binding CloseCommand}">
<Grid>
<!-- Window content -->
</Grid>
</Window>This setup allows you to bind a command to the window's close event, enabling you to perform custom actions when the window is closed.
The RelayCommand class is a simple yet powerful implementation of the ICommand interface that allows you to delegate command logic using delegates. This class is especially useful for implementing commands in MVVM (Model-View-ViewModel) patterns in WPF, UWP, and other XAML-based applications.
CanExecuteChanged: An event that occurs when changes occur that affect whether or not the command should execute.
RelayCommand(Action<object> execute): Initializes a new instance of theRelayCommandclass with an execute delegate.RelayCommand(Predicate<object?>? canExecute, Action<object> execute): Initializes a new instance of theRelayCommandclass with canExecute and execute delegates.CanExecute(object? parameter): Defines the method that determines whether the command can execute in its current state.Execute(object parameter): Defines the method to be called when the command is invoked.
To use the RelayCommand class in your application, follow these steps:
-
Create an instance of
RelayCommandin your ViewModel:public class MainViewModel { public ICommand MyCommand { get; } public MainViewModel() { MyCommand = new RelayCommand(ExecuteMyCommand, CanExecuteMyCommand); } private bool CanExecuteMyCommand(object? parameter) { // Your logic to determine if the command can execute return true; } private void ExecuteMyCommand(object parameter) { // Your logic to execute the command } }
-
Bind the command to a UI element in your XAML:
<Window x:Class="YourNamespace.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <local:MainViewModel /> </Window.DataContext> <Grid> <Button Content="Click Me" Command="{Binding MyCommand}" /> </Grid> </Window>
In this example, replace YourNamespace with the appropriate namespace for your project. The MyCommand property is bound to the RelayCommand in your ViewModel, and the Button in the XAML will execute the command when clicked.
Here's a complete example in context:
<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Button Content="Click Me" Command="{Binding MyCommand}" />
</Grid>
</Window>This setup allows you to easily bind commands to UI elements and define the command logic in your ViewModel.
The ResizableGridControl class is a custom WPF Grid control that supports dynamic row and column resizing. This control allows users to resize rows and columns by dragging the edges with the mouse, providing a more flexible and interactive layout experience.
AddColumn(): Adds a new column to the grid.AddRow(): Adds a new row to the grid.RemoveColumn(int index): Removes a column at the specified index from the grid.RemoveRow(int index): Removes a row at the specified index from the grid.
GridControl_MouseDown(object sender, MouseButtonEventArgs e): Handles the MouseDown event, initiating row or column resizing.GridControl_MouseLeave(object sender, MouseEventArgs e): Handles the MouseLeave event, cancelling row or column resizing.GridControl_MouseMove(object sender, MouseEventArgs e): Handles the MouseMove event, performing row or column resizing.GridControl_MouseUp(object sender, MouseButtonEventArgs e): Handles the MouseUp event, finalizing row or column resizing.
To use the ResizableGridControl in your application, follow these steps:
-
Include the necessary namespace:
xmlns:local="clr-namespace:YourNamespace"
-
Use the
ResizableGridControlin your XAML:<local:ResizableGridControl> <!-- Add your content here --> </local:ResizableGridControl>
Here's a complete example in context:
<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourNamespace"
Title="MainWindow" Height="350" Width="525">
<local:ResizableGridControl>
<local:ResizableGridControl.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</local:ResizableGridControl.ColumnDefinitions>
<local:ResizableGridControl.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
</local:ResizableGridControl.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Cell 0,0" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="Cell 0,1" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Cell 1,0" />
<TextBlock Grid.Row="1" Grid.Column="1" Text="Cell 1,1" />
</local:ResizableGridControl>
</Window>This setup allows you to use the ResizableGridControl to create grids with dynamically resizable rows and columns. Users can resize the rows and columns by dragging the edges with the mouse.
The MongoDbHelper<T> class is a general-purpose interface for interacting with a MongoDB database. This class provides methods to create, read, update, and delete documents in a MongoDB collection, and it uses the LoggerProvider for logging operations.
MongoDbHelper(string connectionString, string databaseName, string collectionName): Initializes a new instance of theMongoDbHelper<T>class.CreateUserAsync(string email, string username, string password): Asynchronously creates a new user in the MongoDB database.DeleteAsync(ObjectId id): Deletes a document from the collection by its ObjectId.GetAllAsync(): Retrieves all documents from the collection.GetByIdAsync(ObjectId id): Retrieves a document by its ObjectId.InsertAsync(T document): Inserts a document into the collection.UpdateAsync(ObjectId id, T document): Updates a document in the collection by its ObjectId.VerifyUserAsync(string email, string password): Asynchronously verifies if a user with the given email and password exists in the MongoDB database.
To use the MongoDbHelper<T> class in your application, follow these steps:
-
Create an instance of
MongoDbHelper<T>in your code:var mongoDbHelper = new MongoDbHelper<MyDocumentClass>("your_connection_string", "your_database_name", "your_collection_name");
-
Use the available methods to interact with the MongoDB database. For example, to insert a document:
await mongoDbHelper.InsertAsync(new MyDocumentClass { Name = "John", Age = 30 });
-
To retrieve all documents from the collection:
var allDocuments = await mongoDbHelper.GetAllAsync();
-
To verify a user:
bool isVerified = await mongoDbHelper.VerifyUserAsync("user@example.com", "password");
Here's a complete example in context:
public class MyDocumentClass
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
var mongoDbHelper = new MongoDbHelper<MyDocumentClass>("your_connection_string", "your_database_name", "your_collection_name");
await mongoDbHelper.InsertAsync(new MyDocumentClass { Name = "John", Age = 30 });
var allDocuments = await mongoDbHelper.GetAllAsync();
bool isVerified = await mongoDbHelper.VerifyUserAsync("user@example.com", "password");This setup allows you to easily interact with a MongoDB database, performing CRUD operations and logging activities using the LoggerProvider.
The SqlServerHelper class is a general-purpose interface for interacting with a SQL Server database. This class provides methods to create, read, update, and delete records in a SQL Server database, and it uses the LoggerProvider for logging operations.
SqlServerHelper(string connectionString): Initializes a new instance of theSqlServerHelperclass.CreateUserAsync(string email, string username, string password): Asynchronously creates a new user in the SQL Server database.ExecuteNonQueryAsync(string commandText, SqlParameter[] parameters = null): Executes a non-query SQL command.ExecuteQueryAsync(string queryText, SqlParameter[] parameters = null): Executes a SQL query and returns the result as a DataTable.VerifyUser(string email, string password): Verifies if a user with the given email and password exists in the database.VerifyUserAsync(string email, string password): Asynchronously verifies if a user with the given email and password exists in the database.
To use the SqlServerHelper class in your application, follow these steps:
-
Create an instance of
SqlServerHelperin your code:var sqlServerHelper = new SqlServerHelper("your_connection_string");
-
Use the available methods to interact with the SQL Server database. For example, to insert a user:
await sqlServerHelper.CreateUserAsync("user@example.com", "username", "password");
-
To execute a non-query command:
string commandText = "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)"; SqlParameter[] parameters = { new SqlParameter("@Name", "John"), new SqlParameter("@Age", 30) }; await sqlServerHelper.ExecuteNonQueryAsync(commandText, parameters);
-
To execute a query and get results as a DataTable:
string queryText = "SELECT * FROM Users WHERE Age > @Age"; SqlParameter[] parameters = { new SqlParameter("@Age", 25) }; DataTable result = await sqlServerHelper.ExecuteQueryAsync(queryText, parameters);
-
To verify a user:
bool isVerified = sqlServerHelper.VerifyUser("user@example.com", "password");
Here's a complete example in context:
public class User
{
public string Email { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
var sqlServerHelper = new SqlServerHelper("your_connection_string");
await sqlServerHelper.CreateUserAsync("user@example.com", "username", "password");
string commandText = "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)";
SqlParameter[] parameters = {
new SqlParameter("@Name", "John"),
new SqlParameter("@Age", 30)
};
await sqlServerHelper.ExecuteNonQueryAsync(commandText, parameters);
string queryText = "SELECT * FROM Users WHERE Age > @Age";
parameters = new SqlParameter[] {
new SqlParameter("@Age", 25)
};
DataTable result = await sqlServerHelper.ExecuteQueryAsync(queryText, parameters);
bool isVerified = sqlServerHelper.VerifyUser("user@example.com", "password");This setup allows you to easily interact with a SQL Server database, performing CRUD operations and logging activities using the LoggerProvider.
The SQLiteHelper class is a general-purpose interface for interacting with a SQLite database. This class provides methods to create, read, update, and delete records in a SQLite database, and it uses the LoggerProvider for logging operations.
SQLiteHelper(string connectionString): Initializes a new instance of theSQLiteHelperclass.CreateTableAsync(string createTableQuery): Asynchronously creates a table if it doesn't already exist.CreateUserAsync(string email, string username, string password): Asynchronously creates a new user in the SQLite database.DeleteRecordAsync(string tableName, string conditionColumn, object conditionValue): Deletes a record from a specified table based on a condition.ExecuteNonQueryAsync(string commandText, SQLiteParameter[] parameters = null): Executes a non-query SQL command asynchronously.ExecuteQueryAsync(string queryText, SQLiteParameter[] parameters = null): Executes a SQL query and returns the result as a DataTable.InsertIntoTableAsync(string tableName, Dictionary<string, object?> columnData): Inserts a new record into a specified table.RetrieveAllViewModelStatesAsync(string viewModelName): Asynchronously retrieves the serialized states of all instances of a specific ViewModel from the database.SaveSingletonViewModelStateAsync(string viewModelName, string serializedState): Asynchronously saves the serialized state of a ViewModel into the database.SaveViewModelStateAsync(string viewModelName, string instanceId, string serializedState): Asynchronously saves the serialized state of a ViewModel into the database.StoreUniqueIdentifierAsync(string userId, string uniqueIdentifier): Stores a unique identifier for a user.VerifyUserAsync(string email, string password): Asynchronously verifies if a user with the given email and password exists in the SQLite database.
To use the SQLiteHelper class in your application, follow these steps:
-
Create an instance of
SQLiteHelperin your code:var sqliteHelper = new SQLiteHelper("your_connection_string");
-
Use the available methods to interact with the SQLite database. For example, to create a table:
await sqliteHelper.CreateTableAsync("CREATE TABLE IF NOT EXISTS Users (Id INTEGER PRIMARY KEY, Email TEXT, Username TEXT, Password TEXT)");
-
To insert a user:
await sqliteHelper.CreateUserAsync("user@example.com", "username", "password");
-
To execute a non-query command:
string commandText = "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)"; SQLiteParameter[] parameters = { new SQLiteParameter("@Name", "John"), new SQLiteParameter("@Age", 30) }; await sqliteHelper.ExecuteNonQueryAsync(commandText, parameters);
-
To execute a query and get results as a DataTable:
string queryText = "SELECT * FROM Users WHERE Age > @Age"; SQLiteParameter[] parameters = { new SQLiteParameter("@Age", 25) }; DataTable result = await sqliteHelper.ExecuteQueryAsync(queryText, parameters);
-
To verify a user:
bool isVerified = await sqliteHelper.VerifyUserAsync("user@example.com", "password");
Here's a complete example in context:
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
var sqliteHelper = new SQLiteHelper("your_connection_string");
await sqliteHelper.CreateTableAsync("CREATE TABLE IF NOT EXISTS Users (Id INTEGER PRIMARY KEY, Email TEXT, Username TEXT, Password TEXT)");
await sqliteHelper.CreateUserAsync("user@example.com", "username", "password");
string commandText = "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)";
SQLiteParameter[] parameters = {
new SQLiteParameter("@Name", "John"),
new SQLiteParameter("@Age", 30)
};
await sqliteHelper.ExecuteNonQueryAsync(commandText, parameters);
string queryText = "SELECT * FROM Users WHERE Age > @Age";
parameters = new SQLiteParameter[] {
new SQLiteParameter("@Age", 25)
};
DataTable result = await sqliteHelper.ExecuteQueryAsync(queryText, parameters);
bool isVerified = await sqliteHelper.VerifyUserAsync("user@example.com", "password");This setup allows you to easily interact with a SQLite database, performing CRUD operations and logging activities using the LoggerProvider.
The BehaviorFactory class provides methods to create instances of Behavior types with dependency injection support using MEF (Managed Extensibility Framework). This class is particularly useful for scenarios where behaviors require constructor parameters or dependency injection.
CreateBehavior<T>(params object[] constructorArgs) where T : Behavior: Creates an instance of aBehaviorwith the specified constructor arguments.CreateBehavior(Type type): General-purpose method to create an instance of anyBehaviortype.Initialize(CompositionContainer compositionContainer): Initializes theBehaviorFactorywith aCompositionContainerfor dependency injection.
EnsureInitialized(): Ensures that the factory has been initialized before use.SatisfyImports(Behavior instance): Performs MEF composition on the instance to inject dependencies.ValidateInstance(Behavior instance, Type type): Validates that an instance was created successfully.
To use the BehaviorFactory class, follow these steps:
-
Initialize the
BehaviorFactorywith aCompositionContainer:var catalog = new AggregateCatalog(); // Add parts to the catalog here var container = new CompositionContainer(catalog); BehaviorFactory.Initialize(container);
-
Create an instance of a
Behaviorwith constructor arguments:var behavior = BehaviorFactory.CreateBehavior<MyBehavior>(arg1, arg2);
-
Create an instance of a
Behaviorwithout constructor arguments:var behavior = BehaviorFactory.CreateBehavior(typeof(MyBehavior));
Here's a complete example in context:
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using Microsoft.Xaml.Behaviors;
public class MyBehavior : Behavior<UIElement>
{
[Import]
public IService MyService { get; set; }
protected override void OnAttached()
{
base.OnAttached();
// Use MyService
}
}
// Setup MEF
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(MyBehavior).Assembly));
var container = new CompositionContainer(catalog);
BehaviorFactory.Initialize(container);
// Create an instance of MyBehavior
var behavior = BehaviorFactory.CreateBehavior<MyBehavior>();This setup allows you to create and use behaviors with dependency injection using MEF.
The ViewModelFactory class provides methods to create instances of ViewModel types with dependency injection support using MEF (Managed Extensibility Framework). This class is particularly useful for scenarios where ViewModels require constructor parameters or dependency injection.
CreateViewModel<T>() where T : new(): Creates an instance of a ViewModel of typeTwith a parameterless constructor and satisfies its dependencies using MEF.CreateViewModel<T>(params object[] constructorArgs) where T : class: Creates an instance of a ViewModel of typeTwith the specified constructor arguments and satisfies its dependencies using MEF.CreateViewModel(Type type): Creates an instance of a specified type and satisfies its dependencies using MEF.Initialize(CompositionContainer compositionContainer): Initializes theViewModelFactorywith aCompositionContainerfor dependency injection.
EnsureInitialized(): Ensures that the factory has been initialized before use.SatisfyImports(object instance): Performs MEF composition on the instance to inject dependencies.ValidateInstance(object instance, Type type): Validates that an instance was created successfully.
To use the ViewModelFactory class, follow these steps:
-
Initialize the
ViewModelFactorywith aCompositionContainer:var catalog = new AggregateCatalog(); // Add parts to the catalog here var container = new CompositionContainer(catalog); ViewModelFactory.Initialize(container);
-
Create an instance of a ViewModel with a parameterless constructor:
var viewModel = ViewModelFactory.CreateViewModel<MyViewModel>();
-
Create an instance of a ViewModel with constructor arguments:
var viewModel = ViewModelFactory.CreateViewModel<MyViewModel>(arg1, arg2);
-
Create an instance of a specified type:
var viewModel = ViewModelFactory.CreateViewModel(typeof(MyViewModel));
Here's a complete example in context:
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using Microsoft.Extensions.Logging;
public class MyViewModel
{
[Import]
public IService MyService { get; set; }
public MyViewModel()
{
// Default constructor
}
public MyViewModel(IService service)
{
MyService = service;
}
}
// Setup MEF
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(MyViewModel).Assembly));
var container = new CompositionContainer(catalog);
ViewModelFactory.Initialize(container);
// Create an instance of MyViewModel with a parameterless constructor
var viewModel1 = ViewModelFactory.CreateViewModel<MyViewModel>();
// Create an instance of MyViewModel with constructor arguments
var viewModel2 = ViewModelFactory.CreateViewModel<MyViewModel>(new ServiceImplementation());
// Create an instance of a specified type
var viewModel3 = ViewModelFactory.CreateViewModel(typeof(MyViewModel));This setup allows you to create and use ViewModels with dependency injection using MEF.
The CursorHelper class provides utility methods for creating custom cursors in WPF applications. It includes methods to create cursors from strings and UI elements, allowing for more interactive and visually appealing drag-and-drop operations.
CreateStringCursor(string cursorText, double pixelPerDip): Creates a cursor containing a given string.CreateUIElementCursor(UIElement element): Creates a cursor containing an image that represents the given UI element.
To use the CursorHelper class, follow these steps:
-
Create a cursor from a string:
double dpi = VisualTreeHelper.GetDpi(this).PixelsPerDip; Cursor stringCursor = CursorHelper.CreateStringCursor("Drag Me", dpi);
-
Create a cursor from a UI element:
UIElement element = myUIElement; Cursor elementCursor = CursorHelper.CreateUIElementCursor(element);
Here's a complete example in context:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
double dpi = VisualTreeHelper.GetDpi(this).PixelsPerDip;
// Create a cursor from a string
Cursor stringCursor = CursorHelper.CreateStringCursor("Drag Me", dpi);
// Create a cursor from a UI element
Button button = new Button { Content = "Drag Me" };
Cursor elementCursor = CursorHelper.CreateUIElementCursor(button);
// Set the cursor to the window (for demonstration purposes)
this.Cursor = stringCursor;
// Alternatively, set the cursor to an element
myUIElement.Cursor = elementCursor;
}
}This setup allows you to create and use custom cursors in your WPF applications, enhancing the user experience for drag-and-drop operations.
##Locators
The ContainerLocator class provides a static locator service for resolving dependencies via MEF (Managed Extensibility Framework). This class is designed to compose parts and retrieve exported values, enabling efficient dependency injection and service location.
ComposeParts(object obj): Composes the parts of a particular object.GetExportedValue<T>(string contractName = ""): Retrieves the exported value of the specified typeT.GetExportedValues<T>(string contractName = ""): Retrieves the exported values of the specified typeT.Initialize(CompositionContainer container): Initializes the composition container.
To use the ContainerLocator class, follow these steps:
-
Initialize the
ContainerLocatorwith aCompositionContainer:var catalog = new AggregateCatalog(); // Add parts to the catalog here var container = new CompositionContainer(catalog); ContainerLocator.Initialize(container);
-
Compose the parts of an object:
var myObject = new MyObject(); ContainerLocator.ComposeParts(myObject);
-
Retrieve an exported value:
var myService = ContainerLocator.GetExportedValue<IMyService>();
-
Retrieve exported values:
var services = ContainerLocator.GetExportedValues<IMyService>();
Here's a complete example in context:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
public interface IMyService
{
void DoWork();
}
[Export(typeof(IMyService))]
public class MyService : IMyService
{
public void DoWork()
{
Console.WriteLine("Work done!");
}
}
public class MyObject
{
[Import]
public IMyService MyService { get; set; }
public void UseService()
{
MyService.DoWork();
}
}
class Program
{
static void Main(string[] args)
{
// Setup MEF
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(MyService).Assembly));
var container = new CompositionContainer(catalog);
ContainerLocator.Initialize(container);
// Compose parts
var myObject = new MyObject();
ContainerLocator.ComposeParts(myObject);
// Use the service
myObject.UseService();
// Retrieve an exported value
var myService = ContainerLocator.GetExportedValue<IMyService>();
myService.DoWork();
// Retrieve exported values
var services = ContainerLocator.GetExportedValues<IMyService>();
foreach (var service in services)
{
service.DoWork();
}
}
}This setup allows you to efficiently resolve dependencies and compose parts using MEF, providing a flexible and powerful mechanism for dependency injection in your applications.
##Loggers
The LoggerProvider class provides a static logging service using the ColorConsoleLoggerProvider. This class is designed to log messages with different log levels, leveraging the Microsoft.Extensions.Logging framework.
Log(string message, LogLevel logLevel = LogLevel.Information): Logs a message with the specified log level.
To use the LoggerProvider class, follow these steps:
-
Log a message with the default log level (Information):
LoggerProvider.Log("This is an informational message.");
-
Log a message with a specific log level:
LoggerProvider.Log("This is an error message.", LogLevel.Error);
Here's a complete example in context:
using Microsoft.Extensions.Logging;
public class Program
{
static void Main(string[] args)
{
// Log an informational message
LoggerProvider.Log("Application has started.");
// Log an error message
LoggerProvider.Log("An error occurred.", LogLevel.Error);
// Log a debug message
LoggerProvider.Log("Debugging application.", LogLevel.Debug);
}
}This setup allows you to log messages with different log levels using the LoggerProvider class, providing a consistent and centralized logging mechanism for your applications.
The ColorConsoleLogger class provides color-coded logging to the console or debug window, leveraging the Microsoft.Extensions.Logging framework. This logger is designed to enhance log readability by using different colors for different log levels.
ColorConsoleLogger(string name, Func<ColorConsoleLoggerConfiguration> getCurrentConfig, LoggerOutputTarget outputTarget = LoggerOutputTarget.DebugWindow): Initializes a new instance of theColorConsoleLoggerclass.BeginScope<TState>(TState state): This method is not supported inColorConsoleLogger.IsEnabled(LogLevel logLevel): Checks if the specified log level is enabled.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter): Logs a message with the specified log level.
SetConsoleColor(ConsoleColor color): Sets the console color.GetCurrentConfig(): Retrieves the current logger configuration.WriteLog<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter, ColorConsoleLoggerConfiguration config): Writes the log message to the console or debug window.
To use the ColorConsoleLogger class, follow these steps:
-
Configure the logger in your application:
public class Program { public static void Main(string[] args) { var logger = new ColorConsoleLogger("MyLogger", () => new ColorConsoleLoggerConfiguration()); logger.Log(LogLevel.Information, new EventId(1, "AppStart"), "Application has started.", null, (state, exception) => state); } }
-
Log messages with different log levels:
var logger = new ColorConsoleLogger("MyLogger", () => new ColorConsoleLoggerConfiguration()); // Log an informational message logger.Log(LogLevel.Information, new EventId(1, "InfoEvent"), "This is an informational message.", null, (state, exception) => state); // Log an error message logger.Log(LogLevel.Error, new EventId(2, "ErrorEvent"), "This is an error message.", null, (state, exception) => state); // Log a debug message logger.Log(LogLevel.Debug, new EventId(3, "DebugEvent"), "This is a debug message.", null, (state, exception) => state);
Here's a complete example in context:
using System;
using Microsoft.Extensions.Logging;
public class Program
{
public static void Main(string[] args)
{
// Configure logger
var logger = new ColorConsoleLogger("MyLogger", () => new ColorConsoleLoggerConfiguration
{
LogLevelToColorMap = new Dictionary<LogLevel, ConsoleColor>
{
[LogLevel.Trace] = ConsoleColor.Gray,
[LogLevel.Debug] = ConsoleColor.Blue,
[LogLevel.Information] = ConsoleColor.Green,
[LogLevel.Warning] = ConsoleColor.Yellow,
[LogLevel.Error] = ConsoleColor.Red,
[LogLevel.Critical] = ConsoleColor.Magenta
}
});
// Log messages
logger.Log(LogLevel.Information, new EventId(1, "InfoEvent"), "This is an informational message.", null, (state, exception) => state);
logger.Log(LogLevel.Error, new EventId(2, "ErrorEvent"), "This is an error message.", null, (state, exception) => state);
logger.Log(LogLevel.Debug, new EventId(3, "DebugEvent"), "This is a debug message.", null, (state, exception) => state);
}
}
public class ColorConsoleLoggerConfiguration
{
public Dictionary<LogLevel, ConsoleColor> LogLevelToColorMap { get; set; } = new();
}This setup allows you to log messages with different log levels using the ColorConsoleLogger class, providing a color-coded output to enhance log readability.
The DatabaseLoggers namespace contains classes for logging to various types of databases using the Microsoft.Extensions.Logging framework. This setup allows for centralized logging to SQL Server, SQLite, or MongoDB databases.
DbLoggerBase: Abstract base class for database loggers.DbLoggerProvider: Provides instances ofDbLoggerBasebased on configuration.MongoDbLogger: MongoDB-specific logger implementation.SqliteLogger: SQLite-specific logger implementation.SqlServerLogger: SQL Server-specific logger implementation.DbLoggerConfiguration: Base configuration class for database loggers.
The DbLoggerBase class is an abstract base class for implementing database loggers.
Constructor:
DbLoggerBase(string connectionString, string logTable, LogLevel minLogLevel): Initializes a new instance of theDbLoggerBaseclass.
Methods:
BeginScope<TState>(TState state): Not supported, returnsnull.IsEnabled(LogLevel logLevel): Checks if the specified log level is enabled.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter): Logs the specified log level, event ID, state, exception, and formatter to the database.LogToDatabase(LogLevel logLevel, string message, Exception exception): Abstract method to log the message to the database.
The DbLoggerProvider class provides instances of DbLoggerBase based on the provided configuration.
Constructor:
DbLoggerProvider(DbLoggerConfiguration config): Initializes a new instance of theDbLoggerProviderclass.
Methods:
CreateLogger(string categoryName): Creates a new logger instance of the specified category.Dispose(): Disposes the logger provider and releases resources.CreateLoggerInstance(): Creates a logger instance based on the current configuration.
The MongoDbLogger class is a MongoDB-specific logger implementation.
Constructor:
MongoDbLogger(string connectionString, string logCollection, LogLevel minLogLevel): Initializes a new instance of theMongoDbLoggerclass.
Methods:
LogToDatabase(LogLevel logLevel, string message, Exception exception): Logs the message to the MongoDB database.
The SqliteLogger class is a SQLite-specific logger implementation.
Constructor:
SqliteLogger(string connectionString, string logTable, LogLevel minLogLevel): Initializes a new instance of theSqliteLoggerclass.
Methods:
LogToDatabase(LogLevel logLevel, string message, Exception exception): Logs the message to the SQLite database.
The SqlServerLogger class is a SQL Server-specific logger implementation.
Constructor:
SqlServerLogger(string connectionString, string logTable, LogLevel minLogLevel): Initializes a new instance of theSqlServerLoggerclass.
Methods:
LogToDatabase(LogLevel logLevel, string message, Exception exception): Logs the message to the SQL Server database.
The DbLoggerConfiguration class provides the configuration for database loggers.
Properties:
string ConnectionString { get; set; }: Gets or sets the connection string for the database.string DatabaseType { get; set; }: Gets or sets the database type (e.g., "SqlServer", "MongoDb", "Sqlite").string LogTable { get; set; }: Gets or sets the table or collection name for storing logs.LogLevel MinLogLevel { get; set; }: Gets or sets the minimum log level to log (default is Information).
var config = new DbLoggerConfiguration
{
ConnectionString = "your-connection-string",
DatabaseType = "SqlServer",
LogTable = "Logs",
MinLogLevel = LogLevel.Information
};
using var loggerProvider = new DbLoggerProvider(config);
var logger = loggerProvider.CreateLogger("MyLogger");
logger.LogInformation("This is an informational message.");
logger.LogError("This is an error message.");The StorageLocationManager class provides utility methods for managing storage locations on a Windows machine. It includes methods to create directories in various special folders, such as AppData, CommonApplicationData, and LocalApplicationData, as well as custom and temporary directories.
CreateAppDataDirectory(string appName): Creates a directory for the application in theAppDatafolder.CreateCommonAppDataDirectory(string appName): Creates a directory for the application in theCommonApplicationDatafolder.CreateCustomDirectory(string customPath, string appName): Creates a directory for the application in a custom folder.CreateLocalAppDataDirectory(string appName): Creates a directory for the application in theLocalApplicationDatafolder.CreateTempDirectory(string appName): Creates a directory for the application in the system's temporary folder.
To use the StorageLocationManager class, follow these steps:
-
Create a directory in the
AppDatafolder:string appDataDirectory = StorageLocationManager.CreateAppDataDirectory("MyApp");
-
Create a directory in the
CommonApplicationDatafolder:string commonAppDataDirectory = StorageLocationManager.CreateCommonAppDataDirectory("MyApp");
-
Create a directory in a custom folder:
string customDirectory = StorageLocationManager.CreateCustomDirectory("C:\\CustomPath", "MyApp");
-
Create a directory in the
LocalApplicationDatafolder:string localAppDataDirectory = StorageLocationManager.CreateLocalAppDataDirectory("MyApp");
-
Create a directory in the system's temporary folder:
string tempDirectory = StorageLocationManager.CreateTempDirectory("MyApp");
Here's a complete example in context:
using System;
using CodingDad.Common.Storage;
public class Program
{
public static void Main(string[] args)
{
// Create directories
string appDataDirectory = StorageLocationManager.CreateAppDataDirectory("MyApp");
Console.WriteLine($"AppData Directory: {appDataDirectory}");
string commonAppDataDirectory = StorageLocationManager.CreateCommonAppDataDirectory("MyApp");
Console.WriteLine($"CommonAppData Directory: {commonAppDataDirectory}");
string customDirectory = StorageLocationManager.CreateCustomDirectory("C:\\CustomPath", "MyApp");
Console.WriteLine($"Custom Directory: {customDirectory}");
string localAppDataDirectory = StorageLocationManager.CreateLocalAppDataDirectory("MyApp");
Console.WriteLine($"LocalAppData Directory: {localAppDataDirectory}");
string tempDirectory = StorageLocationManager.CreateTempDirectory("MyApp");
Console.WriteLine($"Temp Directory: {tempDirectory}");
}
}This setup allows you to manage storage locations for your application efficiently, providing methods to create directories in various special folders on a Windows machine.
This section provides an overview of the components used for handling user creation and login functionalities in the CodingDad.Common namespace. These components work together to provide a full implementation for user management in your application.
The UserModel class represents a user with properties for email, ID, and username.
- Properties:
Email: The user's email address.Id: The user's unique identifier.Username: The user's username.
The UserIdentifier class provides functionality to uniquely identify a user based on certain system attributes.
-
Constructor:
UserIdentifier(NetworkInterface[] nics): Initializes a new instance of theUserIdentifierclass with an array ofNetworkInterfaceobjects.
-
Methods:
string GetUniqueIdentifier(): Generates a unique identifier for the user based on system attributes.
The UserViewModel class provides a view model for handling user creation and login functionalities. It utilizes the LoggerProvider for logging various operations.
-
Constructor:
UserViewModel(IDatabaseHelper databaseManager, string email, string username): Initializes a new instance of theUserViewModelclass.
-
Properties:
Email: The user's email address.Username: The user's username.CreateUserCommand: Command for creating a new user.GoToCreateUserCommand: Command for navigating to the create user view.LoginCommand: Command for logging in a user.
-
Methods:
int GenerateUniqueId(): Generates a unique ID for the user.bool IsUserLoggedIn(): Checks if the user is logged in.void CreateUser(string password): Creates a new user.void GoToCreateUser(): Navigates to the create user view.void ValidateUserLogin(string password): Validates the user login.
The UserCreateView user control provides the UI for creating a new user.
- Components:
TextBox: For entering the new username.TextBox: For entering the new email.PasswordBox: For entering the password.Button: For submitting the create user command.
The UserLoginView user control provides the UI for logging in a user.
- Components:
TextBox: For entering the username.PasswordBox: For entering the password.Button: For submitting the login command.Button: For navigating to the create user view.
To integrate the user creation and login functionality into your application, follow these steps:
- ViewModel Initialization:
var databaseManager = new YourDatabaseHelperImplementation();
var userViewModel = new UserViewModel(databaseManager, "initialEmail@example.com", "initialUsername");- Bind ViewModel to Views:
<!-- UserCreateView.xaml -->
<UserControl
x:Class="CodingDad.NET.Common.UserCreationLogin.Views.UserCreateView"
DataContext="{Binding UserViewModelInstance}"
...>
...
</UserControl>
<!-- UserLoginView.xaml -->
<UserControl
x:Class="CodingDad.NET.Common.UserCreationLogin.Views.UserLoginView"
DataContext="{Binding UserViewModelInstance}"
...>
...
</UserControl>- Configure Commands and Logging:
Ensure that the LoggerProvider is correctly set up to log user creation and login operations.
By following these steps, you can utilize the user creation and login functionalities provided by the CodingDad.Common namespace in your application, ensuring a consistent and efficient user management experience.
The MefJsonUtility class is a utility for serializing and deserializing objects while also managing MEF (Managed Extensibility Framework) imports. It ensures that deserialized objects have their MEF dependencies satisfied, making it useful for applications that rely on dependency injection and modular components.
DeserializeAndSatisfyImports<T>(string json) where T : class: Deserializes a JSON string to an object of typeTand satisfies its MEF imports.Initialize(CompositionContainer container): Initializes theMefJsonUtilitywith aCompositionContainer.Serialize<T>(T obj): Serializes an object of typeTto a JSON string.
To use the MefJsonUtility class, follow these steps:
-
Initialize the utility with a
CompositionContainer:var catalog = new AggregateCatalog(); // Add parts to the catalog here var container = new CompositionContainer(catalog); MefJsonUtility.Initialize(container);
-
Serialize an object to a JSON string:
var myObject = new MyClass { Property1 = "value1", Property2 = "value2" }; string jsonString = MefJsonUtility.Serialize(myObject);
-
Deserialize a JSON string to an object and satisfy MEF imports:
string jsonString = "{ \"Property1\": \"value1\", \"Property2\": \"value2\" }"; var myObject = MefJsonUtility.DeserializeAndSatisfyImports<MyClass>(jsonString);
Here's a complete example in context:
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Text.Json;
public class MyClass
{
public string Property1 { get; set; }
public string Property2 { get; set; }
[Import]
public IMyService MyService { get; set; }
}
public interface IMyService
{
void DoWork();
}
[Export(typeof(IMyService))]
public class MyService : IMyService
{
public void DoWork()
{
Console.WriteLine("Work done!");
}
}
public class Program
{
public static void Main(string[] args)
{
// Setup MEF
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(MyService).Assembly));
var container = new CompositionContainer(catalog);
MefJsonUtility.Initialize(container);
// Create and serialize an object
var myObject = new MyClass { Property1 = "value1", Property2 = "value2" };
string jsonString = MefJsonUtility.Serialize(myObject);
// Deserialize the object and satisfy MEF imports
var deserializedObject = MefJsonUtility.DeserializeAndSatisfyImports<MyClass>(jsonString);
// Use the imported service
deserializedObject.MyService.DoWork();
}
}This setup ensures that serialized objects can be deserialized with all their MEF dependencies correctly satisfied, maintaining the integrity of the dependency injection pattern.
The BaseViewModel class serves as a base class for view models in a MVVM (Model-View-ViewModel) architecture. It provides essential functionality for property change notification and resource management.
- Id: A unique identifier for the view model instance.
- IsDirty: A flag indicating whether the view model has unsaved changes.
- Dispose(): Releases all resources used by the view model.
- Dispose(bool disposing): Releases unmanaged resources and optionally releases managed resources.
- OnPropertyChanged(string? propertyName = null): Raises the
PropertyChangedevent to notify the UI of property changes. - SetProperty(ref T storage, T value, string? propertyName = null): Sets a property and raises the
PropertyChangedevent only if the new value is different from the old value.
To create a view model that inherits from BaseViewModel, define your properties and use the SetProperty method to update their values and notify listeners of changes:
public class MyViewModel : BaseViewModel
{
private string _name;
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
}In this example, MyViewModel inherits from BaseViewModel and uses the SetProperty method to manage the Name property, ensuring that property change notifications are sent to the UI.