wpfvalidationinotifydataerrorinfo

Validation.Error deletes all when ContentPresenter changes content


This is a WPF, .Net 4.8 app. I have a control that's similar to tabcontrol in that there's a ContentPresenter:

<ContentPresenter Content="{Binding SelectedTab.Content, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />

If you click a certain item in a list, Content is switched to another item (the SelectedTab) held in a dependency property that looks like this:

public static readonly DependencyProperty TabsProperty = DependencyProperty.Register(nameof(Tabs), typeof(ObservableCollection<MyTab>), typeof(MyTabLikeControl), new PropertyMetadata(null));

MyTab is just a class like so:

[ContentProperty(nameof(Content))]
public class MyTab : DependencyObject
{
    #region Title
    public string Title
    {
        get => (string)GetValue(TitleProperty);
        set => SetValue(TitleProperty, value);
    }
    public static readonly DependencyProperty TitleProperty =
        DependencyProperty.Register(nameof(Title), typeof(string), typeof(MyTab), new PropertyMetadata(null));
    #endregion Title

    #region Content
    public object Content
    {
        get => GetValue(ContentProperty);
        set => SetValue(ContentProperty, value);
    }
    public static readonly DependencyProperty ContentProperty =
        DependencyProperty.Register(nameof(Content), typeof(FrameworkElement), typeof(MyTab), new PropertyMetadata(null));
        #endregion Content
}

You use the control like:

<m:MyTabControl>
    <m:MyTabControl.Tabs>
        <m:MyTab Title="Tab A">
            ...XAML content...
        </m:MyTab>
        <m:MyTab Title="Tab B">
            ...XAML content...
        </m:MyTab>
        <m:MyTab Title="Tab C">
            ...XAML content...
        </m:MyTab>
    <m:MyTabControl.Tabs>
</m:MyTabControl>

The malfunction is to do with validation. When the SelectedTab changes to one of the other items in the Tabs collection, the Validation.Error fires (x times), deleting all validation errors (using IDataErrorInfo) on the tab we're leaving. That's BAD because I am using the Validation.Error event to count the number of UI elements with errors and display it so the user knows which tabs contain validation errors.

Once I re-select the original tab (and the ContentPresenter displays it), Validation.Error fires again (x times) so I can get the error count again. But of course the other tab then loses all its errors (the event fires)!

Moreover, none of other tabs never get their error counts until they're actually selected (and the ContentPresenter displays them).

So it's like the validation system doesn't recognize the existence of the binding errors because that UI isn't displayed at that moment, even if the UI still exists. The visual state of the non-selected tabs are never lost so they not being deleted and recreated or anything like that (they're stored in the Tabs Dependency Property shown above).

Is there perhaps a way to keep the non-selected tabs in the visual tree when they're not being displayed by my ContentPresenter, and to create them in the visual tree initially? I want them all available immediately so that all tabs can show their error counts and all be updated live regardless which tab is selected.

I tried a third party validation lib called Gu.Wpf.ValidationScope but it suffered the same problem. So now I'm using Validation.Errors manually with the same effect.


Solution

  • I gave up trying to get this to work with my custom control. Instead, I found it easiest to to restyle the TabControl and TabItem, which don't have this issue because they act like an ItemsControl. TabControl has lots of useful keyboard behaviors anyway.