Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hc:InfoElement.Title and hc:TitleElement.Title for input controls fails to handle Binding Converter correctly #1695

Open
pixelredimo opened this issue Feb 6, 2025 · 0 comments

Comments

@pixelredimo
Copy link

Describe the bug

hc:InfoElement.Title and hc:TitleElement.Title (for input controls such as hc:TextBox, hc:ComboBox, hc:NumericUpDown, hc:DateTimePicker, etc...)
when set to use {Binding Converter}, Fails to associate Validation Error Messages correctly.

It will display the validation error message generated by a different control, in a list of controls. This is despite the control using the {Binding Converter} in Title not having any validation errors.

This problem does not occur if the Title is set to a string literal or Binding to a standard MVVM property.

Steps to reproduce the bug

The input control with a Binding Converter will work incorrectly by display the validation error message that was generated by a different input control (the error message seems to be from the last control that has the error in a list of controls).

InputWindow.xaml

<hc:Window x:Class="App.InputWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:hc="https://handyorg.github.io/handycontrol"
        xmlns:system="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:App"
        mc:Ignorable="d"
        Title="Input Parameters" 
        DataContext="{Binding InputViewModel, Source={StaticResource Locator}}"
        Height="Auto" Width="400">
  <hc:Window.Resources>
    <local:LocalizationConverter x:Key="L10nConverter" />
  </hc:Window.Resources>
  <ScrollViewer>
    <StackPanel>
      <UniformGrid Columns="1">

        <!--This TextBox (using Binding Converter for Title), will incorrectly display the validation error message that belongs to the last NumericUpDown control -->
        <hc:TextBox hc:InfoElement.Title="{Binding Converter={StaticResource L10nConverter}, ConverterParameter=ContainerBarcode}" Text="{Binding Barcode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" hc:TitleElement.TitlePlacement="Left" hc:InfoElement.TitleWidth="130"  />

        <!--This TextBox (using Binding to standard MVVM property for Title) will correctly display validation error message if it has an error, else it will be empty as expected. The TitleBarcode binding gets its value from the same L10nService as used by L10nConverter used above -->
        <hc:TextBox hc:InfoElement.Title="{Binding TitleBarcode}" Text="{Binding Barcode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" hc:TitleElement.TitlePlacement="Left" hc:InfoElement.TitleWidth="130" />

        <!--This TextBox (using string literal for Title) will correctly display validation error message if it has an error, else it will be empty as expected. -->
        <hc:TextBox hc:InfoElement.Title="Container Barcode" Text="{Binding Barcode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" hc:TitleElement.TitlePlacement="Left" hc:InfoElement.TitleWidth="130" />

        <hc:NumericUpDown hc:TitleElement.Title="Container Weight (kg)" Value="{Binding Weight, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource NumericUpDownPlus}" hc:TitleElement.TitlePlacement="Left" hc:InfoElement.TitleWidth="130" />

      </UniformGrid>

      <hc:UniformSpacingPanel Margin="5" Spacing="5" Orientation="Vertical" >
        <Button Content="Cancel" Style="{StaticResource ButtonDanger}" IsCancel="True" />
        <Button Content="Validate" Command="{Binding ValidateCmd, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource ButtonPrimary}" IsDefault="True" />
      </hc:UniformSpacingPanel>

  </ScrollViewer>
</hc:Window>

InputWindow.xaml.cs

public partial class InputWindow
{
  public InputWindow()
  {
    InitializeComponent();
  }
}

namespace used in example
namespace App

View Model: InputViewModel.cs

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.DependencyInjection;
using System.ComponentModel.DataAnnotations;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Windows;

public class InputViewModel : ObservableValidator
{
    private string barcode = string.Empty;
    [Required(ErrorMessage = "Required")]
    public string Barcode
    {
      get => barcode;
      set => SetProperty(ref barcode, value, true);
    }

    private float weight;
    [Range(1,1000)]
    public float Weight
    {
      get => weight;
      set => SetProperty(ref weight, value, true);
    }

    private string titleBarcode;
    public string TitleBarcode
    {
      get => titleBarcode;
      set => SetProperty(ref titleBarcode, value);
    }

    public RelayCommand ValidateCmd { get; }

    public AssayInputViewModel()
    {
       ValidateCmd = new(ValidateParameters);
       // Get the Title string to use for the TextBox
       TitleBarcode = Ioc.Default.GetService<L10nService>()["ContainerBarcode"];    
    }

    private void ValidateParameters()
    {
      ValidateAllProperties();
    }
}

Localization Converter (to look up L10n string value) that is used in XAML

public class LocalizationConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      string str = string.Empty;
      try
      {
        if (parameter is not null and string key)
        {
          str = key; // set key as default, incase the key is not found by L10nService
          str = Ioc.Default.GetService<L10nService>()[key];
        }
      }
      catch
      {
      }
      return str;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      return parameter == null ? string.Empty : parameter.ToString();
    }
  }
}

Expected behavior

hc:InfoElement.Title and hc:TitleElement.Title should be able to use {Binding Converter ...}. It should only display validation error messages that belong to itself and NOT associate an error message from a completely different input control in the same hc:Window

Screenshots

Image

The TextBox using Binding Converter is incorrectly displaying the validation error message that was generated by the NumericUpDown control

But the issue does not occur if the TextBox is using string literal (or) a standard MVVM property for the Title

NuGet package version

HandyControl 3.4.0

IDE

Visual Studio 2022

Framework type

.Net 6.0

Windows version

May 2021 Update (19043)

Additional context

The problem occurs on
.NET 6, 7, 8
HandyControl v3.4.0, v3.3.0 and previous versions
Windows 10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant