I need help with a change of perspective.
I got stuck trying to approach UWP in a way I used to do in WPF regarding a MVVM pattern for managing UserControls dynamically.
I naturally tried to perform the same pattern in UWP but got stuck on various things like UWP not supporting 'x:Type' ...
Situation is; time to rethink this approach and look for a new direction. Seems I'm forced to abandon to use implicit binding in a similar fashion to the WPF pattern, using the Content property of a ContentPresenter and a VM property 'of type Object', which maintain a selected ViewModel. It was a simple and clean approach for matching up the correct View automagically with the VM set in ActiveViewModel.
the below was such a simple way of managing many views all over the place, odd MS not fixing this? But, back to the big Q: what now in UWP!?
<ContentPresenter Content="{Binding ActiveViewModel}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:OneViewModel}">
<local:OneView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:TwoViewModel}">
<local:TwoView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
What Shall I do instead of this!? Anyone found a new efficient way of doing it? I got stuck in my stubborn mind and need someone to kick my butt so I go forward. Getting to old to change, but due to this profession it seems I constantly have to. :)
Looking at the DataTemplate documentation, there's a paragraph explaining the situation which you are trying to figure out.
For advanced data binding scenarios, you might want to have properties
of the data determine which template should produce their UI
representations. For this scenario, you can use a DataTemplateSelector
and set properties such as ItemTemplateSelector to assign it to a data
view. A DataTemplateSelector is a logic class you write yourself,
which has a method that returns exactly one DataTemplate to the
binding engine based on your own logic interacting with your data. For
more info, see Data binding in depth.
Here, you have an example on how you can select distinct DataTemplate for items in a control such as a ListView based on defined conditions.
Your situation is a bit different from the one described above, but the solution should be within what is explained above.
Create a class which derives from DataTemplateSelector, and override the SelectTemplateCore methods exposed by it, where you define the logic of what DataTemplate should be selected for the specific presented object.
This Derived class should expose properties of type DataTemplate, which identify each single DataTemplate template object, you pretend to be able to choose from.
Just as in the example, you are probably better of by defining the DataTemplate resources on an higher level object, such as the Page itself.
Instantiate your DataTemplateSelector Derived class in XAML as a resource and set each of the properties exposed above of type DataTemplate to the analogous DataTemplate static resource.
Utilize the ContentTemplateSelector dependency property, by setting it your custom DataTemplateSelector.
With this logic, it should be possible to have your ContentPresenter decide correctly between which DataTemplate it should choose from, based on your required UI logic.
Related
can someone explain to me what this code in a App.xaml does, especially the logic:AppDataModel part. AppDataModel is Class in the Project.
<Application.Resources>
<logic:AppDataModel
x:Key="TheViewModel" />
<x:String
x:Key="AppName">Master app</x:String>
</Application.Resources>
This markup, when parsed, creates two entries in the Application.Resources dictionary. They key "TheViewModel" is tied to a new instance of AppDataModel and the key "AppName" is tied to a string initialized to "Mater app".
To go beyond your question, the reason you do this in XAML is to co-locate (keep together) your UI code and some instance data, loosely speaking. The biggest example is wanting your UI to always have a particular view model that it binds to. This can be achieved, as I assume from the markup you posted, like you're doing. Creating a view model object in the resources for a given control, window, or app and then assigning it using {StaticResource TheViewModel} will keep you from having to muddy up your code-behind or your view model with binding code.
Hope this helps!
These xaml lines add items to the Resources dictionary of the current application:
Application.Current.Resources["TheViewModel"] = new logic.AppDataModel();
Application.Current.Resources["AppName"] = "Master app";
Example:
<DataTemplate x:DataType="FooEntity">
<Grid Background="{x:Bind MyClass.MyStaticBindingMethod(???)}" />
</DataTemplate>
It’s easy enough to pass in properties of the entity, but I can’t see a way to pass in the instance itself. Is this feature not supported? I could store a reference to this in FooEntity with a property called Instance (for example), and then go MyClass.MyStaticBindingMethod(Instance), but just want to make sure there isn't a cleaner way.
Relevant docs: https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/x-bind-markup-extension
You cannot pass the instance itself onto a DataTemplate.
The DataTemplate is only responsible for describing the visual structure of a data object and therefore its not part of its job to hold a explicit reference to any CLR object.
DataTemplate is defined to extend the visual structure of data objects, such as GridView/ListView, and those already handle the possibility of referencing to Collections, by setting the ItemsSource dependency property. Taking advantage of this, the DataTemplate simply exposes the customization of your visual structure. However this visual structure should be followed with the necessary bindings, to achieve your desired custom behavior.
If you are dealing with x:Bind, you will have to set the x:DataType, to the type of the Collection which you are setting as the Control ItemsSource, because the compiler needs that information at compile-time.
That is not a problem for Binding because those are evaluated at runtime, with the help of reflection.
I am not sure if I understand correctly, but to bind this, meaning the entity directly, you can just use empty binding:
Background="{x:Bind}"
or
Background="{Binding}"
This however means that FooEntity should derive from Brush so that it is compatible with Background type.
I have looked at various examples and read about attached properties. However it is still not clear to me why they are required or better. Look at this example:
<DockPanel>
<CheckBox DockPanel.Dock="Top">Hello</CheckBox>
</DockPanel>
DockPanel.Dock is an attached property and it is clear what the intention is: not very element should have or need an individual property that would allow it to define its docking behavior. Same goes for grid's row and columns definitions. But why not express things like this instead:
<DockPanel>
<Docked Location="Top">
<CheckBox>Hello</CheckBox>
</Docked>
</DockPanel>
Similar would be possible for grids with row and column tags.
Was this a pure design decision or are there other reasons that make attached properties the better or the only solution?
Your example might be applied for just one case, even frequent, but you should not rely on just one attached property.
Suppose, for instance, that you wish to mark more than just one attached property, as follows:
<DockPanel>
<CheckBox DockPanel.Dock="Top" TextBlock.FontSize="16">Hello</CheckBox>
</DockPanel>
How messy would be the equivalent "encapsulated" way?
I myself would add another viewpoint, despite is just mine. The XAML notation often denotes the objects structure: an element represents a class (instance), whereas an attribute a property. Your pattern would fight against the ability to set a property as follows:
<DockPanel>
<DockPanel.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY=3" />
</DockPanel.RenderTransform>
</DockPanel>
This is a particular element pattern which denotes an alternative way to define a property (e.g. RenderTransform) content (i.e. the actual transform instance).
UPDATE: I'd also add another thing about what should be inserted as child of a certain container (the DockPanel in your example). The "Docked" should be an actual child or just a virtual container being not part of the visual/logic tree? Then , supposing walking up the visual/logic tree, should you find this element or not? If not, in which way should you get the "Docked" value?
Now, I am not sure whether my answer is satisfying you, but...feel free to specify better what you don't like in the attached-properties pattern, and maybe you'll reach the point!
At the article, WPF Apps With The Model-View-ViewModel Design Pattern, the author who is Josh Smith said:
(1) In a well-designed MVVM architecture, the codebehind for most Views should be empty, or, at most, only contain code that manipulates the controls and resources contained within that view. (2) Sometimes it is also necessary to write code in a View's codebehind that interacts with a ViewModel object, such as hooking an event or calling a method that would otherwise be very difficult to invoke from the ViewModel itself.
My question is ,at the (1), why the empty codebehind is regarded as a a well-designed MVVM.(It sounds that the empty codebehind is always good.)
EDIT: My question is, as the following, why the approach like the AttachedCommandBehavior or the InvokeCommandAction is tried to avoid the codebehind coding.
Let me explain more detail.
As far as the (1) is concerned, I would think like the following situation as from the AttachedCommandBehavior. As the Border doesn't implement the ICommandSource for the MouseRightButtonDown, you cannot commonly bind the event and the ICommand, but can do with the AttachedCommandBehavior.
<!-- I modified some code from the AttachedCommandBehavior to show more simply -->
<Border>
<local:CommandBehaviorCollection.Behaviors>
<local:BehaviorBinding Event="MouseRightButtonDown"
Command="{Binding SomeCommand}"
CommandParameter="A Command on MouseRightButtonDown"/>
</local:CommandBehaviorCollection.Behaviors>
</Border>
OR
We can do this with the System.Windows.Interactivity.InvokeCommandAction.
<Border xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseRightButtonDown">
<i:InvokeCommandAction Command="{Binding SomeCommand}"
CommandParameter="A Command on MouseRightButtonDown"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Border>
BUT,
We use the following XAML and its codebehind having the Border_MouseRightButtonDown method, which is linked to the (2) Josh Simth said above.
<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>
I think using the codebehind as above is not bad just because the difference between these is only where binding a command or add event handler is.
What do you think about this?
why the empty codebehind is regarded as a a well-designed MVVM
Having a code-behind file which consists solely of a call to InitializeComponent() in its constructor means you have achieved purity - you have absolutely zero logic in your codebehind. You have not polluted your view with any code that rightfully belongs in the viewmodel or model. This means a couple of things:
the viewmodel (and model) is easier to test in isolation
you have achieved a good level of loose coupling, which has excellent benefits from a maintenance and extensibility perspective
The benefits really become noticeable when you have to change your UI, i.e. you switch from using a ListView to a DataGrid, or you change from using the standard Microsoft controls to using some other vendor's.
As mentioned though, it is sometimes impossible to avoid a little code in the code-behind file. What you should ensure is that the code you do have is purely UI related. As an example, if you have ComboA and ComboB, and ComboB is set in response to the selection in ComboA, then setting the SelectedIndex of ComboB from the view is fine, but setting the Items or the SelectedItem of ComboB is not - those properties are both data related and should be specified via binding to the viewmodel. The SelectedIndex property is directly visual related and somewhat independent of the actual data (and it is irrelevant to the viewmodel).
If you do access the viewmodel from code-behind in the view, you should try and do it via an interface. This means your viewmodel is injected or given to the view as an interface. (Note that the binding subsystem doesn't know or care about the interface, it will continue to bind in its normal way. What this achieves is better code, with less tight coupling). The way I code it, the viewmodel has no idea that a view exists, and the view only knows about the viewmodel as an interface.
One thing to remember though is that MVVM is a pattern, and a pattern is simply a recipe or prescription for achieving a certain result in a certain situation. It shouldn't be treated as a religion, where non-believers or non-conformers are going to go to some purgatory (although adherence to the pattern is good if you want to avoid the purgatory of maintenance hell and code smell).
If you want an excellent example of how this particular pattern helps, try writing a few reasonably complicated screens in ASP.Net, and then write the same in WPF or Silverlight, and note the difference.
Edit:
let me answer some of your questions, I hope it helps....
the viewmodel's (model of view) role , in my view, has UI logic and state of a view
The viewmodel should never have any UI logic or "view state" in it. For the purposes of this explanation, I would define view state as scroll position, selected row index, selected index, window size, etc. None of those belong in the viewmodel; things like SelectedIndex are specific to the way the data is shown in the UI (if you change the sort order of a DataGrid then the SelectedIndex can change, even though the SelectedItem is still the same). In this particular case, the SelectedItem can be bound to the viewmodel, but the SelectedIndex shouldn't.
If you need to keep track of UI session type info them then you should come up with something generic (for example, I have persisted view state before by saving important stuff into a KeyValuePair list) which is then "saved" with a call to the viewmodel (via the interface I mentioned previously). The view has no idea how the data is being saved, and the viewmodel has no idea the data is coming from a view (it has simply exposed a call through its interface).
and the view's role is displaying some contents and synchronizing the viewmodel(having databinding code)
Yes, the view's responsibility is simply to visually display data presented by the viewmodel. The viewmodel gets the data from the model (the model is responsible for making database calls or WCF webservice calls, this will usually be done via a "service", but that is a whole other discussion). The viewmodel can then shape or manipulate the data, i.e. it may get a list of all customers, but only expose a filtered version of that list (maybe the current customers) in a public property which the view can then bind to.
If the data is to be manipulated into something visual (a common example is an enum value being translated into a color), then the viewmodel still only has the enum value(s), and the view still binds to that value, but the view also uses a converter to translate the pure data to a visual representation. By using the converter the viewmodel has still avoided doing anything UI related, and the view has avoided any real logic.
The MVVM can split code and page design completely; coders just care about coding and designers only care about design. But:
I've never seen any designer who using Blend or understanding XAML.
Almost all XAMLs are written by coder himself.
There is nothing inherently bad in code-behind. For simple cases, it's fine to have it. However, UI logic can get difficult to manage in many scenarios. Encapsulating that logic in attached behaviors and view models allows us to isolate the variables (and test them) so that it's easier to comprehend and maintain.
If testability is a concern, the more of your UI logic that you can encapsulate in viewmodels and attached behaviors, the more you you will be able to verify without resorting to UI testing. (While it doesn't eliminate the need for UI Testing altogether, it does provide a first level of verification before engaging in UI Testing which will be more time/resource intensive.
I think the quoted section refers to the way data is visualized. I think they mean you should not write code in code behind that is, for example, related to how or where the data is displayed (for example something like: label1.Text = ...). Doing things like that using bindings makes it easier to separate design and code (what happens if you need the data to be displayed in a text box named "tbTest" in a later version? You'd have to change your code behind).
They are not saying that you shouldn't have any code in code behind - they are just saying that in an ideal world, you'd only react to events or process data that could not otherwise be processed.
At least that's what I understand from the section you quoted.
The MVVM pattern is powerful but I find it too 'Purist'. I can see benefit is having the code behind handle all the commands and properties in the view while the ViewModel is concerned with any translation to business model properties.
A benefit of this is that if you wish to change the user UI, perhaps from desktop to browser it is likely to be just replacing the View and its code behind.
Just my thoughts!!
If I have a usercontrol (in Silverlight) that I've written, that uses XAML to define it's appearance, how can I make a customised version of it?
i.e. I have MyControl.xaml & MyControl.xaml.cs
What do I need to do if I want a "SpecialisedControl" child class? I assume I just make a new code file, then inherit from MyControl. But what if I want to change the appearance of the base class - then what do I do?
I wrote this thinking you were talking about WPF, rather than Silverlight, but there may be enough overlap for this to be helpful, so I'm posting it, anyway.
If by "change the appearance of the base class" you mean "provide a new template", then what you need is probably a CustomControl, not a UserControl.
The best way to accomplish this is to follow the example set by other Microsoft controls, such as Button or ListBox:
Create a class that derives directly from Control (or whatever is closest to your control).
If any properties will need to be exposed to the control (such as text on a button, for example), make sure that you properly define them as DependencyProperties.
As described here, create a ResourceDictionary called Themes/generic.xaml and add a style for your class that includes a template (don't give the style a key).
Use TemplateBindings for any properties of elements on your control that need to get values from your control.
If you'll need to attach any event handlers to elements in your template, give them a unique name. Microsoft uses the convention of prefixing these names with "PART_", and I think it's a good thing to do for the sake of consistency, but it's not strictly required.
Again, if you need to attach event handlers, overload OnApplyTemplate(). In this method, you should detach any old event handlers (we certainly don't want any memory leaks!), and look for elements that have the names your provided in your template--when you find them, attach event handlers, as necessary.
This is certainly much more work than simply deriving from UserControl, but if you want to be able to totally re-template controls, like you can with the built-in controls, this is the way to do it.
On the other hand, if all you want to do is to provide a certain amount of limited customization, such as changing the background, or associating a Command with some user action, then the best thing to do is to expose DependencyProperties, which can then be set in styles for your control, or on instances of your control, itself.
In the case you mentioned of wanting to customize the look in an inherited control, the process is pretty similar: just add a default style for the new control with a new template; if you need to add more event handlers, just be absolutely certain that you call base.OnApplyTemplate().
I dunno, I like doing things with just plain objects. Here's an article that describes an easy way to slip a XAML-designed control outside your inheritance hierarchy so that you can customize appearance and behavior using SimpleThingsLikeInheritance rather than MicrosoftStuffThatAlmostWorks
http://gen5.info/q/2009/02/10/subverting-xaml-how-to-inherit-from-silverlight-user-controls/
As Mihnea's link describes, the easiest solution is to simply add a namespace in your XAML:
C#
public class MyBase : UserControl
{
}
public class FirstUserControl : MyBase
{
...
}
XAML
<local:MyBase
x:Class="FirstUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="YourAssembly" ...>
<!-- Sticking with UserControl instead of local:MyBase makes this clearer -->
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
..
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
..Your XAML
</local:MyBase>
You can solve this by using a wrapper as described in the link above.
But you can also use the strategy pattern to solve this problem.
In this post I explain how you implement these two methods.
http://www.lab101.be/2008/07/silverlight-usercontrol-inheritance/