Suppose in a C# WPF class I have something like this:
class test: INotifyPropertyChanged
{
private datetime _DOB
public datetime DOB
{
get
{
return _DOB;
}
set
{
if (_DOB != value)
{
_DOB = value;
RaisePropertyChanged();
}
}
}
private int _age
public int Age
{
get
{
return _age;
}
set
{
if (_age != value)
{
_age = value;
RaisePropertyChanged();
}
}
}
....
}
Now, let us suppose that a user can put in any of the properties. They can put in either their DOB, or their age, so making one of them calculated property would not work.
Apart from using methods like UpdateAge() in the setter of DOB and UpdateDOB() in the setter of Age, is there any other method that would automatically update the "dependent" properties along with the dependency properties (which INPC takes care of)?
is there any other method that would automatically update the "dependent" properties along with the dependency properties (which INPC takes care of)?
There is no "automatic" or magic here. You need to set the backing field and raise the PropertyChanged event for the data bound property that you want to refresh in the view.
Just make sure that you don't end up in an infinite loop where you set the Age property from the DOB property and vice versa.
You could set the _age backing field in the setter of the DOB property and vice versa, e.g.:
private DateTime _DOB;
public DateTime DOB
{
get
{
return _DOB;
}
set
{
if (_DOB != value)
{
_DOB = value;
RaisePropertyChanged();
_age = DateTime.Now.Year - _DOB.Year;
RaisePropertyChanged("Age");
}
}
}
Related
Currently I have three properties in class MyClassOne. The number of properties may increase in future. Whenever any of the property changes, I need to call a method called SavePropertyToFile() which is responsible to set the corresponding property (AnotherPropertyOne, AnotherPropertyTwo or AnotherPropertyThree) of another class.
My sample code (which is of course not working) is below:
Class MyClassOne
{
public bool PropertyOne
{
get => _propertyOne;
set
{
if (_propertyOne == value)
return;
_propertyOne = value;
SavePropertyToFile(value, MyAnotherClass.AnotherPropertyOne); //<------------------
NotifyOfPropertyChange(() => _propertyOne);
}
}
public bool PropertyTwo
{
get => _propertyTwo;
set
{
if (_propertyTwo == value)
return;
_propertyTwo = value;
SavePropertyToFile(value, MyAnotherClass.AnotherPropertyTwo); //<------------------
NotifyOfPropertyChange(() => _propertyTwo);
}
}
public bool PropertyThree
{
get => _propertyThree;
set
{
if (_propertyThree == value)
return;
_propertyThree = value;
SavePropertyToFile(value, MyAnotherClass.AnotherPropertyThree); //<------------------
NotifyOfPropertyChange(() => _propertyThree);
}
}
SavePropertyToFile(bool value, TProperty myPropertyOfAnotherClass)
{
myPropertyOfAnotherClass = value;
// Some more lines of Code
RefreshProgram();
}
}
In the code above, I need to find a way so that I can parse the correct property of AnotherClass. I already had a look at this another SO question, but I am not able to apply any of the answer for my case.
How can I parse different properties to a method?
Update: As per the suggestions in the comments, I have tried to use "Nathan Baulch" answer's option-2 but then I getting warning/error wiggly line as shown in the screenshot below:
If the idea is to make several classes use the same property, my approach is to wrap the values in a class:
public class Changeable<T> : INotifyPropertyChanged
{
private T currentValue;
public Changeable(T initialValue) => currentValue = initialValue;
public T Value
{
get => currentValue;
set
{
if (!EqualityComparer<T>.Default.Equals(currentValue, value))
{
this.currentValue = value;
Changed?.Invoke(this, value);
OnPropertyChanged(nameof(Value));
}
}
}
public event EventHandler<T> Changed;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
You can then just let both classes use the same actual object. This approach can also be used to cut down on boilerplate for wpf, instead of declaring getters and setters you can just write:
public Changeable<bool> MyProperty {get;} => new (false);
Just remember to update the binding: {Binding MyProperty.Value}
You can also write various extensions. For example if you want to update one property whenever some other property updates:
MyProperty.BindTo(MyIntProperty, intValue => intValue > 0);
So whenever MyIntProperty changes sign, the MyProperty would be updated and raise its changed event. I'm not going to include all the code behind this, since it is fairly large, but I hope you get the idea. This approach makes it possible to link various UI values in a convenient way, but it can also make the code more difficult to understand and debug, so some caution is advised.
I am new to ObjectListView and I haven't found how to use a property of a object inside the model as AspectName for ObjectListView.
For example, the list will show Cars names and their owner name
public class Person
{
private string _name;
public string Name
{
get => _name;
set => _name = value;
}
}
public class Car
{
private Person _owner;
private string _name;
public Person Owner
{
get => _owner;
set => _owner = value;
}
public string Name
{
get => _name;
set => _name = value;
}
}
If I set the AspectName of a column to Owner.Name it doesn't show anything on the list. I have made a small workaround of defining a property OwnerName inside the Car model, but I have more complex models which is a pain to have to define that property.
Is there a way I can do that?
Thanks
Based on what you have said then this should work. So there must be some other problem which is causing this issue.
You could try setting the AspectGetter programmatically instead such as this;
this.olvColumn2.AspectGetter = delegate (Object obj)
{
Car car = (Car)obj;
if (car == null)
return "Unknown";
else
return car.Owner.Name;
};
You can then put a breakpoint inside this code and see when/if it is called and what happens.
Remember that you must define/set all of the aspect getters etc. before you call objectListView1.SetObjects
Preamble: I am making a logging tool for our company needs. We use MVVM - pattern in our projects via Caliburn. At this moment my tool is capable of weaving compiled code via Mono.Cecil assembly and injecting call of a logging method in public properties set methods.
Fabula: Let's say, I have a class Person
public class Person
{
public string Name
{
get { return _name; }
set
{
Logger.MyLogMethod(_name, value, "Person");
_name = value;
}
}
private string _name;
}
and a class Logger
public static class Logger
{
public static void MyLogMethod(string oldvalue, string newvalue, string propertyname)
{
//condition to log only user changes
}
}
And an instance of a person has its Name property binded to textbox
<TextBox Text="{Binding SelectedPerson.Name}"/>
And we have a button, which click calls a code, which will set new value to SelectedPerson.
So, we have two ways of setting our Person's Name property at a runtime. It's either by user typing in textbox, or a user clicking a button, therefore calling some code.
I would like to know: how to distinct these two cases. In other words - when a set method of a property is called - how to determine, if it was called by binding engine or by our code.
So far I have one approach that is doable in my opinion - to take a look at StackTrace. Not sure how to do it thought.
You can make the Name property private. Then you expose a public property for binding and another for the rest of the application.
You can know differentiate a call from binding from a call from somewhere else
public class Person
{
string NameForOthers
{
get { return Name; }
set
{
Logger.MyLogMethod(_name, value, "Person name set by other place");
Name= value;
}
}
public string NameForBinding
{
get { return Name; }
set
{
Logger.MyLogMethod(_name, value, "Person name set by binding");
Name= value;
}
}
string Name
{
get { return _name; }
set
{
Logger.MyLogMethod(_name, value, "Person");
_name = value;
}
}
private string _name;
}
Then you use it for your binding
<TextBox Text="{Binding SelectedPerson.NameForBinding}"/>
I have a complex class with at least 100 properties. I want to track if any properties have been changed since the class was loaded with data (initialized) so I've coded the following to manage this. I also don't want to set the IsDirty flag if the value being passed in is the same as the current value of the property. When the class is instantiated, the IsDirty flag is set to false and while data is being loaded into the class, the IsInitializing flag will be set to true.
private T SetPropertyValue<T>(T property, T value)
{
if (!property.Equals(value))
{
// If values are different, return the new value and
// if the IsInitializing flag is false, then set the dirty flag for the class.
if (!IsInitializing)
IsDirty = true;
return value;
}
// If the current value of the property and the value passed in are the same,
// return the current value of the property.
return property;
}
private DateTimeOffset? _actualProjectCompletionDate;
public DateTimeOffset? ActualProjectCompletionDate
{
get
{
return _actualProjectCompletionDate;
}
set
{
_actualProjectCompletionDate = SetPropertyValue(_actualProjectCompletionDate, value);
}
}
I'd like to avoid having to specify the actual private variable twice in the set method, but when I tried to use a method instead of a function, I had to use the out argument modifier and I also had to initialize the property value with default(T) which of course, negates what I am trying to do. I think the above will work, I was just wondering if there was a better way.
Use the ref keyword:
private T SetPropertyValue<T>(ref T property, T value)
{
if (!EqualityComparer<T>.Default.Equals(property, value))
{
if (!IsInitializing)
{
IsDirty = true;
}
property = value;
}
}
public DateTimeOffset? ActualProjectCompletionDate
{
get { return _actualProjectCompletionDate; }
set { SetPropertyValue(ref _actualProjectCompletionDate, value); }
}
I have a property defined with no explicit mention of backing field in a way like this :
//How to fire RaisePropertyChanged("Name") from setter
public string Name { get; set; }
How exactly do I fire a RaisePropertyChanged event in the setter of this property ?
I know how to do it when there is a private backing field and with a public property encapsulating it.
Is a multi line setter allowed in this scenario ?
No, you can't do this with an automatic property. You'll need to have a backing field and define both the getter and setter yourself, and raise the event in the setter as you described.
That's an Automatic Property, you need to have a backing field.
private string _name;
public string Name
{
get { return name; }
set
{
name = value;
RaisePropertyChanged("Name");
}
}