canton7 / Stylet

A very lightweight but powerful ViewModel-First MVVM framework for WPF for .NET Framework and .NET Core, inspired by Caliburn.Micro.
MIT License
996 stars 144 forks source link

Validation error indicators are gone after deactivate/activate #17

Closed azabluda closed 7 years ago

azabluda commented 7 years ago

I took the standard Stylet.Samples.ModelValidation sample app and just slightly modified its ShellView for Conductor<IScreen>.Collection.OneActive

    public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
    {
        public ShellViewModel(Func<UserViewModel> userViewModelFactory)
        {
            this.DisplayName = "Stylet.Samples.ModelValidation";

            this.Items.Add(userViewModelFactory());
            this.Items.Add(userViewModelFactory());
        }

        protected override void OnActivate()
        {
            base.OnActivate();
            this.ActivateItem(this.Items[0]);
        }
    }
<Window ...>
    <TabControl ItemsSource="{Binding Items}" SelectedItem="{Binding ActiveItem}">
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ContentControl s:View.Model="{Binding}"/>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Window>

The initial screen shows up correctly with error indicators. I switch to another tab and the indicators are also there. But when I switch back to the first tab the indicators are gone. Is it a correct behavior? If so then is there a way to force/bring the error indicators back?

canton7 commented 7 years ago

Weird, it seems that WPF isn't refreshing the validation state - when the first tab activates again, it still has the correct values for HasErrors and GetErrors. If we force the ErrorsChanged even to be raised again (by clearing the error for a field, then putting it back again), then WPF notices. Unfortunately there's no way, currently, to clear all validation errors then re-validate.

I don't think there's a workaround currently: there's no way to clear the propertyErrors collection.

I'm actually thinking of rewriting ValidatingModelBase to be much simpler - just having the RecordPropertyError method, and following a push-based approach rather than having ValidatingModelBase call the validator directly.

canton7 commented 7 years ago

I'll add in a method to clear all validation results, so you can validate again.

canton7 commented 7 years ago

When this gets released, the following will work around the issue

        protected override void OnActivate()
        {
            this.ClearAllPropertyErrors();
            this.Validate();
            base.OnActivate();
        }

I don't think there's much else I can do at the moment - I want to rearrange things so Screen derives from PropertyChangedBase, and some sort of ValidatingScreen derives from Screen, then ValidatingScreen can hook into when Screen is activated to overcome this. I don't see a way to do that without massively breaking backwards compatibility though...

Splinterjke commented 7 years ago

For TabItems seems like it works w/o clearing property errors and overriding OnActivate(), but after you switched the TabItem the Fluent validator doesn't check properties for rules till you input validated value atleast once.

canton7 commented 7 years ago

The issue is that the validation errors are there, but WPF doesn't bother to check them until we raise ErrorsChanged again for each property that has errors. That's done (in my post above) by clearing the validation errors and re-running validation.

Splinterjke commented 7 years ago

I've added setter for HasErrors property to set it manually in OnActivate(), but you're right there is always need to call errorschanged to validate properties again for errors. Got it with ClearAllPropertyErrors() thnx.