Dependecy properties that depend on other properties - wpf

Class C implements INotifyPropertyChanged.
Assume the C has Length, Width and Area propreties, where Area = Length * Width. A change in either might cause a change in area. All three are bound, i.e. the UI expects all three to notify of changes in their values.
When either Length or Width change, their setters call NotifyPropertyChanged.
How should I treat the calculated Area property? Currently the pattern I can think of is detecting in NotifyPropertyChanged whether the changed property is either Length or Width and, if such is the case, initiate an addional PropertyChanged notification for Area. This, however, requires that I maintain inside NotifyPropertyChanged the dependencies graph, which I feel is an anti-pattern.
So, my question is: How should I code dependency properties that depend on other dependency properties?
edit: People here suggested that Length and Width also call NotifyPropertyChanged for Area. Again, I think this is an anti-pattern. A property (IMHO) shouldn't be aware of who depends on it, as shouldn't NotifyPropertyChanged. Only the property should be aware of who it depends on.

This issue kept on bugging me, so I re-opened it.
First, I'd like to appologize for anyone taking my "anti-pattern" comment personally. The solutions offered here were, indeed, how-it's-done in WPF. However, still, IMHO they're bad practices caused, deficiencies in ther framework.
My claim is that the information hiding guide dictates that when B depeneds on A, A should not be aware of B. For exmaple, when B derives from A, A should not have code saying: "If my runtime type is really a B, then do this and that". Simiarily, when B uses A, A should not have code saying: "If the object calling this method is a B, then ..."
So it follows that if property B depends on property A, A shouldn't be the one who's responsible to alert B directly.
Conversely, maintaining (as I currently do) the dependencies graph inside NotifyPropertyChanged is also an anti-pattern. That method should be lightweight and do what it name states, not maintain dependency relationships between properties.
So, I think the solution needed is through aspect oriented programming: Peroperty B should use an "I-depend-on(Property A)" attribute, and some code-rewriter should create the dependency graph and modify NotifyPropertyChanged transparently.
Today, I'm a single programmer working on a single product, so I can't justify dvelving with this any more, but this, I feel, is the correct solution.

Here is an article describing how to create a custom attribute that automatically calls PropertyChanged for properties depending on another property: http://www.redmountainsw.com/wordpress/2012/01/17/a-nicer-way-to-handle-dependent-values-on-propertychanged/
The code will look like this:
[DependsOn("A")]
[DependsOn("B")]
public int Total
{
get { return A + B; }
}
public int A
{
get { return m_A; }
set { m_A = value; RaisePropertyChanged("A"); }
}
public int B
{
get { return m_B: }
set { m_B = value; RaisePropertyChanged("B"); }
}
I haven't tried it myself but I like the idea

When the Length or Width properties are changed you fire PropertyChanged for Area in addition to firing it for either Length or Width.
Here is a very simple implementation based on backing fields and the method OnPropertyChanged to fire the PropertyChanged event:
public Double Length {
get { return this.length; }
set {
this.length = value;
OnPropertyChanged("Length");
OnPropertyChanged("Area");
}
}
public Double Width {
get { return this.width; }
set {
this.width = value;
OnPropertyChanged("Width");
OnPropertyChanged("Area");
}
}
public Double Area {
get { return this.length*this.width; }
}
Doing it like this is certainly not an anti-pattern. That is exactly the pattern for doing it. You as the implementer of the class knows that when Length is changed then Area is also changed and you encode it by raising the appropriate event.

Then you should raise twice, in Length and Width property setters. One for the actual property and one for the Area property.
for example:
private int _width;
public int Width
{
get { return _width; }
set
{
if (_width == value) return;
_width = value;
NotifyPropertyChanged("Width");
NotifyPropertyChanged("Area");
}
}
People here suggested that Length and Width also call
NotifyPropertyChanged for Area. Again, I think this is an
anti-pattern. A property (IMHO) shouldn't be aware of who depends on
it, as shouldn't NotifyPropertyChanged. Only the property should be
aware of who it depends on.
This is not an anti-pattern. Actually, your data encapsulated inside this class, so this class knows when and what changed. You shouldn't know outside of this class that Area depends on Width and Length. So the most logical place to notify listeners about Area is the Width and Length setter.
A property (IMHO) shouldn't be aware of who depends on it, as
shouldn't NotifyPropertyChanged.
It does not break encapsulation, because you are in the same class, in the same data structure.
An extra information is that knockout.js (a javascript mvvm library) has a concept which accessing this problem: Computed Observables. So I believe this is absolutely acceptable.

Here is a possible implementation of an attribute:
public class DependentPropertiesAttribute : Attribute
{
private readonly string[] properties;
public DependentPropertiesAttribute(params string[] dp)
{
properties = dp;
}
public string[] Properties
{
get
{
return properties;
}
}
}
Then in the Base View Model, we handle the mechanism of calling property dependencies:
public class ViewModelBase : INotifyPropertyChanged
{
public ViewModelBase()
{
DetectPropertiesDependencies();
}
private readonly Dictionary<string, List<string>> _dependencies = new Dictionary<string, List<string>>();
private void DetectPropertiesDependencies()
{
var propertyInfoWithDependencies = GetType().GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(DependentPropertiesAttribute))).ToArray();
foreach (PropertyInfo propertyInfo in propertyInfoWithDependencies)
{
var ca = propertyInfo.GetCustomAttributes(false).OfType<DependentPropertiesAttribute>().Single();
if (ca.Properties != null)
{
foreach (string prop in ca.Properties)
{
if (!_dependencies.ContainsKey(prop))
{
_dependencies.Add(prop, new List<string>());
}
_dependencies[prop].Add(propertyInfo.Name);
}
}
}
}
protected void OnPropertyChanged(params Expression<Func<object>>[] expressions)
{
expressions.Select(expr => ReflectionHelper.GetPropertyName(expr)).ToList().ForEach(p => {
RaisePropertyChanged(p);
RaiseDependentProperties(p, new List<string>() { p });
});
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected virtual void RaisePropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected void RaiseDependentProperties(string propertyName, List<string> calledProperties = null)
{
if (!_dependencies.Any() || !_dependencies.ContainsKey(propertyName))
return;
if (calledProperties == null)
calledProperties = new List<string>();
List<string> dependentProperties = _dependencies[propertyName];
foreach (var dependentProperty in dependentProperties)
{
if (!calledProperties.Contains(dependentProperty))
{
RaisePropertyChanged(dependentProperty);
RaiseDependentProperties(dependentProperty, calledProperties);
}
}
}
}
Finally we define dependencies in our ViewModel
[DependentProperties("Prop1", "Prop2")]
public bool SomeCalculatedProperty
{
get
{
return Prop1 + Prop2;
}
}

Related

Call to NotifyProportyChanged when adding items to List doesn't work, why?

I'm trying to understand why calling the function (code below...) of NotifyProportyChanged from AddNoteToList to update the view whenever item added to list isn't working.
It works great when I'm doing an assignment on the list, but if I'm trying to add items and then call manually the NotifyProportyChanged it doesn't.
I know I should use ObservableCollection to solve the problem, but I would like to know why this implementation I wrote is not doing the job.
public class MainWindowVM : INotifyPropertyChanged
{
public Model.MainWindowModel Model { get; set; }
public List<DataProtocol.Note> _notesListVM;
public List<DataProtocol.Note> NotesListVM
{
get
{
return _notesListVM;
}
set
{
_notesListVM = value;
NotifyProportyChanged("NotesListVM");
}
}
//dp:
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyProportyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
//Command:
public RelayCommand AddNoteCommand { get; set; }
public void AddNoteToList(object parm)
{
string value = parm.ToString();
NotesListVM.Add(new DataProtocol.Note(value));
NotifyProportyChanged("NotesListVM");
}
public MainWindowVM()
{
Model = new PL.Model.MainWindowModel();
NotesListVM = Model.NotesList;
AddNoteCommand = new RelayCommand(AddNoteToList);
}
}
Even though you are raising PropertyChanged, the object instance NotesListVM hasn't actually changed, only its content has. WPF is optimized enough to realize this and do nothing.
If you really wanted to do it your way, you'd need create and assign a new list each time.
As you say, use ObservableCollection instead, which will fire CollectionChanged.
ItemsControl.ItemsSource is a dependency property, and will only register a change when you actually set the value to a different collection instance - sending a PropertyChanged event isn't sufficient.
As you noted, using an ObservableCollection is the correct way to have your bound U.I. controls detect that items have been added / removed from your list of items.

Implementing NotifyPropertyChanged without magic strings [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
typesafe NotifyPropertyChanged using linq expressions
I'm working on a large team application which is suffering from heavy use of magic strings in the form of NotifyPropertyChanged("PropertyName"), - the standard implementation when consulting Microsoft. We're also suffering from a great number of misnamed properties (working with an object model for a computation module that has hundreds of stored calculated properties) - all of which are bound to the UI.
My team experiences many bugs related to property name changes leading to incorrect magic strings and breaking bindings. I wish to solve the problem by implementing property changed notifications without using magic strings. The only solutions I've found for .Net 3.5 involve lambda expressions. (for example: Implementing INotifyPropertyChanged - does a better way exist?)
My manager is extremely worried about the performance cost of switching from
set { ... OnPropertyChanged("PropertyName"); }
to
set { ... OnPropertyChanged(() => PropertyName); }
where the name is extracted from
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
MemberExpression body = selectorExpression.Body as MemberExpression;
if (body == null) throw new ArgumentException("The body must be a member expression");
OnPropertyChanged(body.Member.Name);
}
Consider an application like a spreadsheet where when a parameter changes, approximately a hundred values are recalculated and updated on the UI in real-time. Is making this change so expensive that it will impact the responsiveness of the UI? I can't even justify testing this change right now because it would take about 2 days worth of updating property setters in various projects and classes.
I did a thorough test of NotifyPropertyChanged to establish the impact of switching to the lambda expressions.
Here were my test results:
As you can see, using the lambda expression is roughly 5 times slower than the plain hard-coded string property change implementation, but users shouldn't fret, because even then it's capable of pumping out a hundred thousand property changes per second on my not so special work computer. As such, the benefit gained from no longer having to hard-code strings and being able to have one-line setters that take care of all your business far outweighs the performance cost to me.
Test 1 used the standard setter implementation, with a check to see that the property had actually changed:
public UInt64 TestValue1
{
get { return testValue1; }
set
{
if (value != testValue1)
{
testValue1 = value;
InvokePropertyChanged("TestValue1");
}
}
}
Test 2 was very similar, with the addition of a feature allowing the event to track the old value and the new value. Because this features was going to be implicit in my new base setter method, I wanted to see how much of the new overhead was due to that feature:
public UInt64 TestValue2
{
get { return testValue2; }
set
{
if (value != testValue2)
{
UInt64 temp = testValue2;
testValue2 = value;
InvokePropertyChanged("TestValue2", temp, testValue2);
}
}
}
Test 3 was where the rubber met the road, and I get to show off this new beautiful syntax for performing all observable property actions in one line:
public UInt64 TestValue3
{
get { return testValue3; }
set { SetNotifyingProperty(() => TestValue3, ref testValue3, value); }
}
Implementation
In my BindingObjectBase class, which all ViewModels end up inheriting, lies the implementation driving the new feature. I've stripped out the error handling so the meat of the function is clear:
protected void SetNotifyingProperty<T>(Expression<Func<T>> expression, ref T field, T value)
{
if (field == null || !field.Equals(value))
{
T oldValue = field;
field = value;
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(GetPropertyName(expression), oldValue, value));
}
}
protected string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression memberExpression = (MemberExpression)expression.Body;
return memberExpression.Member.Name;
}
All three methods meet at the OnPropertyChanged routine, which is still the standard:
public virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(sender, e);
}
Bonus
If anyone's curious, the PropertyChangedExtendedEventArgs is something I just came up with to extend the standard PropertyChangedEventArgs, so an instance of the extension can always be in place of the base. It leverages knowledge of the old value when a property is changed using SetNotifyingProperty, and makes this information available to the handler.
public class PropertyChangedExtendedEventArgs<T> : PropertyChangedEventArgs
{
public virtual T OldValue { get; private set; }
public virtual T NewValue { get; private set; }
public PropertyChangedExtendedEventArgs(string propertyName, T oldValue, T newValue)
: base(propertyName)
{
OldValue = oldValue;
NewValue = newValue;
}
}
Personally I like to use Microsoft PRISM's NotificationObject for this reason, and I would guess that their code is reasonably optimized since it's created by Microsoft.
It allows me to use code such as RaisePropertyChanged(() => this.Value);, in addition to keeping the "Magic Strings" so you don't break any existing code.
If I look at their code with Reflector, their implementation can be recreated with the code below
public class ViewModelBase : INotifyPropertyChanged
{
// Fields
private PropertyChangedEventHandler propertyChanged;
// Events
public event PropertyChangedEventHandler PropertyChanged
{
add
{
PropertyChangedEventHandler handler2;
PropertyChangedEventHandler propertyChanged = this.propertyChanged;
do
{
handler2 = propertyChanged;
PropertyChangedEventHandler handler3 = (PropertyChangedEventHandler)Delegate.Combine(handler2, value);
propertyChanged = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.propertyChanged, handler3, handler2);
}
while (propertyChanged != handler2);
}
remove
{
PropertyChangedEventHandler handler2;
PropertyChangedEventHandler propertyChanged = this.propertyChanged;
do
{
handler2 = propertyChanged;
PropertyChangedEventHandler handler3 = (PropertyChangedEventHandler)Delegate.Remove(handler2, value);
propertyChanged = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.propertyChanged, handler3, handler2);
}
while (propertyChanged != handler2);
}
}
protected void RaisePropertyChanged(params string[] propertyNames)
{
if (propertyNames == null)
{
throw new ArgumentNullException("propertyNames");
}
foreach (string str in propertyNames)
{
this.RaisePropertyChanged(str);
}
}
protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
string propertyName = PropertySupport.ExtractPropertyName<T>(propertyExpression);
this.RaisePropertyChanged(propertyName);
}
protected virtual void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler propertyChanged = this.propertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public static class PropertySupport
{
// Methods
public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}
MemberExpression body = propertyExpression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException("propertyExpression");
}
PropertyInfo member = body.Member as PropertyInfo;
if (member == null)
{
throw new ArgumentException("propertyExpression");
}
if (member.GetGetMethod(true).IsStatic)
{
throw new ArgumentException("propertyExpression");
}
return body.Member.Name;
}
}
If you're concerned that the lambda-expression-tree solution might be too slow, then profile it and find out. I suspect the time spent cracking open the expression tree would be quite a bit smaller than the amount of time the UI will spend refreshing in response.
If you find that it is too slow, and you need to use literal strings to meet your performance criteria, then here's one approach I've seen:
Create a base class that implements INotifyPropertyChanged, and give it a RaisePropertyChanged method. That method checks whether the event is null, creates the PropertyChangedEventArgs, and fires the event -- all the usual stuff.
But the method also contains some extra diagnostics -- it does some Reflection to make sure that the class really does have a property with that name. If the property doesn't exist, it throws an exception. If the property does exist, then it memoizes that result (e.g. by adding the property name to a static HashSet<string>), so it doesn't have to do the Reflection check again.
And there you go: your automated tests will start failing as soon as you rename a property but fail to update the magic string. (I'm assuming you have automated tests for your ViewModels, since that's the main reason to use MVVM.)
If you don't want to fail quite as noisily in production, you could put the extra diagnostic code inside #if DEBUG.
Actually we discussed this aswell for our projects and talked alot about the pros and cons. In the end, we decided to keep the regular method but used a field for it.
public class MyModel
{
public const string ValueProperty = "Value";
public int Value
{
get{return mValue;}
set{mValue = value; RaisePropertyChanged(ValueProperty);
}
}
This helps when refactoring, keeps our performance and is especially helpful when we use PropertyChangedEventManager, where we would need the hardcoded strings again.
public bool ReceiveWeakEvent(Type managerType, object sender, System.EventArgs e)
{
if(managerType == typeof(PropertyChangedEventManager))
{
var args = e as PropertyChangedEventArgs;
if(sender == model)
{
if (args.PropertyName == MyModel.ValueProperty)
{
}
return true;
}
}
}
One simple solution is to simply pre-process all files before compilation, detect the OnPropertyChanged calls that are defined in set { ... } blocks, determine the property name and fix the name parameter accordingly.
You could do this using an ad-hoc tool (that would be my recommendation), or use a real C# (or VB.NET) parser (like those which can be found here: Parser for C#).
I think it's reasonable way to do it. Of course, it's not very elegant nor smart, but it has zero runtime impact, and follows Microsoft rules.
If you want to save some compile time, you could have both ways using compilation directives, like this:
set
{
#if DEBUG // smart and fast compile way
OnPropertyChanged(() => PropertyName);
#else // dumb but efficient way
OnPropertyChanged("MyProp"); // this will be fixed by buid process
#endif
}

Need help understanding MVVM Tutorial, RelayCommand

I am reading http://msdn.microsoft.com/en-us/magazine/dd419663.aspx tutorial
i don't understand what the below code is trying to do.
_saveCommand = new RelayCommand(param => this.Save(), param => this.CanSave );
As defined in the realy Command class CanSave should have been a Method with a paramter since it maps to predicate therefore it's correspoding method should have a paramter same is true for action object. Please help understand.
RelayCommand uses functions (more precisely, delegates) passed into its constructor to implement CanExecute and Execute methods.
In this sample two functions are passed. First describes how to save - just call Save method on RelayCommand owner. Another one describes, how to check if saving is possible - just check current state of owner's CanSave property.
In this way you don't have to create your own Command class explicitly.
UPD:
Thanks, but my questions is Save() is of type Action, defined as Action and as per my understanding Save() should have a parameter in order to work. But some reason it is able to work even without a paramter.
Ok, let's look at it closer.
_saveCommand = new RelayCommand(param => this.Save(), param => this.CanSave );
is equivalent of (in syntax of C# v2.0)
_saveCommand = new RelayCommand(
new Action<object>(delegate(object param){ this.Save(); }),
new Func<object,bool>(delegate(object param){ return this.CanSave; }));
So, you create anonymous functions wrap actual methods leaving to you right to use or not to use their own parameters.
If you want to go deeper, the code above is compiled under the hood to something like:
// it is OK to ignore methods arguments.
// So, it's also OK to ignore them in anonymous methods as well
private void Save_Anonymous(object parameter){
this.Save();
}
private bool CanSave_Anonymous(object parameter){
return this.CanSave;
}
....
_saveCommand = new RelayCommand(new Action<object>(this.Save_Anonymous),
new Func<object, bool>(this.CanSave_Anonymous));
Note that compiler can select other strategies for implementing delegates, depending on what values they enclose from surrounding context. E.g. if your anonymous functions referenced some local variables compiler would generate anonymous class that contained those variables and put methods in this class.
Let us simplify it
First off, RelayCommand is not part of WPF. It is a class inside the WPFlight toolkit, and we are free to write our own implementations of it.
It acts as a wrapper on top of the WPF ICommand, and provides two aspects: action and predicate. The predicate part can be used, for example to enable or disable a button based on some condition. The action part shall contain the logic that should run when the command is executed.
As with most concepts, this too has many possible approaches.
Approach 1
Write explicit named methods for action and predicate. Sample code below
class demoViewModel
{
string filename = "";
private ICommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand== null)
{
_saveCommand = new RelayCommand<object>(
action => Save(filename),
predicate => CanSave(filename));
}
return _saveCommand;
}
}
private bool CanSave(string fname)
{
return (!string.IsNullOrEmpty(fname));
}
private void Save(string fname)
{
SaveHelper(fname);//some logic goes inside SaveHelper
}
}
Approach 2
Here we shall use anonymous methods. This reduces many lines of code and makes the whole code more readable.
class demoViewModel1
{
string filename = "";
private ICommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand== null)
{
_saveCommand = new RelayCommand<object>(
action => { SaveHelper(filename); },
predicate => { return (!string.IsNullOrEmpty(filename)); }
);
}
return _saveCommand;
}
}
}
Approach 3
Make use of lambda expressions, well, almost fully
class demoViewModel2
{
string filename = "";
private ICommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand== null)
{
_saveCommand = new RelayCommand<object>(
(objParamForAction) => { SaveHelper(filename); },
() => { return (!string.IsNullOrEmpty(filename)); }
);
}
return _saveCommand;
}
}
}

How to use PropertyChanged to pass trough DataTemplate?

Question is simple: how can I trigger a change on the dataObject without acutaly changing the dataObject, and see this change on the visual?
DataObject:
ProductData : INotifyPropertyChanged
{
private ProductPartData myProductPartData;
public ProductPartData ProductPartData
{
get
{
return myProductPartData;
}
set
{
if (value != myProductPartData)
{
myProductPartData = value;
OnNotifyPropertyChanged("ProductPartData");
}
}
}
}
DataTemplate:
<DataTemplate
DataType="{x:Type ProductData}"
>
<VisualProduct
ProductPartData="{Binding Path=ProductPartData, Mode=OneWay}"
/>
</DataTemplate>
And now in a VM I have:
product.OnNotifyPropertyChanged("ProductPartData");
Problem:
Even if the getter for ProductPart is called when I execute OnNotifyPropertyChanged, the visual is not notified, because is the same instance of the ProductPartData.
How do I trigger a change seen by the Visual without changing the instance?
Thank you,
Daniel,
A solution is to use UpdateTarget() method of the BindingExpression class, this way the target of the binding gets refreshed no matter what; of course, your converter will also be hit - if any. Since I'm guessing you don't have access to your visual in the Product, you could use an attached property and in its callback, you can get the BindingExpression and call UpdateTarget() on it.
Note that I'm using a simple TextBlock as the visual of the data object.
public class BindingHelper
{
public static bool GetRefreshBinding(DependencyObject obj)
{
return (bool) obj.GetValue(RefreshBindingProperty);
}
public static void SetRefreshBinding(DependencyObject obj, bool value)
{
obj.SetValue(RefreshBindingProperty, value);
}
// Using a DependencyProperty as the backing store for RefreshBinding. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RefreshBindingProperty =
DependencyProperty.RegisterAttached("RefreshBinding", typeof(bool), typeof(BindingHelper), new UIPropertyMetadata(false, OnRefreshBindingPropertyChanged));
static void OnRefreshBindingPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs ea)
{
TextBlock elem = o as TextBlock;
if (elem != null)
{
BindingExpression bEx = elem.GetBindingExpression(TextBlock.TextProperty);
if (bEx != null)
{
bEx.UpdateTarget();
}
}
}
}
Also, in your data object that you can create a new bool property(let's name it ShouldRefresh) that is bound to the attached property within the template - this will trigger the AP's property changing:
<DataTemplate DataType="{x:Type local:ProductData}">
<TextBlock Text="{Binding Path=Name, Converter={StaticResource BlankConverter}}"
local:BindingHelper.RefreshBinding="{Binding Path=ShouldRefresh}"/>
</DataTemplate>
So, this way, whenever you want to update the target through binding, you can set:
ShouldRefresh = !ShouldRefresh
in your data class.
HTH.
If you raise a PropertyChanged event and the new value of the property is equal to the value WPF already has, it will simply ignore you. You have a couple of options:
The "fast" way is to set the property to null and then back to the correct value again, ensuring PropertyChanged events are raised each time. It's dirty but it works every time.
The "right" way is to force a binding refresh as discussed in this post by Jaime Rodriguez. Because your visual is data-templated though getting the "dependencyObject" to pass into the call in that post is a little tricky. You may end up needing to use the template's FindName method as discussed in this post by Josh Smith.
We encountered this kind of issue with data coming from a database and converted to a DTO (data transfert object).
Our base class for DTO override Object's method such as Equals() and GetHashCode() as follow:
public override Boolean Equals(Object obj)
{
// Null reference
if (null == obj)
return false;
// Same reference
if (Object.ReferenceEquals(this, obj))
return true;
EntityDTOBase<TEntity> entiteObj = obj as EntityDTOBase<TEntity>;
if (null == entiteObj)
return false;
else
return Equals(entiteObj);
}
public Boolean Equals(EntityDTOBase<TEntity> other)
{
// Null reference
if (null == other)
return false;
// Same reference
if (Object.ReferenceEquals(this, other))
return true;
// No Id: cannot be compared, return false
if (this.id == TypeHelper.DefaultValue<long>())
return false;
// Id comparison
if (this.id != other.id)
return false;
return true;
}
public override Int32 GetHashCode()
{
return this.id.GetHashCode();
}
So the problem was when we load again the same entity from the database, since the ID is the same, some binding were not properly updated.
This particular issue was circumvented by adding an additional virtual EqualsExtended() method which default implementation simply returns true:
protected virtual Boolean EqualsExtended(EntityDTOBase<TEntity> other)
{
return true;
}
public Boolean Equals(EntityDTOBase<TEntity> other)
{
/// Same code as before (except last line):
return EqualsExtended(other);
}
Now in any implementation of our DTO class we can add some logic to make Equals() returning false in some situations, for example by adding a timestamp when data is retrieved from the database :
protected override Boolean EqualsExtended(EntityDTOBase<Act> other
{
if (this.Timestamp != other.Timestamp)
{
return false;
}
return true;
}
Long story short, one way to workaround this issue is to make your class instance look different whenever you want the GUI to update accordingly.
The problem might be that you are returning GuiProductPartData typed myProductPartData with ProductPartData typed ProductPartData? But in any case this shouldn't be like this :)
Also it's not a great practice to have the variable name same as the type, so you shouldn't have a ProductPartData ProductPartData property.
Naming conventions aside (and assuming just typos on the typing) the problem probably resides inside your ProductPartData class. Does it implement INotifyPropertyChanged as well?

WPF doesn't honor Textbox.MinLines for Auto height calculation

I want to have a TextBox which Height grows as Iam entering lines of Text.
I've set the Height property to "Auto", and so far the growing works.
Now I want that the TextBox's Height should be at least 5 lines.
Now I've set the MinLines property to "5" but if I start the app the TextBox's height is still one line.
Try setting the MinHeight property.
A hack to make the MinLines property work
public class TextBoxAdv : TextBox
{
bool loaded = false;
/// <summary>
/// Constructor
/// </summary>
public TextBoxAdv()
{
Loaded += new RoutedEventHandler( Control_Loaded );
SetResourceReference( StyleProperty, typeof( TextBox ) );
}
void Control_Loaded( object sender, RoutedEventArgs e )
{
if( !loaded )
{
loaded = true;
string text = Text;
Text = "Text";
UpdateLayout();
Text = text;
}
}
}
I propose a different solution that properly respects the MinLines property, rather than forcing you to use MinHeight.
First, start with a convenience method to allow you to Post an action to the window loop. (I'm including both one where you need to pass state and one where you don't.)
public static class Globals {
public static void Post(Action callback){
if(SynchronizationContext.Current is SynchronizationContext currentContext)
currentContext.Post( _ => callback(), null);
else{
callback();
}
}
public static void Post<TState>(TState state, Action<TState> callback){
if(SynchronizationContext.Current is SynchronizationContext currentContext)
currentContext.Post(_ => callback(state), null);
else{
callback(state);
}
}
}
Next, create an extension method for TextBox to 'initialize' the proper size based on MinLines. I put this in a Hacks class because to me, that's what this is and it clearly identifies the code as such.
public static void FixInitialMinLines(this TextBox textBox) {
Globals.Post(() => {
var textBinding = textBox.GetBindingExpression(TextBox.TextProperty)?.ParentBinding;
if (textBinding != null) {
BindingOperations.ClearBinding(textBox, TextBox.TextProperty);
textBox.UpdateLayout();
BindingOperations.SetBinding(textBox, TextBox.TextProperty, textBinding);
}
else {
var lastValue = textBox.Text;
textBox.Text = lastValue + "a";
textBox.UpdateLayout();
textBox.Text = lastValue;
}
});
}
The above code handles both bound and unbound TextBox controls, but rather than simply changing the value like other controls which may cascade that change down through the bindings, it first disconnects the binding, forces layout, then reconnects the binding, thus triggering the proper layout in the UI. This avoids unintentionally changing your bound sources should the binding be two-way.
Finally, simply call the extension method for every TextBox where MinLines is set. Thanks to the Post call in the extension method, You can call this immediately after InitializeComponent and it will still be executed after all other events have fired, including all layout and the Loaded event.
public partial class Main : Window {
public Main() {
InitializeComponent();
// Fix initial MinLines issue
SomeTextBoxWithMinLines.FixInitialMinLines();
}
...
}
Add the above code to your 'library' of functions and you can address the issue with a single line of code in all of your windows and controls. Enjoy!

Resources