question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Incorrect XAML codegen for INotifyDataErrorInfo

See original GitHub issue

Discovered in https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/3569

Describe the bug It looks like that the XAML codegen when binding a TextBox to a property from a viewmodel implementing INotifyDataErrorInfo is incorrect, which causes the UI not to be properly updated then an invalid property is toggled back to valid, if this is the last invalid property in the viewmodel. Toggling other properties seems to work just fine instead.

Steps to reproduce the bug

Steps to reproduce the behavior:

  1. Clone https://github.com/mvegaca/WindowsTemplateStudio/tree/Mockup-WinUI3-ObservableValidator
  2. Open the app, go do the Forms WCT page
  3. Click “Submit”, all fields will be invalid
  4. Start filling in fields with valid values
  5. Observe that whatever field you leave for last, it’s impossible to make it valid again

Expected behavior

Fields should all be updated correctly in the UI.

Screenshots

image

Version Info

NuGet package version:

Windows app type:

UWP Win32
Yes
Windows 10 version Saw the problem?
Insider Build (xxxxx)
May 2020 Update (19041) Yes
November 2019 Update (18363)
May 2019 Update (18362)
October 2018 Update (17763)
April 2018 Update (17134)
Fall Creators Update (16299)
Creators Update (15063)
Device form factor Saw the problem?
Desktop Yes
Xbox
Surface Hub
IoT

Additional context

Here is my analysis of the issue, from https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/3569#issuecomment-772555360.

I’m looking at the generated .g.cs backing file and it seems to me there might be something off here. The registration of INotifyDataErrorInfo itself is done correctly right next to INotifyPropertyChanged:

public void UpdateChildListeners_ViewModel(global::WinUIDesktopApp.ViewModels.FormWCTViewModel obj)
{
    if (obj != cache_ViewModel)
    {
        // ...
        if (obj != null)
        {
            cache_ViewModel = obj;
            ((global::System.ComponentModel.INotifyPropertyChanged)obj).PropertyChanged += PropertyChanged_ViewModel;
            ((global::System.ComponentModel.INotifyDataErrorInfo)cache_ViewModel).ErrorsChanged += ErrorsChanged_ViewModel;
        }
    }
}

Now, consider the situation where the bug happens, so when we have a viewmodel with just one remaining field that is then updated, validated again and then marked as valid. The viewmodel now has 0 errors, and it raises ErrorsChanged to notify the UI of this change in errors. We expect the view to clear the errors in that control bound to this property, which is not happening. This is the code that is invoked when ErrorsChanged is raised:

public void ErrorsChanged_ViewModel(object sender, global::System.ComponentModel.DataErrorsChangedEventArgs e) 
{
    FormWCTPage_obj1_Bindings bindings = TryGetBindingObject();
    if (bindings != null)
    {
        string propName = e.PropertyName;
        if (global::System.String.IsNullOrEmpty(propName))
        {
            bindings.UpdateErrors_ViewModel((global::System.ComponentModel.INotifyDataErrorInfo)sender, "OrderID");
            // All other properties here...
        }
        else
        {
            bindings.UpdateErrors_ViewModel((global::System.ComponentModel.INotifyDataErrorInfo)sender, propName);
        }
    }
}

In this case propName is "ShipsTo", so the second branch is taken - we can move on to UpdateErrors_ViewModel:

private void UpdateErrors_ViewModel(global::System.ComponentModel.INotifyDataErrorInfo sender, string propertyName)
{
    if (this.initialized)
    {
        switch (propertyName)
        {
            // All other properties here...
            case "ShipTo":
            {
                UpdateErrors_(obj6, sender, "ShipTo");
                break;
            }
        }
    }
}

Just a wrapper to actually switch the bound property name and the respecting control, this is fine. Now on to the possibly faulty method:

private void UpdateErrors_(global::Microsoft.UI.Xaml.Controls.Control control, global::System.ComponentModel.INotifyDataErrorInfo sender, string propertyName)
{
    if (sender.HasErrors)
    {
        UpdateInputValidationErrors(control, sender.GetErrors(propertyName));
    }
}

But here, sender.HasErrors is false now, because we just validated the last incorrect property. So this method just returns and the UI is not updated at all, which explains why we’re seeing that behavior in the last field being modified.

This is what makes me say it looks like a XAML codegen issue. It seems to me that there should at least be another branch in UpdateErrors_ that just clears all the errors in the target control without doing other checks in case the linked viewmodel has no errors left anymore.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:15 (11 by maintainers)

github_iconTop GitHub Comments

6reactions
stevenbrixcommented, Feb 16, 2021

Gotcha, thanks for your patience, I’m finally there 😃

I agree that this if (sender.HasErrors) check could just be removed. Removing the check would be my vote, because the UpdateInputValidationErrors method will already do the right thing.

5reactions
RealTommyKleincommented, Jul 8, 2021

Sorry for the delayed response on this (and thanks @azchohfi for pinging me!) , but the fix is checked in for the upcoming Reunion 1.0 fall release.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Validating insertions of wrong datatype when using ...
I've got a ViewModel implementing INotifyDataErrorInfo, and a View bound to that ViewModel. The ViewModel contains a property of type Double ...
Read more >
INotifyDataErrorInfo Interface (System.ComponentModel)
Defines members that data entity classes can implement to provide custom synchronous and asynchronous validation support.
Read more >
CSLA Forum Archive Index
Xaml.ViewModelBase<T>. 18 Nov 2012 - Accessing the "click" action of a datagridcheckbox column. 17 Nov 2012 - Problem with CSLA 4.3 on a...
Read more >
Is it possible to use swagger codegen to generate a client for ...
Currently, Swagger Codegen C# client generator supports the following framework: ... of ValidationRules and INotifyDataErrorInfo for wpf validation?
Read more >
Adding Validation to a XAML Control Using ...
We'll start by taking a look at the INotifyDataErrorInfo interface. This interface has been around for quite some time and exposes a single ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found