I have an Address object in my model which has 6 address lines as separate properties. In my Silverlight view I want this to be displayed in a multiline text box and to be updated using databinding.
The View is linked to a ViewModel which has an Address property which is always set. My first thought was to use a ValueConverter which was initially fine as it could take an Address object and pass back a string which is displayed.
My problem arises when I want to ConvertBack the string. I wish to update the existing Address object but cannot find a way to do this. I think you can pass back a new Address object but this is not what I want to happen.
I am on the right track here or is there a better method than using a ValueConverter.
You are almost on the right track here! You are right in your observation that the ConvertBack method would need to create a new Address instance. You cannot obtain a reference back to the original address in your converter, the binding framework does not permit this kind of tight coupling.
How about using MVVM? create a ViewModel that exposes / adapts your Address as a string, basically performing the role of your value converter. When the TwoWay binding updates this string property, your ViewModel can then update the Address that it adapts.
Related
Having to work with a legacy silverlight application I ran into a strange piece of code. The viewmodel has a List dependency property as binding source for the grid. This DP has a default value, an other List that is used globally in the app. This is used to easily share entity data between different parts of the application.
DependencyProperty MyEntitiesProperty = DependencyProperty.Register("MyEntities", typeof(List<Entity>), typeof(...), new PropertyMetadata(Global.Entities));
Now, when the list is changed (on user actions), the global list is repopulated from database but MyEntities is never set explicitly. This does not work: the grid (the binding target) never changes. So its a wrong solution.
I speculate that the idea behind all this could have been been the following: if you have a DP with a given value and you never set a local value for it then the effective value of the DP will be the default value. If the 'underlying' default value is changed, the changes are reflected in the effective value.
If it worked, it was a nice way of sharing data between independent viewmodels without fiddling with property change events and such.
What is wrong here? Is it a big misunderstanding of how DPs work or the idea was ok and some implementation details were missed?
Please comment if something is not clear.
Well, taking also your comment into account, it is a big misunderstanding of how DPs work. Let me explain:
Setting a globally known list as the default value of MyEntities might not be a pattern I recommend, but is technically not faulty and can be done to share a list. MyEntities now holds a reference to this very list.
If you now replace the global list with a new list instance, the old instance does not cease to exist. Your property MyEntities still holds a reference to the old list. The value of a DP is only updated automatically if it is bound via Binding to either an ordinary property that is wired with the INotifyPropertyChanged mechanism or another DP.
Setting a default value happens neither via a Binding to an ordinary property nor via a Binding to another DP, it is just a plain old object reference.
I can think of several ways to correct the situation:
First solution
If the global list implements INotifyCollectionChanged (e.g. ObservableCollection, DependencyObjectCollection) you can - instead of creating a new list instance - just delete the old items from the list and add the new items. The views that have a reference to the list will perform an update as soon as they receive the associated CollectionChanged event.
Second solution
Make sure the Global.Entities list is available and always up-to-date as a public property (wired with INotifyPropertyChanged) on the DataContext of the root view. Now when you want a nested view somewhere deep down inside the UI tree to be connected to this Global.Entities list you can bind it to the root view's DataContext' public list property.
<MyRootView>
... nested views spread across multiple files ...
<MyNestedEntitiesListDisplay
MyEntities="{Binding
Path=DataConext.GlobalEntities,
RelativeSource={RelativeSource AncestorType=MyRootView}}"/>
I have a DataTemplate(well two data templates) that I want to use as views for some
basic form viewmodels(that that contain a value and and boolean indicating whether I want to use the value).
I want to use the datatemplate(s) several times for separate form items. I think the right way to do this is to set it as the ContentControl's ContentTemplate (in that case it will have the same data context right?) but I also want to pass the label string and since the label string is part of the ui and doesn't change it seems wrong to put it in the viewmodel object. How do I give access of the label string to the DataTemplate instance?
Just like its name, a DataTemplate is used to template the Data... For example, if you have a class called MyItem which has a Name and Value and you want this shown in a specific way, you'll set a datatemplate for Item and use it whenever needed.
In your case, you're speaking about having very similar views, with only a minor change between them. This minor change (if I understood your question correctly) is not something that comes from the model or from the viewmodel but something which is entirely view-oriented (a different title for the page, for instance).
If you plan on using a different viewmodel for every view, and each viewmodel has a different purpose - I don't see a problem with adding a Title property to the VM and bind to that too (Remember, MVVM is a set of guidelines, not rules...)
If you still rather have it separated from the viewmodel, then you can use an Attached Property. Create an Attached Property called TemplateTitle, for instance, and have each contentcontrol in each view change it. The label, of course, will bind to that Attached Property.
I'm working on a WPF project and have implemented a very simple way to undo one level of change which works nicely throughout the project except for one case where changes to an object's property reflects in the MemberwiseClone.
What I am doing is to do a MemberwiseClone in my object before adding or editing properties in that object, and then if the user wants to undo, I copy each property from the MemberwiseClone object back into my current object.
Because I am using WPF binding, using the MemberwiseClone is attractive to me because up until now, any change made in a property was not reflected in the MemberwiseClone. This time I have a property in my object that is an ObservableCollection of another object, and what is happening is that if I add an item to the ObservableCollection, it also gets added to the object created by MemberwiseClone and I can never truly undo.
Is there any way around this? Any thoughts you might have on this are welcomed.
Thanks.
According to Object.MemberwiseClone Remarks the object references in your ObservableCollection will be copied but not the referenced object itself. Therefore your undo collection references the same possible changed objects.
You need a deep copy, not a shallow one. Take a look at How do you do a deep copy an object in .Net (C# specifically)?
I have a Silverlight control which has a ListBox showing a series of email addresses. The data source is an ObservableCollection of strings (one per email) in the ViewModel. Simple enough!
I wanted to allow in-place editing of the list, by changing the data template from a TextBlock to a TextBox, with a two-way binding.
The problem is this: How do I validate the user edit is a valid email address?
I don't want to save the bound text to the list unless it's valid. I can't throw an exception as it's bound to a string, so there's no Set method to modify.
The only solution I can think of is to create a dummy class with a single Email property just so I can validate the value. I can't believe that's the best way.
Well you've got bigger problems than just the validation. You can't use TwoWay binding when the source object is a string.
It does make some sense to create an AddressEntry class that has an EmailAddress string property. That way you can make two way binding work and it gives you somewhere to write your validation.
When we use any attached property against any dependency object, I thunk it actually maps the property and the value with the dependency object.
E.g. <DockPanel><TextBlock x:Name="MyText" DockPanel.Dock="Top"/></DockPanel>
Here value "Top" is mapped with DockPanels DockProperty via the dependency object textblock "MyText"
But my question is when is this mapping disposed? The reason I am asking this is the DockPanel's DockProperty is static\shared. So it must be having such multiple mappings Pair (Of value, dependency object) maitained against it in some kind of internal dictionary. (just a guess)
So this must be garbage collected when the dependency object is destroyed.
So now my point is is there any way that I should know IF such attached property diposing is taking place (like some kind of dispairing or dispose event for the given attached property and dependency object)?
Also if such garbage collection doesnt take place then isnt this a memory leak?
Thx
Vinit Sankhe.
As I understand the new property system in the WPF, the DependecyObject itself stores the value.
In your example, this would be the textblock.
Don't get confused as you call a static member - it is supposed to be implemented like:
element.SetValue(DockPanel.TopProperty, value);
So there happens no static field storage.
I think it was created using WeakReference. So removing of empty references takes place periodically.