Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
6 changes: 3 additions & 3 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
<PackageProjectUrl>https://github.com/USACE-RMC/WPF-Framework</PackageProjectUrl>
<RepositoryUrl>https://github.com/USACE-RMC/WPF-Framework</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Version>1.0.2</Version>
<AssemblyVersion>1.0.2.0</AssemblyVersion>
<FileVersion>1.0.2.0</FileVersion>
<Version>1.0.3</Version>
<AssemblyVersion>1.0.3.0</AssemblyVersion>
<FileVersion>1.0.3.0</FileVersion>

<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<IsPackable>false</IsPackable>
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/`:
Expand Down
4 changes: 2 additions & 2 deletions codemeta.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ For NuGet consumption, reference the Controls bundle. It brings in Core, Models,

```xml
<ItemGroup>
<PackageReference Include="RMC.Wpf.Framework.Controls" Version="1.0.2" />
<PackageReference Include="RMC.Wpf.Framework.Controls" Version="1.0.3" />
</ItemGroup>
```

Expand Down
82 changes: 53 additions & 29 deletions scripts/pack-wpf-framework.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/DAGControls/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
2 changes: 1 addition & 1 deletion src/DatabaseControls/TableViewer.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
4 changes: 2 additions & 2 deletions src/OxyPlotControls/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFramework>net10.0-windows</TargetFramework>
<IsPackable>true</IsPackable>
<IncludeBuildOutput>false</IncludeBuildOutput>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
<NuspecFile>RMC.Wpf.Framework.Controls.nuspec</NuspecFile>
<NuspecBasePath>$(MSBuildProjectDirectory)</NuspecBasePath>
<NuspecProperties>configuration=$(Configuration);version=$(Version);rmcNumericsPackageDependencyVersion=$(RmcNumericsPackageDependencyVersion)</NuspecProperties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<repository type="git" url="https://github.com/USACE-RMC/WPF-Framework" />
<readme>README.md</readme>
<description>WPF controls, framework UI, DAG controls, database controls, numeric controls, OxyPlot controls, and AvalonDock assemblies for the RMC WPF Framework.</description>
<releaseNotes>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.</releaseNotes>
<releaseNotes>Version 1.0.3 defaults the DatabaseControls TableViewer Export Table dialog to CSV while retaining DBF, Excel, and SQLite options.</releaseNotes>
<tags>RMC WPF framework controls AvalonDock OxyPlot numeric database DAG</tags>
<dependencies>
<group targetFramework="net10.0-windows7.0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFramework>net10.0-windows</TargetFramework>
<IsPackable>true</IsPackable>
<IncludeBuildOutput>false</IncludeBuildOutput>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
<NuspecFile>RMC.Wpf.Framework.Core.nuspec</NuspecFile>
<NuspecBasePath>$(MSBuildProjectDirectory)</NuspecBasePath>
<NuspecProperties>configuration=$(Configuration);version=$(Version)</NuspecProperties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<repository type="git" url="https://github.com/USACE-RMC/WPF-Framework" />
<readme>README.md</readme>
<description>Core interfaces, project model contracts, undo/redo infrastructure, messaging, and WPF themes for the RMC WPF Framework.</description>
<releaseNotes>Coordinated WPF Framework 1.0.2 release; no package-specific functional changes.</releaseNotes>
<releaseNotes>Coordinated WPF Framework 1.0.3 release; no package-specific functional changes.</releaseNotes>
<tags>RMC WPF framework themes undo-redo</tags>
<dependencies>
<group targetFramework="net10.0-windows7.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFramework>net10.0-windows</TargetFramework>
<IsPackable>true</IsPackable>
<IncludeBuildOutput>false</IncludeBuildOutput>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
<NuspecFile>RMC.Wpf.Framework.Models.nuspec</NuspecFile>
<NuspecBasePath>$(MSBuildProjectDirectory)</NuspecBasePath>
<NuspecProperties>configuration=$(Configuration);version=$(Version);closedXmlVersion=$(ClosedXmlVersion);documentFormatOpenXmlVersion=$(DocumentFormatOpenXmlVersion);excelNumberFormatVersion=$(ExcelNumberFormatVersion);fastMemberVersion=$(FastMemberVersion);sourceGearSqlite3Version=$(SourceGearSqlite3Version);systemDataSQLiteVersion=$(SystemDataSQLiteVersion)</NuspecProperties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<repository type="git" url="https://github.com/USACE-RMC/WPF-Framework" />
<readme>README.md</readme>
<description>Model, graph, database, expression-parser, and vendored OxyPlot assemblies for the RMC WPF Framework.</description>
<releaseNotes>Coordinated WPF Framework 1.0.2 release; no package-specific functional changes.</releaseNotes>
<releaseNotes>Coordinated WPF Framework 1.0.3 release; no package-specific functional changes.</releaseNotes>
<tags>RMC WPF framework database expression-parser DAG OxyPlot</tags>
<dependencies>
<group targetFramework="net10.0-windows7.0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFramework>net10.0-windows</TargetFramework>
<IsPackable>true</IsPackable>
<IncludeBuildOutput>false</IncludeBuildOutput>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
<!-- The updater executable payload is intentionally packaged as deployable content, not a compile reference. -->
<NoWarn>$(NoWarn);NU5100</NoWarn>
<NuspecFile>RMC.Wpf.Framework.Support.nuspec</NuspecFile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<repository type="git" url="https://github.com/USACE-RMC/WPF-Framework" />
<readme>README.md</readme>
<description>Software update services and deployable updater helper for the RMC WPF Framework.</description>
<releaseNotes>Version 1.0.2 carries forward protected, transactional self-updates and ships a version-aligned updater payload.</releaseNotes>
<releaseNotes>Coordinated WPF Framework 1.0.3 release; no package-specific functional changes.</releaseNotes>
<tags>RMC WPF framework software-update updater</tags>
<dependencies>
<group targetFramework="net10.0-windows7.0" />
Expand Down
6 changes: 3 additions & 3 deletions src/SoftwareUpdate.Updater/SoftwareUpdate.Updater.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
<Version>1.0.2</Version>
<AssemblyVersion>1.0.2.0</AssemblyVersion>
<FileVersion>1.0.2.0</FileVersion>
<Version>1.0.3</Version>
<AssemblyVersion>1.0.3.0</AssemblyVersion>
<FileVersion>1.0.3.0</FileVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
86 changes: 86 additions & 0 deletions tests/Themes.Tests/Core/TableViewerExportTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System.IO;
using Xunit;

namespace Themes.Tests.Core;

/// <summary>
/// Regression tests for TableViewer export dialog defaults.
/// </summary>
public class TableViewerExportTests
{
/// <summary>
/// Verifies the Export Table dialog defaults to comma-delimited output.
/// </summary>
[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);
}

/// <summary>
/// Extracts a method body from a C# source file.
/// </summary>
/// <param name="source">The source text.</param>
/// <param name="signature">The method signature prefix.</param>
/// <returns>The method body, including the signature and braces.</returns>
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.");
}

/// <summary>
/// Resolves a repository-relative path from the test output directory.
/// </summary>
/// <param name="repoRelativePath">The repository-relative path.</param>
/// <returns>The absolute path.</returns>
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}");
}
}
Loading