SGU.Tools_CronExpressionBuilder
1.1.4
dotnet add package SGU.Tools_CronExpressionBuilder --version 1.1.4
NuGet\Install-Package SGU.Tools_CronExpressionBuilder -Version 1.1.4
<PackageReference Include="SGU.Tools_CronExpressionBuilder" Version="1.1.4" />
<PackageVersion Include="SGU.Tools_CronExpressionBuilder" Version="1.1.4" />
<PackageReference Include="SGU.Tools_CronExpressionBuilder" />
paket add SGU.Tools_CronExpressionBuilder --version 1.1.4
#r "nuget: SGU.Tools_CronExpressionBuilder, 1.1.4"
#:package SGU.Tools_CronExpressionBuilder@1.1.4
#addin nuget:?package=SGU.Tools_CronExpressionBuilder&version=1.1.4
#tool nuget:?package=SGU.Tools_CronExpressionBuilder&version=1.1.4
SGU.Tools_CronExpressionBuilder
A comprehensive WinForms control for visually building and editing Quartz and Hangfire CRON expressions with an intuitive tabbed interface.
🎯 Live Demo Application
Want to see all features in action? The package includes a Demo Application in the source code!
Features in Demo
- ✅ Interactive testing of all tab options
- ✅ Quick test expressions (Every second, Daily at 9 AM, Weekdays, etc.)
- ✅ Parse and edit existing expressions
- ✅ Format selector to switch between Quartz/Hangfire
- ✅ Expression validation and testing
- ✅ Copy to clipboard functionality
- ✅ Field-by-field breakdown display
Perfect for: Evaluating the control before integrating it into your project!
Demo Project - GitHub(https://github.com/Solutions-Group-Unlimited/SGU_Tools_CronExpressionBuilder)
-
Features
Visual CRON Expression Builder
- Intuitive Tabbed Interface: Separate tabs for Seconds, Minutes, Hours, Days, Months, and Years
- No CRON Syntax Knowledge Required: Build complex schedules using radio buttons, checkboxes, and dropdowns
- Real-Time Preview: See the CRON expression and human-readable description update as you build
- Bidirectional Editing: Parse existing CRON expressions and edit them visually
Multiple Format Support
- Quartz 7-Position:
Second Minute Hour Day Month DayOfWeek Year - Quartz 6-Position:
Second Minute Hour Day Month DayOfWeek - Hangfire 5-Position:
Minute Hour Day Month DayOfWeek
Advanced Scheduling Options
- Intervals: Every N seconds/minutes/hours/days/months/years
- Ranges: Between specific values (e.g., 9 AM - 5 PM)
- Specific Values: Select multiple specific values
- Day Patterns:
- Last day of month
- Last weekday
- Nearest weekday to a specific day
- Nth occurrence of a day (e.g., 2nd Tuesday)
- Days before end of month
Expression Parsing
- Parse Existing Expressions: Paste any CRON expression and click "Parse" to populate all tabs
- Format Auto-Detection: Automatically detects Quartz 7, Quartz 6, or Hangfire 5 formats
- Validation & Error Handling: Clear error messages for invalid expressions
Installation
Install via NuGet Package Manager Console:
Install-Package SGU.Tools_CronExpressionBuilder
Or via .NET CLI:
dotnet add package SGU.Tools_CronExpressionBuilder
Or search for SGU.Tools_CronExpressionBuilder in the NuGet Package Manager UI.
Quick Start
Option 1: Add from Toolbox (Drag & Drop)
After installing the NuGet package and rebuilding your project:
- Open the Toolbox in Visual Studio (View → Toolbox or
Ctrl+Alt+X) - Find "SGU Tools" category or search for "Cron Expression Builder"
- Drag and drop the
CronExpressionControlonto your Form - Resize to desired size (recommended minimum: 760 x 540)
- Subscribe to events in the Properties window or code-behind
The control will appear in the Toolbox under the "SGU Tools" category with the display name "Cron Expression Builder".
Option 2: Add Programmatically
using SGU.Tools;
public partial class MyForm : Form
{
private CronExpressionControl cronControl;
public MyForm()
{
InitializeComponent();
// Create the control
cronControl = new CronExpressionControl
{
Dock = DockStyle.Fill
};
// Add to your form
this.Controls.Add(cronControl);
// Subscribe to events
cronControl.ExpressionChanged += CronControl_ExpressionChanged;
}
private void CronControl_ExpressionChanged(object sender, EventArgs e)
{
string expression = cronControl.ExpressionString;
string description = cronControl.Description;
Console.WriteLine($"Expression: {expression}");
Console.WriteLine($"Description: {description}");
}
}
Option 3: Add via Designer
- Open your Form in the Designer
- Click on your Form or container control
- In the Designer, click to add from Toolbox or use Add → UserControl
- Select
CronExpressionControlfrom the dialog - Configure properties in the Properties Window
Design-Time Support
Properties Window Configuration
When you select the control in the Designer, the following properties are available in the Properties Window:
CRON Expression Category
- ExpressionString - Set the initial CRON expression
- Example:
"0 0 9 ? * MON-FRI *" - Supports multi-line editor for easy editing
- Example:
- Format - Choose the CRON format
- Options:
Quartz7,Quartz6,Hangfire5 - Default:
Quartz7
- Options:
- Description (read-only) - View the human-readable description
Appearance Category
- ShowFormatSelector - Show/hide the Format selector dropdown (Would allow users to change format at runtime)
- Type:
Boolean - Default:
false - When
false, control uses theFormatproperty value without displaying the dropdown
- Type:
- ShowDescription - Show/hide the human-readable description text area
- Type:
Boolean - Default:
true - When
false, hides the description textbox and label - Useful for when using a custom description display
- Type:
Behavior
- Enabled - Enable/disable the control
- Visible - Show/hide the control
Layout
- Dock - Dock the control to edges
- Recommended:
FillorNone
- Recommended:
- Size - Set control size
- Location - Position on form
Design
- BackColor - Background color
- ForeColor - Text color
Events in Designer
Double-click the control or use the Events tab (⚡) in Properties to add event handlers:
- ExpressionChanged - Fires when the CRON expression changes
- FormatChanged - Fires when the format is changed
// Auto-generated event handler
private void cronExpressionControl1_ExpressionChanged(object sender, EventArgs e)
{
// Access the control's properties
string expr = cronExpressionControl1.ExpressionString;
string desc = cronExpressionControl1.Description;
// Update your UI
lblCurrentExpression.Text = expr;
txtDescription.Text = desc;
}
Usage Examples
Building a CRON Expression Visually
Users interact with the tabbed interface to build their schedule:
- Seconds Tab: Choose "Every second", "Every N seconds", specific seconds, or a range
- Minutes Tab: Choose "Every minute", "Every 15 minutes", specific minutes, etc.
- Hours Tab: Choose "Every hour", "9 AM - 5 PM", specific hours, etc.
- Day Tab: Choose "Every day", "Weekdays only", "Last Friday", "2nd Monday", etc.
- Month Tab: Choose "Every month", specific months, "Every 3 months", etc.
- Year Tab: Choose "Any year", specific years, or a range
The expression and description update in real-time as selections are made.
Get the CRON Expression
// Get as string
string cronExpression = cronControl.ExpressionString;
// Example: "0 0 9 ? * MON-FRI *"
// Get as object
CronExpression expression = cronControl.Expression;
Console.WriteLine($"Format: {expression.Format}");
Console.WriteLine($"Second: {expression.Second}");
Console.WriteLine($"Minute: {expression.Minute}");
// ... access all fields
// Get description
string description = cronControl.Description;
// Example: "at second 0, at minute 0, at hour 9 AM, every day of the week between Monday and Friday, every month, every year"
Set/Parse a CRON Expression
// Set expression - automatically parses and populates all tabs
cronControl.ExpressionString = "0 */15 9-17 ? * MON-FRI *";
// The control will:
// 1. Detect format (Quartz 7-position)
// 2. Parse the expression
// 3. Populate Seconds tab: "at second 0"
// 4. Populate Minutes tab: "every 15 minutes"
// 5. Populate Hours tab: "9 AM - 5 PM"
// 6. Populate Day tab: "Monday-Friday"
// 7. Populate Month tab: "every month"
// 8. Populate Year tab: "every year"
// User can now edit visually using the tabs!
Change Format
// Switch between formats
cronControl.Format = CronExpressionFormat.Quartz7; // 7 fields
cronControl.Format = CronExpressionFormat.Quartz6; // 6 fields (no year, every year is implied)
cronControl.Format = CronExpressionFormat.Hangfire5; // 5 fields (no seconds)
// Subscribe to format changes
cronControl.FormatChanged += (s, e) =>
{
Console.WriteLine($"Format changed to: {cronControl.Format}");
};
// Show format selector to let users change format at runtime
cronControl.ShowFormatSelector = true;
// Hide format selector and use programmatic control only
cronControl.ShowFormatSelector = false;
cronControl.Format = CronExpressionFormat.Quartz7;
Programmatic Expression Building
// Build expression programmatically
var builder = new CronExpressionBuilder(CronExpressionFormat.Quartz7)
.WithSecond("0") // At second 0
.WithMinute("*/5") // Every 5 minutes
.WithHour("9-17") // Between 9 AM and 5 PM
.WithDayOfMonth("?") // Any day of month
.WithMonth("*") // Every month
.WithDayOfWeek("MON-FRI") // Monday through Friday
.WithYear("*"); // Every year
CronExpression expression = builder.Build();
cronControl.Expression = expression;
Use Presets
// Common schedules as presets
cronControl.Expression = CronExpressionBuilder.Presets.EverySecond();
cronControl.Expression = CronExpressionBuilder.Presets.EveryMinute();
cronControl.Expression = CronExpressionBuilder.Presets.EveryHour();
cronControl.Expression = CronExpressionBuilder.Presets.Daily(hour: 9, minute: 0);
cronControl.Expression = CronExpressionBuilder.Presets.Weekly(DayOfWeek.Monday, hour: 9);
cronControl.Expression = CronExpressionBuilder.Presets.Monthly(dayOfMonth: 1, hour: 9);
cronControl.Expression = CronExpressionBuilder.Presets.Yearly(month: 1, dayOfMonth: 1, hour: 9);
Parse Button Workflow
// User types or pastes a CRON expression into the text box
// Then clicks the "Parse" button
// The control automatically:
// 1. Validates the expression
// 2. Detects the format
// 3. Parses all fields
// 4. Populates all tabs with the correct selections
// 5. Shows success or error message
// You can also trigger parsing programmatically
try
{
cronControl.ExpressionString = "0 0 12 1 * ?";
// Tabs are now populated and user can edit visually
}
catch (ArgumentException ex)
{
MessageBox.Show($"Invalid expression: {ex.Message}");
}
Supported CRON Patterns
Time Components
*- Every second/minute/hour*/N- Every N seconds/minutes/hoursN- Specific valueN,M,O- Multiple specific valuesN-M- Range of valuesN/M- Every M starting at N
Day of Month
*- Every day?- No specific valueN- Specific dayN,M- Specific daysN-M- Range of daysL- Last day of monthLW- Last weekday of monthL-N- N days before end of monthNW- Nearest weekday to day NN/M- Every M days starting on day N
Day of Week
*- Every day of week?- No specific valueNorDAY- Specific day (1=SUN, 2=MON, etc.)N,MorMON,WED,FRI- Specific daysN-MorMON-FRI- Range of daysNL- Last occurrence of day NN#M- Mth occurrence of day N (e.g.,2#2= 2nd Monday)N/M- Every M days of week starting on day N
Month
*- Every monthNorMON- Specific monthN,MorJAN,MAR,DEC- Specific monthsN-MorJAN-JUN- Range of monthsN/M- Every M months starting at month N
Year (Quartz 7-position only)
*- Every yearYYYY- Specific yearYYYY,YYYY- Specific yearsYYYY-YYYY- Range of yearsYYYY/N- Every N years starting at YYYY
Real-World Examples
Every Weekday at 9 AM
Visual Selection:
- Seconds: "At second 0"
- Minutes: "At minute 0"
- Hours: "At hour 9"
- Day: Select "Monday, Tuesday, Wednesday, Thursday, Friday"
- Month: "Every month"
- Year: "Every year"
Result: 0 0 9 ? * MON-FRI *
Description: "at second 0, at minute 0, at hour 9 AM, every day of the week between Monday and Friday, every month, every year"
Every 15 Minutes During Business Hours
Visual Selection:
- Seconds: "At second 0"
- Minutes: "Every 15 minute(s)"
- Hours: "Between hour 9 and hour 17"
- Day: "Every day"
- Month: "Every month"
- Year: "Every year"
Result: 0 */15 9-17 ? * * *
Description: "at second 0, every 15 minutes, every hour between 9 AM and 5 PM, every day, every month, every year"
First Monday of Every Month at Noon
Visual Selection:
- Seconds: "At second 0"
- Minutes: "At minute 0"
- Hours: "At hour 12 (noon)"
- Day: "On the 1st Monday of the month"
- Month: "Every month"
- Year: "Every year"
Result: 0 0 12 ? * MON#1 *
Description: "at second 0, at minute 0, at hour noon, on the first Monday of the month, every month, every year"
Last Day of Every Quarter
Visual Selection:
- Seconds: "At second 0"
- Minutes: "At minute 0"
- Hours: "At hour 0 (midnight)"
- Day: "On the last day of the month"
- Month: Select "MAR, JUN, SEP, DEC"
- Year: "Every year"
Result: 0 0 0 L * ? * (for monthly) or 0 0 0 L MAR,JUN,SEP,DEC ? *
API Reference
CronExpressionControl
Properties
Expression- Gets/sets the current CRON expression objectExpressionString- Gets/sets the CRON expression as a stringDescription- Gets the human-readable descriptionDescriptionText- Gets/sets the displayed description textFormat- Gets/sets the CRON expression formatTranslator- Gets/sets the translator for descriptionsShowFormatSelector- Gets/sets whether the format selector dropdown is visible (default:false)ShowDescription- Gets/sets whether the description text area is visible (default:true)
Events
ExpressionChanged- Fired when the expression changesFormatChanged- Fired when the format changes
Methods
GetExpression()- Gets the current CRON expression as a stringSetExpression(string)- Sets the CRON expression from a string
CronExpression
public class CronExpression
{
public string Second { get; set; }
public string Minute { get; set; }
public string Hour { get; set; }
public string DayOfMonth { get; set; }
public string Month { get; set; }
public string DayOfWeek { get; set; }
public string Year { get; set; }
public CronExpressionFormat Format { get; set; }
public static CronExpression Parse(string expression, CronExpressionFormat format);
public bool IsValid();
public CronExpression Clone();
public override string ToString();
}
CronExpressionBuilder
public class CronExpressionBuilder
{
public CronExpressionBuilder(CronExpressionFormat format);
public CronExpressionBuilder WithSecond(string second);
public CronExpressionBuilder WithMinute(string minute);
public CronExpressionBuilder WithHour(string hour);
public CronExpressionBuilder WithDayOfMonth(string dayOfMonth);
public CronExpressionBuilder WithMonth(string month);
public CronExpressionBuilder WithDayOfWeek(string dayOfWeek);
public CronExpressionBuilder WithYear(string year);
public CronExpression Build();
// Presets
public static class Presets
{
public static CronExpression EverySecond();
public static CronExpression EveryMinute();
public static CronExpression EveryHour();
public static CronExpression Daily(int hour = 0, int minute = 0);
public static CronExpression Weekly(DayOfWeek day, int hour = 0, int minute = 0);
public static CronExpression Monthly(int dayOfMonth = 1, int hour = 0, int minute = 0);
public static CronExpression Yearly(int month = 1, int dayOfMonth = 1, int hour = 0, int minute = 0);
}
}
Platform Support
- .NET Framework 4.8
- .NET 8.0 (Windows)
- .NET 10.0 (Windows)
- .NET 10.0 (Windows 10.0.26100.0)
Note: This is a WinForms control and requires Windows desktop applications.
Integration Examples
Save to Database
public void SaveSchedule()
{
var schedule = new ScheduleConfig
{
Name = txtScheduleName.Text,
CronExpression = cronControl.ExpressionString,
Description = cronControl.Description,
Format = cronControl.Format.ToString(),
IsActive = true,
CreatedDate = DateTime.UtcNow
};
database.Schedules.Add(schedule);
database.SaveChanges();
}
Load from Database
public void LoadSchedule(int scheduleId)
{
var schedule = database.Schedules.Find(scheduleId);
if (schedule != null)
{
txtScheduleName.Text = schedule.Name;
cronControl.ExpressionString = schedule.CronExpression;
// Tabs are automatically populated for visual editing
}
}
Use with Quartz.NET
using Quartz;
public void ScheduleJob()
{
// Get expression from control
string cronExpression = cronControl.ExpressionString;
// Create Quartz trigger
var trigger = TriggerBuilder.Create()
.WithIdentity("myTrigger", "group1")
.WithCronSchedule(cronExpression)
.Build();
// Schedule job
scheduler.ScheduleJob(myJob, trigger);
}
Use with Hangfire
using Hangfire;
public void ScheduleRecurringJob()
{
// Get expression from control (ensure Hangfire format)
cronControl.Format = CronExpressionFormat.Hangfire6;
string cronExpression = cronControl.ExpressionString;
// Schedule with Hangfire
RecurringJob.AddOrUpdate(
"myJob",
() => MyMethod(),
cronExpression);
}
Tips & Best Practices
Validation
// Always validate before using
if (cronControl.Expression.IsValid())
{
string expr = cronControl.ExpressionString;
// Use expression
}
else
{
MessageBox.Show("Invalid CRON expression");
}
Format Selection
// Match your scheduler's format
if (usingHangfire)
{
cronControl.Format = CronExpressionFormat.Hangfire5;
}
else if (usingQuartzWithYear)
{
cronControl.Format = CronExpressionFormat.Quartz7;
}
else
{
cronControl.Format = CronExpressionFormat.Quartz6;
}
User Experience
// Provide real-time feedback
cronControl.ExpressionChanged += (s, e) =>
{
lblExpression.Text = cronControl.ExpressionString;
lblDescription.Text = cronControl.Description;
// Show next 5 execution times
ShowNextExecutions(cronControl.ExpressionString);
};
Simplified UI (Recommended for Most Users)
// For a cleaner, simpler interface, hide advanced options
// This is the default configuration - no code needed!
// Format selector is hidden by default
// Control defaults to Quartz 7-position format
// Change format programmatically if needed:
cronControl.Format = CronExpressionFormat.Hangfire5;
// If you need to show the format selector:
cronControl.ShowFormatSelector = true; // Let users switch formats
// Hide description for compact layout:
cronControl.ShowDescription = false;
// Show/hide description dynamically:
chkShowDescription.CheckedChanged += (s, e) =>
{
cronControl.ShowDescription = chkShowDescription.Checked;
};
UI Customization
Control Visibility Options
The control provides two visibility properties to customize the UI based on your application's needs:
ShowDescription Property
Controls the visibility of the human-readable description text area.
Default: true (description visible)
When to Hide:
- Space-constrained UIs where vertical space is limited
- Applications with expert users who don't need visual confirmation
- Custom description displays elsewhere in your UI
- Embedded scenarios where the control is part of a larger form
When to Show (Default):
- New users who need to understand what their CRON expression means
- Training or educational scenarios
- Quick visual confirmation of expression meaning
- General use where space is not a concern
Example Usage:
// Hide description
cronControl.ShowDescription = false;
// Show description (default)
cronControl.ShowDescription = true;
// Toggle dynamically
btnToggleDescription.Click += (s, e) =>
{
cronControl.ShowDescription = !cronControl.ShowDescription;
btnToggleDescription.Text = cronControl.ShowDescription
? "Hide Description"
: "Show Description";
};
// Use description elsewhere when hidden
if (!cronControl.ShowDescription)
{
// Display in a separate label or tooltip
lblCustomDescription.Text = cronControl.Description;
toolTip1.SetToolTip(cronControl, cronControl.Description);
}
ShowFormatSelector Property
Controls the visibility of the format selector dropdown.
Default: false (dropdown hidden)
When to Hide (Default):
- Single format applications (e.g., only using Hangfire)
- Simplified UI for end users
- Format is controlled programmatically
- Prevent users from changing format accidentally
When to Show:
- Multi-scheduler applications (supporting both Quartz and Hangfire)
- Power users who need format flexibility
- Development/testing tools
Example Usage:
// Show format selector for flexibility
cronControl.ShowFormatSelector = true;
// Hide format selector and lock format
cronControl.ShowFormatSelector = false;
cronControl.Format = CronExpressionFormat.Hangfire5;
// Dynamic control based on user role
if (user.IsAdmin)
{
cronControl.ShowFormatSelector = true;
}
Combined Scenarios
// Scenario 1: Minimal UI (most compact)
cronControl.ShowFormatSelector = false;
cronControl.ShowDescription = false;
// Best for: Simple schedulers
// Scenario 2: Standard UI (default, recommended)
cronControl.ShowFormatSelector = false;
cronControl.ShowDescription = true;
// Best for: Most applications, good balance
// Scenario 3: Power User UI
cronControl.ShowFormatSelector = true;
cronControl.ShowDescription = true;
// Best for: Admin panels, development tools
// Scenario 4: Custom Description Display
cronControl.ShowDescription = false;
cronControl.ExpressionChanged += (s, e) =>
{
// Show in custom location
txtMyCustomDescription.Text = cronControl.Description;
// Or in a tooltip
toolTip1.SetToolTip(lblExpression, cronControl.Description);
};
// Best for: Custom layouts, specialized UIs
Layout Adjustment
// The control handles layout automatically
cronControl.ShowDescription = false;
cronControl.ShowDescription = true;
// Smooth transition with no flickering
this.SuspendLayout();
cronControl.ShowDescription = !cronControl.ShowDescription;
this.ResumeLayout();
📋 Issue Reporting & Support
If you encounter any bugs or have feature requests, please contact:
Solutions Group Unlimited, LLC
Email: support@solutionsgroupunlimited.com
Please include:
- Version of the package
- Target framework (.NET Framework 4.8, .NET 8, .NET 10)
- Steps to reproduce the issue
- Expected vs actual behavior
- Sample CRON expression (if applicable)
License
Licensed under the MIT License.
Author
Solutions Group Unlimited, LLC
Copyright © 2025 Solutions Group Unlimited, LLC. All rights reserved.
Changelog
Support
If you find this library helpful, consider supporting development:
| 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. net10.0-windows7.0 is compatible. net10.0-windows10.0.26100 is compatible. |
| .NET Framework | net48 is compatible. net481 was computed. |
-
.NETFramework 4.8
- No dependencies.
-
net10.0-windows10.0.26100
- No dependencies.
-
net10.0-windows7.0
- No dependencies.
-
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.
🚀 Visual CRON Expression Builder for WinForms
✨ Features:
• Intuitive tabbed interface (no CRON syntax knowledge required)
• Support for Quartz 7/6 and Hangfire 5 formats
• Parse existing CRON expressions
• Real-time description preview
• Advanced scheduling: Last day, Nth occurrence, nearest weekday, and more
📦 Installation:
Install-Package SGU.Tools_CronExpressionBuilder
📖 Documentation:
See the package README for complete documentation, API reference, and usage examples.
Demo application is included in the package for hands-on evaluation.
🆕 What's New in This Version:
• Renamed Demo project (formerly TestApp) for better clarity
• Comprehensive test suite with 414 tests covering all scenarios
• Fixed Hangfire vs Quartz day-of-week indexing (Monday=1 in Hangfire, Monday=2 in Quartz)
• Improved symbol package handling (symbols for internal builds only, not published to NuGet.org)
📧 Support:
For issues or questions, contact: support@solutionsgroupunlimited.com
📄 License: MIT
© 2025 Solutions Group Unlimited, LLC