Click here to Skip to main content
15,890,512 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a WPF code in which I can not get notified property updates.
My code needs to have such structure:
A1… An (view .xaml & .xaml.cs) → B1… Bn (viewmodel .cs)
C (model .cs, my business logic)
D (utility .cs like constants etc)
E (custom object .cs, that will be x-times instantiated in my model C)

Diagram: diagram.bmp - Google Drive[^]

What I need is that ONLY my custom object implements the InotifyPropertyChanged, and NOT my viewmodels, but I couldn’t get the Gui notified when settig the properties of my custom objects (E) inside my models (C).
Here is an example of what I have so far:

What I have tried:

In my views .xaml:
<Button 
    Content="{Binding content, Mode=OneWay, NotifyOnTargetUpdated=True}"
    Command="{Binding action}" />

In my views .xaml.cs (code behind):
public A1()
{
    InitializeComponent();
    DataContext = new B1();
}

In my viewmodels .cs:
public class B1 : C
{
    public string content => MyObject.Text;
    public ICommand action => MyObject.Pressed;
}

In my models .cs:
public class C : D
{
    // here i instantiate my object(s) 
    public E MyObject = new E();

    // here comes my stuff
    ... 
}

public class D
{
    //my constants and wrappers
    ... 
}

And for my custom objects (they will be x-times instantiated in my model):
public class E : INotifyPropertyChanged
{
    private string _text = String.Empty;
    public string Text
    {
        get => _text
        set => SetProperty(ref _text, value);
    }

    private readonly _DelegateCommand _pressed;
    public ICommand Pressed => _pressed;

    private void OnPressed(object commandParameter, string value)
    {
        Text = "newtext";
        _pressed.InvokeCanExecuteChanged();
    }

    private bool CanExecute(object commandParameter)
    {
        ... // some logic here
    }

    public E()
    {
        _pressed = new _DelegateCommand(OnPressed, CanExecute);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public bool SetProperty<T>(ref T field, T newValue, [CallerMemberName]string propertyName = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, newValue))
        {
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            return true;
        }
        return false;
    }
}

Can anyone help me please on this?
Thanks a lot in advance for any hints!
Posted
Updated 8-Dec-19 19:23pm
v3

You over-engineered OnPropertyChanged and things are now all confused; particularly the refs.

You make OnPropertyChanged() in the class that is bound to the controls in XAML public or internal, and call it from anything that updates that class and you want the ui updated. In terms of supplying a property name, it's only worthwhile if you can use nameof() instead of literals, and performance-wise, it only matters when "paging" or the like, otherwise, no one can tell when you supply only "" to refresh all in THAT user control / view model / controller / presenter / code-behind.
 
Share this answer
 
v4
Comments
anna3276 8-Dec-19 23:40pm    
Hi Gerry, thanks for your reply. All classes are already "public", so unfortunately I don't get your point... could you please let me know the way I should change my business-logic class (C) so that changes in my object's properties (instances of (E) everywhere) may update/refresh my views (A1)? Many thanks for your time!
[no name] 9-Dec-19 1:42am    
Inheritance is usually bad, particularly in your case; and the only object that "logically" makes sense to have an IPropertyChangedInterface is "B1", which has no proper properties. Too much "indirection" otherwise.

(It's pointless to do individual "property changed" if you're refreshing ALL the properties since OnPropertyChanged("") accomplishes the same thing … that's why I said to make it public or internal so it can be called from "outside" that object when necessary.)

public partial class xxx : aaaa, INotifyPropertyChanged {

public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged( string name = "" ) {
PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( name ) );
}

// etc.
}
anna3276 9-Dec-19 3:18am    
uhmm... what are classes
xxx
and
aaaa
supposedd to be in your sample? I've tried to write these changes into my class (C) but with no success... certainly I am missing something important here...
if i understand well, i dont think so you need class b1 just for inheriting c which does not make sense here. as datacontext you are trying to set here is class c, so just make sure all binding are done for controls are part of data context class. m not sure use of class E here, you can even move all stuff from E to class C to make your design simple.
public A1()
{
    InitializeComponent();
    DataContext = new C();
}
public class C : D
{
    public E MyObject;
    public C()
    {
        MyObject = new E();
    }
    public string content => MyObject.Text;
    public ICommand action => MyObject.Pressed;
}
 
Share this answer
 
Comments
anna3276 9-Dec-19 0:50am    
Hi Ashutosh, thanks for your reply. I still need the program structure exposed in my diagram and question, but I changed anyway my
DataContext = new B1();
(which before asking I also tried) but still don't gets notifications on my gui...
Ashutosh Gpta 9-Dec-19 1:05am    
ok, then your solution could be, keep reference of c in your class E and class E is kind o child of C, which is managing E.
implement INotifyPropertyChanged for class c as well as this class props are binded in control.
public E MyObject = new E(this); // c class implementation.
public E(C cobj) // constructor of E
{
this.Cobj = cobj;
}
public bool SetProperty<t>(ref T field, T newValue, [CallerMemberName]string propertyName = null)
{
if (!EqualityComparer<t>.Default.Equals(field, newValue))
{
field = newValue;
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
this.Cobj.PropertyChanged?.Invoke(this.Cobj, new
PropertyChangedEventArgs(nameof(this.Cobj.Content)));
return true;
}
return false;
}

do not just refer my code and paste it, i hope my code give you understanding of how INotifyPropChnge work.
anna3276 9-Dec-19 3:15am    
I tried to get your (adapted) code to work in my program sample but unfortunately not managed. Although, I can not understand why you added the line
this.Cobj.PropertyChanged?.Invoke(this.Cobj, new PropertyChangedEventArgs(nameof(this.Cobj.Content)));
because there are no properties to be changed in class C, as all of those are defined in class E...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900