Wranglerino
Wranglerino

Reputation: 197

Property wont bind to view

Got good help here earlier regarding getting a property from another class using an eventhandler. Update property from interface

The result is a property that looks like this on my ViewModel and it does not behave in a familiar way.

 public string Test
    {
        get { return _myInterface.Test; }
        set {_myInterface.Test = value }
    }

This is a property that I would like to bind to my view. Normally I would do it like this:

<TextBlock Text="{Binding Test}"/>

It does not work on this specifik property. When hovering over value I can see that the value is there. But when i hover over the propertyname, nothing happens.

Edit:

 public double Test
    {
        get { return _myInterface.Test; }
        set
        {
            _myInterface.Test = value;
            OnPropertyChanged("Test");
        }

    }

public new event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propName)
{
    if (this.PropertyChanged != null)
    {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
}  

Complete code:

Interface:

 public interface IMyInterFace: INotifyPropertyChanged
    {

        string Test { get; set; }
    }

Class that implements it:

public class MyClass : MyInterface
    {

        private string _test;
        public string Test
        {
            get { return _test; }
            set
            {
                _test = value;
                OnPropertyChanged("Test");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }


        public void MyMetod()
        {
            //logic that updates Test
        }

ViewModel: (takes the IInterface in constructor.)

 public string Test
        {
            get
            {
                return _myInterface.Test;
            }
            set
            {
                _myInterface.Test = value;
                OnPropertyChanged();
            }
        }


        public new event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

The OnPropertyChanged in the VM does never get hit..

UPDATE:

This is now my view-model:

I got rid of MVVM-light and now do it like this:

public class ViewModel : INotifyPropertyChanged
{
     public string Test
            {
                get { return _myInterface.Test; }
                set
                {
                    _myInterface.Test = value;
                    OnPropertyChanged("Test");
                }

            }

            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(propertyName));
                }
            }

}

But the event-handler never gets hit. The Value in the Test-property never gest assigned properly. Even though I can "see" the value when hovering over value. Thank you very much for helping.

Upvotes: 1

Views: 163

Answers (3)

Daniel Mann
Daniel Mann

Reputation: 58981

You're hiding the PropertyChangedEventHandler in your viewmodel's base class with the new keyword.

public new event PropertyChangedEventHandler PropertyChanged;

Presumably, your viewmodel is inheriting from some other class that also implements INotifyPropertyChanged. If that's the case, you don't need to reimplement the interface.

Update:

I took an existing project of mine and broke it in the same way as follows:

Given an existing Notifier base class:

public class NotifierBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

and an implementor:

public class MainWindowViewModel : NotifierBase
{
    private bool someProperty;
    public bool SomeProperty 
    {
        get
        {
            return this.someProperty;
        }
        set
        {
            if (this.someProperty != value)
            {
                this.someProperty = value;
                this.OnPropertyChanged();
            }
        }
    }
}

When I changed the view model class as follows:

public class MainWindowViewModel : NotifierBase
{
    private bool someProperty;
    public bool SomeProperty 
    {
        get
        {
            return this.someProperty;
        }
        set
        {
            if (this.someProperty != value)
            {
                this.someProperty = value;
                this.OnPropertyChanged();
            }
        }
    }

    public new event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

This broke in exactly the same way you're describing. Only implement the PropertyChangedEventHandler once.

Upvotes: 1

Sagiv b.g
Sagiv b.g

Reputation: 31014

have you tried to set the "UpdateSourceTrigger" to "PropertyChanged"?

<TextBlock Text="{Binding Test,UpdateSourceTrigger=PropertyChanged}"/>

I would also check the DataContext. just to be sure, try to explicit mention the DataSource

for example if you got a resource with a Key named: "MainViewModel" then:

<TextBlock Text="{Binding Test,Source={StaticResource MainViewModel},UpdateSourceTrigger=PropertyChanged}"/>

*Edit: can you please try this implementation of INotifyPropertyChanged instead of what you have:

public event PropertyChangedEventHandler PropertyChanged = delegate { };

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

*Edit#2: on your last piece of code (ViewModel) looks like you forgot to pass the name of the property to the OnPropertyChanged() method.

public string Test
        {
            get
            {
                return _myInterface.Test;
            }
            set
            {
                _myInterface.Test = value;
                OnPropertyChanged();
            }
        }

Upvotes: 0

Rainer
Rainer

Reputation: 356

You need to implement the INotifyPropertyChanged and raise it when setting your Test like

public class YourClass : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public string Test
        {
            get
            {
                return _myInterface.Test;
            }
            set
            {
                _myInterface.Test = value;
                OnPropertyChanged();
            }
        }
    }

Upvotes: 0

Related Questions