0

I have an fullproperty like that in my VM:

public ObservableCollection<ServiceHost> ServiceHosts
{
    get => serviceHosts;
    set
    {
        if (serviceHosts == value) { return; }
        serviceHosts = value;
        OnPropertyChanged();
    }
}

In my other ViewModel for my MainWindow I'm using the CollectionChanged event on the ServiceHosts property to get the item that was added, convert it to my expected Type and listen to ErrorsChanged event that is a property from that type.
This looks like that:

ServiceHostViewModel.ServiceHosts.CollectionChanged += ServiceHostsOnCollectionChanged;

private void ServiceHostsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.Action == NotifyCollectionChangedAction.Add)
    {
        if (e.NewItems[0] is ServiceHost newItems)
        {
            newItems.Validator = new ServiceHostValidator();
            newItems.ErrorsChanged += (o, args) => UpdateAllErrors();
            newServiceHost.ValidateAllProperties();

        }
    }
}

Unfortunately the ErrorsChanged event never triggers the UpdateAllErrors method, even when the cells show a red border, this event doesn't execute and I don't know why.
Here is a working example where I also use the ErrorsChanged event, but here I add the data to ServiceHosts from code and not the UI:

private void SetErrorsChangedEventToAllServiceHosts(XmlParserBase xmlParserBase)
{
    foreach (var serviceHost in xmlParserBase.GetServiceHostClients(new ServiceHostValidator()))
    {
        ServiceHostViewModel.ServiceHosts.Add(serviceHost);
        serviceHost.ErrorsChanged += (sender, args) => UpdateAllErrors();
    }
}

Why does the ErrorsChanged event in the ServiceHostsOnCollectionChanged doesn't work?
Any help is appreciate.

Update by comment: Here is some code from my model class

public class ServiceHost : INotifyDataErrorInfo
{
    public IValidator<ServiceHost> Validator;

    public ServiceHost(IValidator<ServiceHost> validator)
    {
        this.Validator = validator;
        this.Validator.ErrorsChanged += (s, e) => OnErrorsChanged(e);
    }
}
Stan1k
  • 338
  • 2
  • 17

2 Answers2

1

Unfortunately the ErrorsChanged event never triggers the UpdateAllErrors method, even when the cells show a red border, this event doesn't execute and I don't know why.

It's up to the class that implements the INotifyDataErrorInfo interface to explicitly raise the ErrorsChanged event

It doesn't get raised by the framework whenever the cells show a red border. The red border could for example mean that the source property could not even be set. For example, you cannot set a property of a type T to any other value than an instance of T.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • Alright, you got me an idea what the problem might be. My model class `ServiceHost` is raising the `ErrorsChanged` event but in the constructor. When I compare my first code with the working code, i see that in the working example I create a new object and therefore my constructor gets called, while in the first code i just convert it to an object of that type. Might this be a problem? I will post the code that I mentioned. – Stan1k Apr 01 '21 at 15:35
  • *Might this be a problem?* Well, yes, if you don't raise the event, the handler will never get called. – mm8 Apr 01 '21 at 15:38
  • Alright, I added some code in the question that I mentioned in the comment. If that's the problem how can I change `e.NewItems[0] is ServiceHost newServiceHost` this part of code to call the constructor and subscribe to that event? Or where else could I position the event handler? – Stan1k Apr 01 '21 at 15:43
  • The event should get raises whenever there is an error. I don't know why you are raising it in the constructor. If you want to update the state when an object gets created/added, why don't you simply call `UpdateAllErrors` directly instead of waiting for an event that never gets raised? – mm8 Apr 01 '21 at 16:07
  • When I just call the method directly, like you mentioned, it only gets called once. But I want to call it every time when the Errors change.. I just had a look and like I thought the problem is that with this call `e.NewItems[0] is ServiceHost newServiceHost` I'm not using the constructor and therefore don't subscire to the event inside. Like I asked above is there any possibility how I can call the constructor with `e.NewItems[0]`? – Stan1k Apr 01 '21 at 17:19
  • I just moved my ErrorsChanged event from the constructor to a method that get's called inside the `if (e.NewItems[0] is ServiceHost newServiceHost)` block. It works fine until now. See my answer for more details. Anyway thanks for helping me out. – Stan1k Apr 01 '21 at 18:15
0

I just found a working solution. Like I mentioned in the comments to @mm8 I found out that this code:

Validator.ErrorsChanged += (s, e) => OnErrorsChanged(e);

which was in my constructor, never got called because by using e.NewItems[0] is ServiceHost newServiceHost to check my runtime type I didn't create a new instance and therefore didn't called the constructor. I tried moving that part outside the constructor and inside ValidateAllProperties method which works fine now.

In my case this method gets called immediately after I'm subscribing to ErrorsChanged property from MainWindow VM.

newServiceHost.ErrorsChanged += (o, args) => UpdateAllErrors();

If you have assumptions or better ideas let me know.

Stan1k
  • 338
  • 2
  • 17