Add validation to prevent empty names in ImageResizer size presets (#45425)

## Summary of the Pull Request

Prevents users from clearing the name field in ImageResizer size preset
edit dialog. Empty names made the UI confusing without causing errors.

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

Added validation guard in `ImageSize.Name` property setter:

```csharp
public string Name
{
    get => _name;
    set
    {
        if (!string.IsNullOrWhiteSpace(value))
        {
            SetProperty(ref _name, value);
        }
    }
}
```

Invalid assignments (empty, null, whitespace) are silently ignored,
preserving the existing value. This matches the existing pattern used
for `FileName` validation in `ImageResizerViewModel`.

TwoWay binding in UI causes the TextBox to revert when users attempt to
clear the field—standard behavior for required fields.

## Validation Steps Performed

- Added unit test `ImageSizeNameShouldNotBeSetToEmptyOrNull()` covering
all rejection and acceptance cases
- Verified silent rejection behavior matches `FileName` property pattern

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `i1qvsblobprodcus353.vsblob.vsassets.io`
> - Triggering command: `/usr/bin/dotnet dotnet build
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Helpers/ResultHelper.cs
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Helpers/RegistryHelper.cs
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Enumerations/TruncateSide.cs
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Constants/KeyName.cs
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Constants/MaxTextLength.cs
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Commands/CopyRegistryInfoCommand.cs
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Commands/OpenKeyInEditorCommand.cs
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Re
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/CopyType.cs
/home/REDACTED/work/PowerToys/PowerToys/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Registry/Icons.cs`
(dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/microsoft/PowerToys/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[Settings: ImageResizer] Edit size dialog: Add validation
against empty name</issue_title>
> <issue_description>There is one small thing we should add. (But I
don't know how.)
> The data in the name field of the edit dialog should be validated
against `.NullOrEmpty`!
> _Originally posted by @htcfreek in
https://github.com/microsoft/PowerToys/pull/13285#issuecomment-924113251_
> 
> **Detailed description:**
> While users edit an image size in the ImageResizer settings on PT's
settings ux they are able to clear the name of the image size. This
doesn't lead to errors/exceptions, but it also doesn't make sense to
have sizes without a name. So we should prevent user from doing this in
the edit dialog.
> 
> _**Note:**_
> This is the second and last change that is needed to prevent the users
from having incorrect image size settings (#8698). But I think this is
not as relevant, because a missing name won't break image resizing._
> 
> ---
> 
> cc: @niels9001 </issue_description>
> 
> <agent_instructions>Implement a proper fix for this issue. Do NOT
create placeholder stub files. Create actual working code that addresses
the issue described. Follow PowerToys coding guidelines and
conventions.</agent_instructions>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> <comment_new><author>@TheJoeFin</author><body>
> does this issue still happen with v0.73.0?
/needinfo</body></comment_new>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes microsoft/PowerToys#13336

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/microsoft/PowerToys/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: yeelam-gordon <73506701+yeelam-gordon@users.noreply.github.com>
This commit is contained in:
Copilot
2026-05-15 11:39:01 +02:00
committed by GitHub
parent e932fe6e61
commit 34e78bd8c3
2 changed files with 79 additions and 2 deletions

View File

@@ -41,7 +41,7 @@ public partial class ImageSize : INotifyPropertyChanged, IHasId
}
private int _id;
private string _name;
private string _name = string.Empty;
private ResizeFit _fit;
private double _height;
private double _width;
@@ -65,11 +65,22 @@ public partial class ImageSize : INotifyPropertyChanged, IHasId
get => !(Unit == ResizeUnit.Percent && Fit != ResizeFit.Stretch);
}
/// <summary>
/// Gets or sets the name of the image size.
/// Invalid values (null, empty, or whitespace) are silently ignored to maintain the existing name.
/// </summary>
[JsonPropertyName("name")]
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
set
{
// Prevent setting empty or null names
if (!string.IsNullOrWhiteSpace(value))
{
SetProperty(ref _name, value);
}
}
}
[JsonPropertyName("fit")]

View File

@@ -313,5 +313,71 @@ namespace ViewModelTests
Assert.AreEqual(50, imageSize.Width);
Assert.AreEqual(50, imageSize.Height);
}
[TestMethod]
public void ImageSizeNameShouldNotBeSetToEmptyNullOrWhitespace()
{
// arrange
ImageSize imageSize = new ImageSize()
{
Id = 0,
Name = "Original Name",
Fit = ResizeFit.Fit,
Width = 100,
Height = 100,
Unit = ResizeUnit.Pixel,
};
// Act - try to set name to empty string
imageSize.Name = string.Empty;
// Assert - name should remain unchanged
Assert.AreEqual("Original Name", imageSize.Name);
// Act - try to set name to null
imageSize.Name = null;
// Assert - name should remain unchanged
Assert.AreEqual("Original Name", imageSize.Name);
// Act - try to set name to whitespace only
imageSize.Name = " ";
// Assert - name should remain unchanged
Assert.AreEqual("Original Name", imageSize.Name);
// Act - set name to valid value
imageSize.Name = "New Valid Name";
// Assert - name should be updated
Assert.AreEqual("New Valid Name", imageSize.Name);
}
[TestMethod]
public void ImageSizeNameShouldNotBeNullAfterConstructionWithEmptyOrMissingName()
{
// Arrange & Act - construct with default (empty) name, simulating deserialization of legacy settings
ImageSize defaultSize = new ImageSize();
// Assert - name should be non-null empty string, not null (prevents NullReferenceException in callers)
Assert.IsNotNull(defaultSize.Name);
// Arrange & Act - construct with explicit empty name
ImageSize emptyNameSize = new ImageSize(id: 1, name: string.Empty);
// Assert - name should remain as the initialized default, not null
Assert.IsNotNull(emptyNameSize.Name);
// Arrange & Act - construct with explicit null name
ImageSize nullNameSize = new ImageSize(id: 2, name: null);
// Assert - name should remain as the initialized default, not null
Assert.IsNotNull(nullNameSize.Name);
// Verify that StartsWith can be called without NullReferenceException
Assert.IsFalse(defaultSize.Name.StartsWith("Custom", StringComparison.InvariantCulture));
Assert.IsFalse(emptyNameSize.Name.StartsWith("Custom", StringComparison.InvariantCulture));
Assert.IsFalse(nullNameSize.Name.StartsWith("Custom", StringComparison.InvariantCulture));
}
}
}