I have a rather strange need:
the composition of a View depends from data from the ViewModel. But how to pass these parameters from the ViewModel before the InitializeComponent() call?
Maybe I have to explain better: I have to define some measures for a door component, and the number and name of these variables depends on the data in the ViewModel (I show only two variants - there can be 0, 1 or 2 couples of variables, both external and internal):
It is absolutely no problem building my views depending on only two parameters, but what is the right way in MVVM to do something like this?
This is only the first time I encounter such a problem, but it will be common issue in my WPF business applications and one of the possibilities that I have from building my views in code.
Thank you for any hint!
Not quite sure I understand where the problem is. The visibility of each pair can be bound to a boolean property in the VM, so after you've fired up the VM, the property can be set to true for each pair to be shown, and the appropriate controls become visible.
If there was an infinite possible number of pairs, you'd probably do something fancy with a dictionary or something like that, but since it's precisely 0, 1 or 2 I'd keep it simple with two properties, Pair1Visible and Pair2Visible and then a boolean to visibility converter to bind to the controls on the View.
the problem is that the View has to be built depending on these two values of the ViewModel:
if there is only one value pair, the View contains only 2 textboxes (the minimum) and if there are 4 pairs, the View contains 4x 2 textboxes.
So the View needs to be read the parameters from the ViewModel before actually building the controls.
And this is a very common scenario in my applications: depending on the person that is using the application controls are shown or not, or sometimes it depends on the type of data if controls are there or not.
Maybe this comes from the way you build your views in code, but from here it looks fairly normal in that you need to hide/show controls based on the contents of the VM.
So build the view with the maximum number of pairs of boxes (ie all 4 pairs), but with the visibility of each pair tied to a boolean value in the VM. So when the View is being constructed, the property value will automatically be false (the VM isn't connected to the View yet), so none of the 4 pairs will be visible. Once the VM is running and connected to the View as its DataContext, then you can set the visibility of each pair depending on the data in the VM - as you set each property to true for those pairs that are to be shown, the controls become visible on the View.
Visually you'll get an effect of a slight pause as the View shows with just space where the textboxes are, then as the VM gets its data and sets the properties the controls become visible.
The other way would be to send a message from the VM once it's ready - the View can intercept that message and call a method to set up the textboxes either referencing the VM as necessary (at that point you know the VM is available through the DataContext), or else by including the required parameters as data within the message. That way you don't need to hide/show the controls. However I think that straight forward binding to the VM ought to be able to handle it.
Whatever works best for you. Though I still don't see why you can't use a normal binding to the visibility. This pattern of showing/hiding controls in a View based on values in the VM is completely standard.
I prefer the message method because the window changes the appearance completely based on the number of value pair. This is true not only for the names of the values, but also for the labels on the View.
Therefore I prefer to build the window contents when the message from the ViewModel comes in.
With WPF I'm able to build very, very flexible layouts....
Fair enough. I think it may come more naturally for me to do it the binding way because I also keep all text that's used in my views in the VM. All labels are already set by binding to VM properties, so changing labels on the fly is very easy.
In my VO applications, sometimes I move controls around based on the contained data or on the current user.
A sample is the article input mask: if the program is started in the Italian version, the Italian description is before the German one, and if the program is started in the German version, the Italian description field is showed below the German one (because for everyone it is important to have its own mothers language first).
I have no doubts that this is possible also with DataBinding, but I feel it is more natural to have layout logic in the View itself.
And the next step are completely dynamic windows, where the ViewModel dictates the controls that are shown on the View (in my VO applications, such a window is used over and over and saves a lot of time and code)
did you ever tried ValueConverters? You can use them to convert for example numerical values to logic and bind to visibility.
Why not use two panels wich double the labels and text fields. One with italian first and german second, the other the other way. Bind text fields and labels on both panels to the same properties. Then bind visibility of panels to what you want.
And of course it does make any difference doing it in code or via XAML.
personally I don't like graphical windows editors, and specially for WPF I feel a GUI editor limits the dynamic possibilities too much.
I prefer using a more data driven approach, and therefore I prefer to build my windows in code like most HTML guys.
P.S. this is the last time I'm trying to explain why I use the code based approach. I don't expect that others follow my way - but maybe it could be useful for some special need.
And another thing: in the Holy Bible there is a saying: "the Sunday is made for the people, and not the people for the Sunday". Patterns and rules are there to help us, not to make our life too complicated. Therefore I don't have any problem to break a rule sometimes when I know why.
But remember that many others read our postings so we need to get things as right as possible for them too.
Did you explore using a 'UserControl' which can then be instantiated (more than once when required), and placed on one or more Tabs of a Tab Control. This will increase the 'real estate' or form area without need to resize and re-jiggle the rest of the form and its controls - no matter how many tabs you require..
'UserControl's go in 'ContentControl's and all your controls on the UC can be data bound as easily as the main form.
This way you could even have more than one style of UC and select which you want to display at Initialization time.