Passing large sets of data into user controls - wpf

Since UserControls in WPF have to have parameterless constructors, what is the correct way for supplying them with fairly complex data that is needed "near" the time of construction. I have tried using dependency properties for this, but am running into issues with the Visual Studio designer balking at attempts to pass stuff like a Dictionary<string,MyObject> into an IDictionary<string,MyObject> typed dependency property. At some point it must want an exact compile time type match, or the XAML doesn't come up in the designer, although the application executes just fine.
Basically, I want a good way to pass in stuff that I would normally pass into a constructor into a User Control. What's the best way?
Update:
The user control in question will always be created from XAML, so having a non-parameterless construction in addition to the parameterless one is not an option.
Update 2:
An interesting idea would be to have something accessible from the parameterless constructor that I can get my initialization data from. Something like perhaps asking the question: Which of my already initialized ancestors implements an IMyDataProvider interface? This could be similar to how the relative source to ancestor type bindings work, except done programatically from the user control constructor.

If the only problem you are having is passing in derived types, you can pass in instead a simple concrete container class containing your complex types as properties. For example:
public class InitializationData
{
public IDictionary<TKey, TValue> Dictionary { get; set; }
}
This level of indirection will overcome the limitations of the Visual Studio designer.

A couple of options.
1, You can have more than one constructor, a parameterless one for when your control is created via XAML and another that takes a set of parameters for when you create it directly via code. If you definitely don't want to create your instance via code then...
2, Add a public property that only has a setter and is defined with the exact dictionary type you want to pass in and use as the data for initializing the control. The property only needs to be called once. You can have other properties that are getters/setters that expose that initialized data in order more generic types.

Related

Master-Detail relation with inheritance in a WPF MVVM application

I think this is a rather basic question, but I haven't been able to find an answer to this.
I have the following scenario:
Without using any form of EntityFrameWork I have a PersonViewModel and a PersonDetailsViewModel, which inherits from the PersonViewModel. In my PersonView I display a collection of PersonViewModels in a grid. I have properties like Name, DateOfBirth etc, as columns. When I double click on a person a PersonDetailView pops up which is bound to a PersonDetailsViewModel. In this View there is extra information shown about the person (Gender, SocialSecurity number etc.). The user I allowed to edit all properties.
Now I wonder what the best/common approach is to make sure that the PersonViewModel gets updated with the values that have been editted in the PersonDetailsViewModel.
I can think of several options. For starters I could opt for not using different ViewModels, but instead use PersonDetailViewModels to show in the grid, but the downside to that is that I would need to retrieve a lot of unnecessary data per ViewModel.
I can also synchronise the corresponding properties after the PersonDetailsView closes.
The third option I can think of is that instead of inheriting from the PersonView I will include a property in PersonDetailsView that is of the type PersonView and expose it's properties and use it for binding in the PersonDetailsView. All other extra properties in PersonDetailsViewModel will then be retrieved in it's constructor.
In my experience, the best way to update view models who share the same data is to use the Mediator pattern to send a notification message that the data has updated.
In order to have a good object oriented design we have to create lots
of classes interacting one with each other. If certain principles are
not applied the final framework will end in a total mess where each
object relies on many other objects in order to run. In order to avoid
tight coupled frameworks, we need a mechanism to facilitate the
interaction between objects in a manner in that objects are not aware
of the existence of other objects.
Source http://www.oodesign.com/mediator-pattern.html
It is syntactically important to your design that the notification says what has happened (the data was updated) and not what should happen (data gets reloaded) because that response may not stay the same as the system evolves.
Often, common MVVM libraries have Mediator implementations in them. For example, Prism's EventAggregator.
in Addition to Sheridans answer. i would expose the Detail as a property of type PersonDetailsViewModel
public class PersonViewModel
{
public PersonDetailsViewModel Detail {get;set;}
}
then your xaml looks simply like that
<TextBlock Text="{Binding Detail.Gender}"/>
EDIT1: in addition to the comments above
i would not do any inheritence (thats what user1087702 wrote in his question). i would simply create 2 classes: PersonVM and PersonVMDetail. And if the request is, to show Details from my person object, why in hell shouldn't i just create a public Property in my PersonVM class of type PersonVMDetail - to fullfill this request?
The simplest way to achieve your requirements would be to add a constructor to your PersonViewModel class that takes a PersonDetailsViewModel instance and updates its common properties:
public PersonViewModel(PersonDetailsViewModel personDetailsViewModel)
{
Name = personDetailsViewModel.Name;
...
DateOfBirth = personDetailsViewModel.DateOfBirth;
}
...
PersonViewModel = new PersonViewModel(PersonDetailsViewModel);
Of course, this doesn't have to be in the constructor... it could just as easily be a method in the PersonViewModel class, or even a helper method in a separate Factory Pattern class, it's up to you.

Role of Parameterless constructor in WPF (XAML)

I've been reading an online tutorial on WPF, there I read a line
"All classes in WPF have parameterless constructors and make excessive usage of properties. That is done to make it perfectly fit for XML languages like XAML."
I examined above words by creating a custom class with one parameterized constructor and encountered error "Type 'custom_class_name' is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter."
I just wanted to know a specific detailed reason, how parameterless constructors help achieving this.
The WPF Framework uses the parameter-less constructors to instantiate all of the objects that we define in our XAML pages when it builds the visual tree. If it tries to instantiate an object that does not have a public parameter-less constructor, then you will throw this Exception. If you were to add a parameter-less constructor to your object and try again, then this Exception should disappear.
Please also look at the Type '{0}' is not usable as an object element page at MSDN.
Also, I believe that classes without any constructors in .NET are automatically provided with 'invisible' parameter-less constructors by default. However, if we add a parameterised constructor, then no parameter-less constructor will be provided automatically.

Generic WinForms ListView (with regards to Tag)

I'm trying to improve on a Winforms project where datatable rows are stored in the Tag property of ListViewItems. When the datatable is refactored to List<T> (or actually classes containing lists) it would help immensely if I could make the Tag property generic by using a subclass of ListView.
In the best of worlds, I'd want the Tag property to be replaced by a public T Tag{get; set;} that wraps base.Tag and casts it.
Second best would be Obsoleting Tag and providing a new property like TypedTag working like above.
I think this would involve subclassing or composite aggregation of at least ListView, ListViewItemCollection, SelectedListViewItemCollection and ListViewItem, and I'm not sure how to do it.
In short:
ListView<Employee> lvwEmployees;
should result in this being possible:
Employee selected = lvwEmployees.SelectedItems[0].TypedTag;
And give a compilation error for this:
DataRow selected = lvwEmployees.SelectedItems[0].TypedTag;
Is it possible? Is it already done?
Project is dotnet 2.0 but I think I'll try to have it upgraded if it helps this matter.
EDIT: It turns out that the owner constructor argument is all a certain collection needs to hook up to the inner collection. Hence the following works:
ListView a = new ListView();
a.Items.Add("Hello");
Assert.AreEqual(1, new ListView.ListViewItemCollection(a).Count);
This makes it rather easy to create a generic tagged ListView. I'll post a complete solution later. :)
EDIT2: Here's the solution:
http://thecarlr.blogspot.com/2010/11/generic-listview.html
EDIT3: For designer support, just add a non generic subclass and use that.
Example: If you intended to use ListView<Employee> in the form, create a ListViewEmployee : ListView<Employee> in another file, and use ListViewEmployee in the form.
The easiest way to add one of theese listviews would be to add a normal listview to the form, and then change it's type in the source files. (And if you don't know where it's declared or instantiated, find out or use the normal listview instead.)
You made the wrong class generic. SelectedItems[0] is a ListViewItem, not a ListView.
There isn't anything you can do to change the type of the Items and SelectedItems properties. You can certainly derive your own class from ListViewItem and just add the property you want to store. No need for another Tag property. You'll have no trouble adding them but you'll need to cast back to your derived class when you retrieve them back from the Selected/Items collection.
In general, avoid this kind of code by using the ListView only as a view of your model. The ListViewItem.Index should then always be good to get a typesafe reference back from your model.
Here's the solution:
http://thecarlr.blogspot.com/2010/11/generic-listview.html
Enjoy :)
/Carl
VS Designer simply cannot handle abstract or generic controls (not for want of asking).
One way around that limitation is to write a type safe wrapper around a standard ListView.
Something like this:
public class TypedListView<T> where T : class
{
public TypedObjectListView(ListView lv) {
this.lv = lv;
}
private ListView lv;
public virtual T SelectedObject {
get { return (T)this.lv.SelectedItems[0].Tag; }
}
// Lots more methods/properties
}
You create a normal ListView in Designer, and then when you wanted to access it, you create and use your adapter instead. Like this:
var typedListView = new TypedListView<Employee>(this.listView1);
Employee selectedEmployee = typedListView.SelectedObject;
You would need to provide a typed version of every ListView properties or method you wanted to use.
The ObjectListView project takes this approach to create a TypedObjectListView which does exactly what are you asking for.

Delayed "rendering" of WPF/Silverlight Dependency Properties?

Is there a way to know the first time a Dependency Property is accessed through XAML binding so I can actually "render" the value of the property when needed?
I have an object (class derived from Control) that has several PointCollection Dependency Properties that may contain 100's or 1000's of points. Each property may arrange the points differently for use in different types shapes (Polyline, Polygon, etc - its more complicated then this, but you get the idea). Via a Template different XAML objects use TemplateBinding to access these properties. Since my object uses a Template I never know what XAML shapes may be in use for my object - so I never know what Properties they may or may not bind to. I'd like to only fill-in these PointCollections when they are actually needed.
Normally in .NET I'd but some logic in the Property's getter, but these are bypassed by XAML data binding.
I need a WPF AND Silverlight compatible solution.
I'd love a solution that avoids any additional complexities for the users of my object.
Update
One way that I've found to do this is using Value Converters. In my situation I had multiple point collections. There was a main dep. property that contained the usual shape of the data. Two alternate shapes were needed for reuse in other areas/contexts.
At first I had 3 dep. props. But, I could have just had one property (the usual shape) and used a value converted to transform the points into my other 2 desired shapes. Doing this I only make the one set of points in the control. The expense of transforming points to the secondary shapes is only incurred when used. Now my main control doesn't need to anticipate how data needs to look for every possible template thrown at the control - now its the template designers problem.
Update 2
Certainly INotifyPropertyChanged and regular properties are the recommended way to handle this.
You don't necessarily have to use dependency properties to enable data-binding. However, you then have to implement INotifyPropertyChanged if changes at the source should be propagated to the target of the binding. A "normal" .NET property is easy to lazy load perhaps like this:
PointCollection points
public PointCollection Points {
get {
return this.points ?? (this.points = CreatePoints());
}
}
PointCollection CreatePoints() {
// ...
}
I'm not sure how you can fit INotifyPropertyChanged into your control, but it sounds a bit strange that your control supplies data to other parts of the system. Perhaps you need to create a view-model containing the data that you then can let your control data-bind to.
If I paraphrase your question to
How do I get notified when dependency property is changed?
will this be correct? I draw this from your phrase "Normally in .NET I'd but some logic in the Property's getter, but these are bypassed by XAML data binding".
If I'm correct, then you can register your own property changed callback. It's always called. Doesn't matter who caused the change binding, style or trigger. The following code snippet is taken from MSDN Article "Dependency Property Callbacks and Validation":
public static readonly DependencyProperty CurrentReadingProperty =
DependencyProperty.Register(
"CurrentReading",
typeof(double),
typeof(Gauge),
new FrameworkPropertyMetadata(
Double.NaN,
FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(OnCurrentReadingChanged),
new CoerceValueCallback(CoerceCurrentReading)
),
new ValidateValueCallback(IsValidReading)
);
public double CurrentReading
{
get { return (double)GetValue(CurrentReadingProperty); }
set { SetValue(CurrentReadingProperty, value); }
}
Your takeaway here is OnCurrentReadingChanged() method. Hope this helps :).

Are value converters instantiated per-binding in WPF?

Is a separate WPF value converter object instantiated for each binding that a particular value converter class is used in?
I am trying to create a two-way bit-to-boolean value converter. I would like to be able to bind a bool property (such as IsChecked) to a bit in a value type (like a ushort). I'm using the converter's parameter arguments to specify the bit. Implementing the ConvertBack() method is easy, but Convert() is little trickier.
In Convert() I need to know what the value of the entire ushort is so I can toggle just the single bit I am interested in. I was thinking of just using a member variable in my value converter class to temporarily store this whenever ConvertBack() is called, thus leading to the above question: does each binding get its own value converter instance?
If you use a converter defined in your resources, it will be shared amongst your properties.
If you need unique converters:
If you create a specific converter for a property, however, it will not be shared. Either option is workable. You can even use multiple converters (of the same type, with different keys) in your resources, which will create unique instances.
Create a constructor and destructor in your converter and set breakpoints within to tell for sure. I just created a simple example and it looks like only one converter was created for my multiple viewmodels that were using the constructor

Resources