diff --git a/CITATION.cff b/CITATION.cff
index 90b37c64..6ffa2109 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -2,8 +2,8 @@ cff-version: 1.2.0
message: "If you use this software, please cite it as below."
type: software
title: "WPF Framework"
-version: "1.0.2"
-date-released: "2026-07-10"
+version: "1.0.3"
+date-released: "2026-07-14"
license: 0BSD
repository-code: "https://github.com/USACE-RMC/WPF-Framework"
url: "https://github.com/USACE-RMC/WPF-Framework"
diff --git a/Directory.Build.props b/Directory.Build.props
index c1985c6c..77c75074 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -14,9 +14,9 @@
https://github.com/USACE-RMC/WPF-Framework
https://github.com/USACE-RMC/WPF-Framework
git
- 1.0.2
- 1.0.2.0
- 1.0.2.0
+ 1.0.3
+ 1.0.3.0
+ 1.0.3.0
false
false
diff --git a/README.md b/README.md
index 227bf453..70985220 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ dotnet test WPF-Framework.sln
### Build Packages
```bash
-.\scripts\pack-wpf-framework.ps1 -Configuration Release -Version 1.0.2
+.\scripts\pack-wpf-framework.ps1 -Configuration Release -Version 1.0.3
```
This creates and validates the following NuGet packages in `artifacts/packages/`:
diff --git a/codemeta.json b/codemeta.json
index 6bf12afa..36c0cede 100644
--- a/codemeta.json
+++ b/codemeta.json
@@ -3,9 +3,9 @@
"@type": "SoftwareSourceCode",
"name": "WPF Framework",
"description": "A free and open-source .NET 10 application framework for building Windows desktop project management applications. Provides a docking application shell with theming, project explorer, undo/redo, and specialized controls for charting, numeric input, databases, expression parsing, and directed acyclic graphs.",
- "version": "1.0.2",
+ "version": "1.0.3",
"dateCreated": "2025-12-29",
- "dateModified": "2026-07-10",
+ "dateModified": "2026-07-14",
"license": "https://spdx.org/licenses/0BSD",
"codeRepository": "https://github.com/USACE-RMC/WPF-Framework",
"issueTracker": "https://github.com/USACE-RMC/WPF-Framework/issues",
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 2531b3ac..9896704c 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -30,7 +30,7 @@ For NuGet consumption, reference the Controls bundle. It brings in Core, Models,
```xml
-
+
```
diff --git a/scripts/pack-wpf-framework.ps1 b/scripts/pack-wpf-framework.ps1
index 9b667100..08078b0c 100644
--- a/scripts/pack-wpf-framework.ps1
+++ b/scripts/pack-wpf-framework.ps1
@@ -76,11 +76,33 @@ $expectedEntries = @{
"lib/net10.0-windows7.0/Xceed.Wpf.AvalonDock.Themes.VS2013.dll")
}
+$expectedVersionedEntries = @{
+ "RMC.Wpf.Framework.Core" = @(
+ "lib/net10.0-windows7.0/FrameworkInterfaces.dll",
+ "lib/net10.0-windows7.0/Themes.dll")
+ "RMC.Wpf.Framework.Models" = @(
+ "lib/net10.0-windows7.0/DAG.dll",
+ "lib/net10.0-windows7.0/DatabaseManager.dll",
+ "lib/net10.0-windows7.0/ExpressionParser.dll")
+ "RMC.Wpf.Framework.Support" = @(
+ "lib/net10.0-windows7.0/SoftwareUpdate.dll",
+ "contentFiles/any/net10.0-windows7.0/SoftwareUpdate.Updater.exe",
+ "contentFiles/any/net10.0-windows7.0/SoftwareUpdate.Updater.dll")
+ "RMC.Wpf.Framework.Controls" = @(
+ "lib/net10.0-windows7.0/GenericControls.dll",
+ "lib/net10.0-windows7.0/FrameworkUI.dll",
+ "lib/net10.0-windows7.0/DAGControls.dll",
+ "lib/net10.0-windows7.0/DatabaseControls.dll",
+ "lib/net10.0-windows7.0/ExpressionParserControls.dll",
+ "lib/net10.0-windows7.0/NumericControls.dll",
+ "lib/net10.0-windows7.0/OxyPlotControls.dll")
+}
+
$expectedReleaseNotes = @{
- "RMC.Wpf.Framework.Core" = "Coordinated WPF Framework 1.0.2 release; no package-specific functional changes."
- "RMC.Wpf.Framework.Models" = "Coordinated WPF Framework 1.0.2 release; no package-specific functional changes."
- "RMC.Wpf.Framework.Support" = "Version 1.0.2 carries forward protected, transactional self-updates and ships a version-aligned updater payload."
- "RMC.Wpf.Framework.Controls" = "Version 1.0.2 improves time-series table validation performance, preserves ordering checks after edits, and avoids repeated full-table scans while rebuilding large series."
+ "RMC.Wpf.Framework.Core" = "Coordinated WPF Framework 1.0.3 release; no package-specific functional changes."
+ "RMC.Wpf.Framework.Models" = "Coordinated WPF Framework 1.0.3 release; no package-specific functional changes."
+ "RMC.Wpf.Framework.Support" = "Coordinated WPF Framework 1.0.3 release; no package-specific functional changes."
+ "RMC.Wpf.Framework.Controls" = "Version 1.0.3 defaults the DatabaseControls TableViewer Export Table dialog to CSV while retaining DBF, Excel, and SQLite options."
}
foreach ($packageId in $expectedEntries.Keys) {
@@ -134,35 +156,37 @@ foreach ($packageId in $expectedEntries.Keys) {
throw "$($package.Name) has unexpected NuGet release notes."
}
- if ($packageId -eq "RMC.Wpf.Framework.Support") {
- $numericVersion = ($packageVersion -split '-')[0]
- $expectedFileVersion = "$numericVersion.0"
- $payloadBinaryEntries = @(
- "contentFiles/any/net10.0-windows7.0/SoftwareUpdate.Updater.exe",
- "contentFiles/any/net10.0-windows7.0/SoftwareUpdate.Updater.dll")
- $inspectionDirectory = Join-Path ([System.IO.Path]::GetTempPath()) "wpf-framework-package-$([Guid]::NewGuid().ToString('N'))"
- New-Item -ItemType Directory -Path $inspectionDirectory | Out-Null
-
- try {
- foreach ($payloadEntryName in $payloadBinaryEntries) {
- $payloadEntry = $zip.GetEntry($payloadEntryName)
- $payloadPath = Join-Path $inspectionDirectory ([System.IO.Path]::GetFileName($payloadEntryName))
- [System.IO.Compression.ZipFileExtensions]::ExtractToFile($payloadEntry, $payloadPath, $false)
- $versionInfo = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($payloadPath)
-
- if ($versionInfo.FileVersion -ne $expectedFileVersion) {
- throw "$($package.Name) payload $payloadEntryName has file version $($versionInfo.FileVersion) instead of $expectedFileVersion."
- }
+ $numericVersion = ($packageVersion -split '-')[0]
+ $expectedBinaryVersion = "$numericVersion.0"
+ $inspectionDirectory = Join-Path ([System.IO.Path]::GetTempPath()) "wpf-framework-package-$([Guid]::NewGuid().ToString('N'))"
+ New-Item -ItemType Directory -Path $inspectionDirectory | Out-Null
- if ([string]::IsNullOrWhiteSpace($versionInfo.ProductVersion) -or
- -not $versionInfo.ProductVersion.StartsWith($packageVersion, [System.StringComparison]::OrdinalIgnoreCase)) {
- throw "$($package.Name) payload $payloadEntryName has product version $($versionInfo.ProductVersion) instead of $packageVersion."
+ try {
+ foreach ($payloadEntryName in $expectedVersionedEntries[$packageId]) {
+ $payloadEntry = $zip.GetEntry($payloadEntryName)
+ $payloadPath = Join-Path $inspectionDirectory ([System.IO.Path]::GetFileName($payloadEntryName))
+ [System.IO.Compression.ZipFileExtensions]::ExtractToFile($payloadEntry, $payloadPath, $false)
+ $versionInfo = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($payloadPath)
+
+ if ($versionInfo.FileVersion -ne $expectedBinaryVersion) {
+ throw "$($package.Name) payload $payloadEntryName has file version $($versionInfo.FileVersion) instead of $expectedBinaryVersion."
+ }
+
+ if ([string]::IsNullOrWhiteSpace($versionInfo.ProductVersion) -or
+ -not $versionInfo.ProductVersion.StartsWith($packageVersion, [System.StringComparison]::OrdinalIgnoreCase)) {
+ throw "$($package.Name) payload $payloadEntryName has product version $($versionInfo.ProductVersion) instead of $packageVersion."
+ }
+
+ if ([System.IO.Path]::GetExtension($payloadPath).Equals(".dll", [System.StringComparison]::OrdinalIgnoreCase)) {
+ $assemblyVersion = [System.Reflection.AssemblyName]::GetAssemblyName($payloadPath).Version.ToString()
+ if ($assemblyVersion -ne $expectedBinaryVersion) {
+ throw "$($package.Name) payload $payloadEntryName has assembly version $assemblyVersion instead of $expectedBinaryVersion."
}
}
}
- finally {
- Remove-Item -LiteralPath $inspectionDirectory -Recurse -Force -ErrorAction SilentlyContinue
- }
+ }
+ finally {
+ Remove-Item -LiteralPath $inspectionDirectory -Recurse -Force -ErrorAction SilentlyContinue
}
}
finally {
diff --git a/src/DAGControls/Properties/AssemblyInfo.cs b/src/DAGControls/Properties/AssemblyInfo.cs
index 6561bfcd..cb9a9684 100644
--- a/src/DAGControls/Properties/AssemblyInfo.cs
+++ b/src/DAGControls/Properties/AssemblyInfo.cs
@@ -50,5 +50,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("1.0.3.0")]
+[assembly: AssemblyFileVersion("1.0.3.0")]
diff --git a/src/DatabaseControls/TableViewer.xaml.cs b/src/DatabaseControls/TableViewer.xaml.cs
index f53676f8..3e4110f6 100644
--- a/src/DatabaseControls/TableViewer.xaml.cs
+++ b/src/DatabaseControls/TableViewer.xaml.cs
@@ -4369,7 +4369,7 @@ private void ExportTable()
string filters = "comma delimited(*.csv) |*.csv|database(*.dbf) |*.dbf|Excel(*.xlsx) |*.xlsx|Sqlite(*.sqlite) |*.sqlite";
try
{
- var saveFileBrowser = new SaveFileDialog { Filter = filters, FilterIndex = 3 };
+ var saveFileBrowser = new SaveFileDialog { Filter = filters, FilterIndex = 1 };
if (saveFileBrowser.ShowDialog() == true)
{
switch (System.IO.Path.GetExtension(saveFileBrowser.FileName))
diff --git a/src/OxyPlotControls/Properties/AssemblyInfo.cs b/src/OxyPlotControls/Properties/AssemblyInfo.cs
index 61d2814c..99132de8 100644
--- a/src/OxyPlotControls/Properties/AssemblyInfo.cs
+++ b/src/OxyPlotControls/Properties/AssemblyInfo.cs
@@ -28,8 +28,8 @@
// Build Number
// Revision
//
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("1.0.3.0")]
+[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
diff --git a/src/Packaging/RMC.Wpf.Framework.Controls/RMC.Wpf.Framework.Controls.csproj b/src/Packaging/RMC.Wpf.Framework.Controls/RMC.Wpf.Framework.Controls.csproj
index cad8a745..7f06e0dd 100644
--- a/src/Packaging/RMC.Wpf.Framework.Controls/RMC.Wpf.Framework.Controls.csproj
+++ b/src/Packaging/RMC.Wpf.Framework.Controls/RMC.Wpf.Framework.Controls.csproj
@@ -3,7 +3,7 @@
net10.0-windows
true
false
- 1.0.2
+ 1.0.3
RMC.Wpf.Framework.Controls.nuspec
$(MSBuildProjectDirectory)
configuration=$(Configuration);version=$(Version);rmcNumericsPackageDependencyVersion=$(RmcNumericsPackageDependencyVersion)
diff --git a/src/Packaging/RMC.Wpf.Framework.Controls/RMC.Wpf.Framework.Controls.nuspec b/src/Packaging/RMC.Wpf.Framework.Controls/RMC.Wpf.Framework.Controls.nuspec
index 675f7e20..b3db213f 100644
--- a/src/Packaging/RMC.Wpf.Framework.Controls/RMC.Wpf.Framework.Controls.nuspec
+++ b/src/Packaging/RMC.Wpf.Framework.Controls/RMC.Wpf.Framework.Controls.nuspec
@@ -10,7 +10,7 @@
README.md
WPF controls, framework UI, DAG controls, database controls, numeric controls, OxyPlot controls, and AvalonDock assemblies for the RMC WPF Framework.
- Version 1.0.2 improves time-series table validation performance, preserves ordering checks after edits, and avoids repeated full-table scans while rebuilding large series.
+ Version 1.0.3 defaults the DatabaseControls TableViewer Export Table dialog to CSV while retaining DBF, Excel, and SQLite options.
RMC WPF framework controls AvalonDock OxyPlot numeric database DAG
diff --git a/src/Packaging/RMC.Wpf.Framework.Core/RMC.Wpf.Framework.Core.csproj b/src/Packaging/RMC.Wpf.Framework.Core/RMC.Wpf.Framework.Core.csproj
index 1f96a19f..9b19b29a 100644
--- a/src/Packaging/RMC.Wpf.Framework.Core/RMC.Wpf.Framework.Core.csproj
+++ b/src/Packaging/RMC.Wpf.Framework.Core/RMC.Wpf.Framework.Core.csproj
@@ -3,7 +3,7 @@
net10.0-windows
true
false
- 1.0.2
+ 1.0.3
RMC.Wpf.Framework.Core.nuspec
$(MSBuildProjectDirectory)
configuration=$(Configuration);version=$(Version)
diff --git a/src/Packaging/RMC.Wpf.Framework.Core/RMC.Wpf.Framework.Core.nuspec b/src/Packaging/RMC.Wpf.Framework.Core/RMC.Wpf.Framework.Core.nuspec
index c3b56d3a..49da43b9 100644
--- a/src/Packaging/RMC.Wpf.Framework.Core/RMC.Wpf.Framework.Core.nuspec
+++ b/src/Packaging/RMC.Wpf.Framework.Core/RMC.Wpf.Framework.Core.nuspec
@@ -10,7 +10,7 @@
README.md
Core interfaces, project model contracts, undo/redo infrastructure, messaging, and WPF themes for the RMC WPF Framework.
- Coordinated WPF Framework 1.0.2 release; no package-specific functional changes.
+ Coordinated WPF Framework 1.0.3 release; no package-specific functional changes.
RMC WPF framework themes undo-redo
diff --git a/src/Packaging/RMC.Wpf.Framework.Models/RMC.Wpf.Framework.Models.csproj b/src/Packaging/RMC.Wpf.Framework.Models/RMC.Wpf.Framework.Models.csproj
index a4038bc9..24742ea2 100644
--- a/src/Packaging/RMC.Wpf.Framework.Models/RMC.Wpf.Framework.Models.csproj
+++ b/src/Packaging/RMC.Wpf.Framework.Models/RMC.Wpf.Framework.Models.csproj
@@ -3,7 +3,7 @@
net10.0-windows
true
false
- 1.0.2
+ 1.0.3
RMC.Wpf.Framework.Models.nuspec
$(MSBuildProjectDirectory)
configuration=$(Configuration);version=$(Version);closedXmlVersion=$(ClosedXmlVersion);documentFormatOpenXmlVersion=$(DocumentFormatOpenXmlVersion);excelNumberFormatVersion=$(ExcelNumberFormatVersion);fastMemberVersion=$(FastMemberVersion);sourceGearSqlite3Version=$(SourceGearSqlite3Version);systemDataSQLiteVersion=$(SystemDataSQLiteVersion)
diff --git a/src/Packaging/RMC.Wpf.Framework.Models/RMC.Wpf.Framework.Models.nuspec b/src/Packaging/RMC.Wpf.Framework.Models/RMC.Wpf.Framework.Models.nuspec
index 5ff8f9d3..69be73ba 100644
--- a/src/Packaging/RMC.Wpf.Framework.Models/RMC.Wpf.Framework.Models.nuspec
+++ b/src/Packaging/RMC.Wpf.Framework.Models/RMC.Wpf.Framework.Models.nuspec
@@ -10,7 +10,7 @@
README.md
Model, graph, database, expression-parser, and vendored OxyPlot assemblies for the RMC WPF Framework.
- Coordinated WPF Framework 1.0.2 release; no package-specific functional changes.
+ Coordinated WPF Framework 1.0.3 release; no package-specific functional changes.
RMC WPF framework database expression-parser DAG OxyPlot
diff --git a/src/Packaging/RMC.Wpf.Framework.Support/RMC.Wpf.Framework.Support.csproj b/src/Packaging/RMC.Wpf.Framework.Support/RMC.Wpf.Framework.Support.csproj
index 4bd69ee1..73bb61e1 100644
--- a/src/Packaging/RMC.Wpf.Framework.Support/RMC.Wpf.Framework.Support.csproj
+++ b/src/Packaging/RMC.Wpf.Framework.Support/RMC.Wpf.Framework.Support.csproj
@@ -3,7 +3,7 @@
net10.0-windows
true
false
- 1.0.2
+ 1.0.3
$(NoWarn);NU5100
RMC.Wpf.Framework.Support.nuspec
diff --git a/src/Packaging/RMC.Wpf.Framework.Support/RMC.Wpf.Framework.Support.nuspec b/src/Packaging/RMC.Wpf.Framework.Support/RMC.Wpf.Framework.Support.nuspec
index 101bde80..3dfdff43 100644
--- a/src/Packaging/RMC.Wpf.Framework.Support/RMC.Wpf.Framework.Support.nuspec
+++ b/src/Packaging/RMC.Wpf.Framework.Support/RMC.Wpf.Framework.Support.nuspec
@@ -10,7 +10,7 @@
README.md
Software update services and deployable updater helper for the RMC WPF Framework.
- Version 1.0.2 carries forward protected, transactional self-updates and ships a version-aligned updater payload.
+ Coordinated WPF Framework 1.0.3 release; no package-specific functional changes.
RMC WPF framework software-update updater
diff --git a/src/SoftwareUpdate.Updater/SoftwareUpdate.Updater.csproj b/src/SoftwareUpdate.Updater/SoftwareUpdate.Updater.csproj
index 656d6e65..e9f05f1d 100644
--- a/src/SoftwareUpdate.Updater/SoftwareUpdate.Updater.csproj
+++ b/src/SoftwareUpdate.Updater/SoftwareUpdate.Updater.csproj
@@ -8,9 +8,9 @@
enable
enable
latest
- 1.0.2
- 1.0.2.0
- 1.0.2.0
+ 1.0.3
+ 1.0.3.0
+ 1.0.3.0
diff --git a/tests/Themes.Tests/Core/TableViewerExportTests.cs b/tests/Themes.Tests/Core/TableViewerExportTests.cs
new file mode 100644
index 00000000..8165794e
--- /dev/null
+++ b/tests/Themes.Tests/Core/TableViewerExportTests.cs
@@ -0,0 +1,86 @@
+using System.IO;
+using Xunit;
+
+namespace Themes.Tests.Core;
+
+///
+/// Regression tests for TableViewer export dialog defaults.
+///
+public class TableViewerExportTests
+{
+ ///
+ /// Verifies the Export Table dialog defaults to comma-delimited output.
+ ///
+ [Fact]
+ public void ExportTable_DefaultsToCsv()
+ {
+ string source = File.ReadAllText(ResolveRepoPath("src/DatabaseControls/TableViewer.xaml.cs"));
+ string exportTable = ExtractMethod(source, "private void ExportTable()");
+
+ Assert.Contains("string filters = \"comma delimited(*.csv) |*.csv|", exportTable);
+ Assert.Contains("new SaveFileDialog { Filter = filters, FilterIndex = 1 }", exportTable);
+ Assert.DoesNotContain("FilterIndex = 3", exportTable);
+ }
+
+ ///
+ /// Extracts a method body from a C# source file.
+ ///
+ /// The source text.
+ /// The method signature prefix.
+ /// The method body, including the signature and braces.
+ private static string ExtractMethod(string source, string signature)
+ {
+ int start = source.IndexOf(signature, StringComparison.Ordinal);
+ Assert.True(start >= 0, signature + " should exist.");
+
+ int bodyStart = source.IndexOf('{', start);
+ Assert.True(bodyStart >= start, signature + " should have a body.");
+
+ int depth = 0;
+ for (int i = bodyStart; i < source.Length; i++)
+ {
+ if (source[i] == '{')
+ {
+ depth++;
+ }
+ else if (source[i] == '}')
+ {
+ depth--;
+ if (depth == 0)
+ {
+ return source.Substring(start, i - start + 1);
+ }
+ }
+ }
+
+ throw new InvalidOperationException(signature + " body was not closed.");
+ }
+
+ ///
+ /// Resolves a repository-relative path from the test output directory.
+ ///
+ /// The repository-relative path.
+ /// The absolute path.
+ private static string ResolveRepoPath(string repoRelativePath)
+ {
+ string current = AppContext.BaseDirectory;
+ while (!string.IsNullOrEmpty(current))
+ {
+ if (File.Exists(Path.Combine(current, "WPF-Framework.sln")))
+ {
+ return Path.Combine(current, repoRelativePath.Replace('/', Path.DirectorySeparatorChar));
+ }
+
+ string? parent = Path.GetDirectoryName(current);
+ if (parent == current)
+ {
+ break;
+ }
+
+ current = parent!;
+ }
+
+ throw new InvalidOperationException(
+ $"Could not locate repository root (looking for WPF-Framework.sln) starting from {AppContext.BaseDirectory}");
+ }
+}