This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hi, // |
|
|
Hello Corvex, This problem occurs because structs are passed by value -- that is, we receive a *copy* of the Size structure in your class, rather than a reference. Consequently, our data binding expressions end up binding to (and modifying) that copy rather than the original values. We will have a look at whether we can address this using TypeConverter's instance creation support, or some other way. In the meantime, you should be able to create your own editor by specifying a PropertyEditor, or, if you are using a recent nightly, a TypeEditor. (TypeEditors worked only for class types in RTM, but now support struct types as well.) This will allow edit-in-place behaviour, though it will not help with expandability. Thanks for drawing this to our attention! |
|
|
Hello Corvex, I have committed experimental support for this and it will be in nightly builds dated 19 Nov 2008 and above, available from http://www.mindscape.co.nz/products/wpfpropertygrid/nightlybuilds.aspx or from the store after about 0230 GMT. With this build, you will be able to edit struct members within the grid. Structs will expand automatically. If you specify a TypeConverter on the struct definition, that will be used to recreate the struct, but you don't have to: the grid will use the default constructor (and copy values using reflection) if there is no type converter. (In the latter case of course the members must have setters.) There are a couple of limitations: 1. We do not support expandable editing of structs in a multiple-selection situation. That is, if you have multiple objects selected, and the intersection of their properties contains a record-type struct, it will not be shown as expandable. 2. If you supply a TypeConverter, it must be on the struct *type*, not on the property. E.g. if you are displaying a Person, who has a Hat property of type HatDimensions, and HatDimensions is a struct, the TypeConverter must be on the HatDimensions struct, not the Hat property. Please let us know about any bugs or problems you run into. |
|
|
Hi Ivan,
Thank you for your infos. I wil try a new build. It also directed me to an alternative solution. The problem was that I wanted to edit to struct’s properties separately, using WPF elements with datatemplate bindings to struct’s fields, like a textbox to MySize.Width in the example above. If a value in such textbox was edited the struct MySize still doesn’t know that it has been changed. In order to acknowledge the struct we need to assign a new, updated, value to the entire struct. I used the parameterized converters in XAML for a solution. Just in case if someone will need it too: I defined a custom type editor for MySize type and set its EditorTemplate to the following DataTemplate:
<local:MySizeConverter x:Key="converter_mySize"/> <DataTemplate x:Key="MyEditor"> <StackPanel Orientation=”Horizontal” > <ms:TextBox Text="{Binding Path=Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource converter_mySize},ConverterParameter=Width}" /> <ms:TextBox Text="{Binding Path=Value,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource converter_mySize},ConverterParameter=Height}" /> </StackPanel> </DataTemplate> The trick is in the code of converter_mySize that regulates all bindings and updates according to the incoming parameter’s value:
public class MySizeConverter : IValueConverter |
|
|
Hello Ivan, I have tried the build dated 21 Nov but found no change in a work with the structs compare to the previous version. I attached here the solution files that I used to test it, with a code similar to one in my first post. After runing the solution, the tested struct appears in PG, however, editing its member does not update values in the parent class, containing the struct. Would you mind to look, please, I am afraid that I am missing something. Thanks in advance!
|
|
|
To add to this in regards to the nightly builds. The nightly build for trial versions seems to be up to date. However, the night builds for licensed copies dates back to Nov 11, 2008 and I believe this is not up to date as it also does not contain changes Ivan mentioned in a memory leak thread I posted. Do licensed users download the trial version while waiting for a new release of the commercial copy? |
|
|
Hi Klaus, The nightlies for the combo versions of our products is now updated - there is currently an outstanding code change to our nightly build process to automate the nightlies for purchases of our WPF combo products which I will resolve today. Please try the updated nightly build now. Kind regards, John-Daniel Trask |
|
|
Hello Corvex, You are not missing anything. I am afraid we had a regression here -- while doing some work for another customer, we inadvertently made a change that broke the expandable structs behaviour and our tests failed to catch this. I have fixed the regression and the fix will be in nightly builds dated 25 Nov 2008 and above. We really appreciate your taking the time to provide us with the repro case and we're sorry for this slip-up. |
|
|
Hi Ivan, Thank you, I used the lattest build and the structs are working now. However, there are a couple of strange things that I noticed. Firsly, every time when I expand the struct in PG, I receive a warning in the VS output panel: System.Windows.Data Warning: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Mindscape.WpfPropertyGrid.PropertyGrid', AncestorLevel='1''. BindingExpression:Path=SelectedGridItem; DataItem=null; target element is 'TreeListViewItem' (Name=''); target property is 'NoTarget' (type 'Object') This appears in the project code that I attached here, in forum, earlier. Secondly, I can not realize how to update struct's values in PG if they are expanded and shown in PG but changed not in PG. The INotifyPropertyChanged mechanism does not seem to work neither in struct type nor in a parent object, contaning the struct. For example, I want to have the Width and Height values linked in the mySize structs. So when Width is changed I want to re-estimate Height field as 2*Width. Naturally, I change the Height in the setter for the Weight property but then new value is not refreshed on the screen. Calling NotifyPropertyChanged("Height") has no effect as well as calling NotifyPropertyChanged("Size") in the parent object. Only collapsing the struct in PG and expandind it again brins a new value to view. Thank you in advance for your help!
|
|
|
Hi Corvex, Regarding the binding error, we have noticed this and we realise it is annoying but we believe it to be otherwise harmless. We have logged a bug for it but because it doesn't appear to affect the behaviour of the grid we are assigning it as low priority. Hope you can live with it for now at least! Regarding the property change notifications when you modify the struct from code, I have done a bit of experimenting and this appears to be a limitation of the WPF binding infrastructure (specifically the PropertyChangedEventManager). It is probably related in some way to boxing and copying. However I am seeing a different behaviour from you when it comes to raising a change notification in the *parent* object. In my parent object (a Person), I have a HatDimensions property which is a struct. When the HatDimensions property is set, I hook its PropertyChanged event, and my handler raises the PropertyChanged event for the HatDimensions on the Person object. (This should be similar to your NotifyPropertyChanged("Size").) Thus: public HatDimensions HatDimensions With this code in place, I see the cells for the expanded struct properties update correctly when I modify the properties of the HatDimensions -- no need to collapse and re-expand. It sounds like you may be raising the notification for Parent.Size before Size.Height has been set to its new value. Could that be the case? If you use the pattern above and push changes through the Height setter (rather than modifying Height_ directly) then you should be okay. Also note that if you are using a TypeConverter which returns true from GetCreateInstanceSupported then we will be recreating your object using the dictionary of *existing* values (except for the one which was modified in the grid), so it will be up to your TypeConverter to realise that it has to throw away the provided height (the old value) and infer a new one. (However I don't believe you're using a TypeConverter at the moment, and this would normally be used only for immutable structs.) If you still see problems with this then could you send me a repro case please? I know you have already provided us with sample code but this did not include your INotifyPropertyChanged support. (Please note that WPF does *not* support the NotifyParentPropertyAttribute. You *must* use INotifyPropertyChanged.PropertyChanged to raise property change notifications.) |
|
|
Hi Ivan, I really appreciate that you spending your time trying to help me, thank you! I've looked at the notification mechanism in my sample code and found that it does not work as I expected. For my objects and structs I implement the INotifyPropertyChanged Interface in the same way as in example in MSDN: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx It includes the NotifyPropertyChanged(string) to raise the OnPropertyChange event if there are listeners. I made an sample project with it and attached it here. The problem there is not just with the structs but with the plain properties as well. It seems like the PG does not subscribe for PropertyChanged events in my parent class when I assign it to SelectedObject(s). I believe, if I solve this, my structs will be updated normally. I would like to ask if you can attached the full source of your example above so i can compare it with my code? Thank you in advance!
|
|
|
Hello Corvex, There are a couple of issues here. First, "It seems like the PG does not subscribe for PropertyChanged events in my parent class." This is because your parent class does not implement INotifyPropertyChanged. The grid does not search for a PropertyChanged event by name; instead, it looks for an implementation of the INotifyPropertyChanged interface. Thus, you need to change your class declaration from: public class MyClass : object to public class MyClass : object, INotifyPropertyChanged (Specifying object as the base class is redundant, by the way, since that is the default in C#, so you can omit this.) Second, the reason we are not picking up changes to the struct members when they are made through code is, as previously mentioned, that the WPF binding infrastructure does not seem to handle struct members well, probably due to boxing and copying issues. As previously mentioned, the workaround is for the parent class to raise a change notification for the *entire struct* when any struct property changes. So you need to modify MyClass.Size as follows: public mySize Size and add a constructor: public MyClass() What this means is that when you change the mySize.Height property, the parent MyClass object will receive a property change notification for Height, and will itself raise a property change notification for Size. Since MyClass is a class, the WPF binding infrastructure can handle notifications from MyClass. It therefore lets us know that MyClass.Size has changed and we can reread the values. This also takes care of linked changes. For example, add the following member method to MyClass: public void SetWidthTo(int width) and change your Button_Click handler to call this method: private void Button_Click(object sender, RoutedEventArgs e) You will see that the grid shows 5 for the width and 50 for the height. (Why is SetWidthTo a member of MyClass rather than mySize? Because if it were a member of mySize, and you called MyClassInstance.Size.SetWidthTo(5), it would operate on a stack-based copy of MyClassInstance.Size, not the actual member of MyClassInstance. The .NET runtime would translate the C# into "load MyClassInstance.Size into a local variable, and call SetWidthTo(5) on that." But because mySize is a value type, the local variable gets a *copy* of Size, not the original. Whereas a member method of MyClass can operate on the mySize instance stored within the MyClass instance.) I've attached an updated version of Window1.xaml.cs (which was the only one of your files I had to change) -- if you compare it to your original you should see hopefully see how all this stuff fits together -- if not feel free to ask for further clarification! |
|
|
Hi Ivan, I was just my stupid mistake- I forgot to add INotifyPropertyChanged descriptor to MyClass. Now I've done it and the notifications work updating everything including structs. Thank you for clarifying this topic!
|
|