I'm still getting comfortable with WPF, so this might be a silly question. I'm tracking the source of a tab control issue and discovered that I don't know the answer to the question in the title.
My Mvvm-Lite project template put the usual in the Windows opening tag:
DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
And from somewhere else (I really don't remember) I have this handy static resource:
<ObjectDataProvider x:Key="src" ObjectType="vm:MainViewModel" />
While I'm troubleshooting my tab control issue (I won't bore you with those details here) I realized that I didn't know if these two ways of pointing to the view model confilicted in any way. Two separate instances of the view model? I don't think so cause the ViewModelLocator is holding a static reference to Main. Anyway, I just wanted to be sure that I haven't made a "greenie" mistake.
Thanks,
Jim
I am pretty sure that this is going to create two different instances. You can easily verify this by placing a breakpoint in the MainViewModel constructor and running your application in debug mode.
ObjectDataProvider was introduced before MVVM was popular. I would argue that many objects in WPF are kind of obsoleted by MVVM, because now we create these objects and properties in code in the ViewModel layer. In your case, I guess that you probably don't need the ObjectDataProvider, but can use the ViewModelLocator.Main everywhere instead.
Cheers,
Laurent
Related
I need a reference to a Visual (one element of a XAML View Window) in my ViewModel to work with VisualTreeHelper methods like VisualTreeHelper.GetDescendantBounds(Visual reference) but I do not want to break MVVM rules and just name the viewport3d and provide it as a reference when instancing my ViewModel.
Currently I am binding the geometry as content like this to my ViewModel:
<Viewport3D>
<ModelVisual3D Content="{Binding SceneContent.Content}"/>
</Viewport3D>
But I do not see the MVVM possibility to get the containing ModelVisual3D into my ViewModel. Is there a standard (may be data-binding) approach to this in MVVM applications?
Using MVVM, we don't 'get view elements'. If you need to do something with a UI element, then that has nothing to do with MVVM. If you need to use the VisualTreeHelper.GetDescendantBounds method, then once again, that has absolutely nothing to do with MVVM... why do so many people claim to use MVVM, but know nothing about it?
Therefore, your question is invalid. It is entirely appropriate in situations like these for you to use the code behind. In fact, this is a perfect example of when we should use the code behind when following the MVVM methodology. If it is only UI related, then it has no purpose being in a view model, so simply don't put it there.
Please read the answer to the What are MVVM limitations? question to get some further insight into MVVM.
Current I have some Views linked to ViewModels using code similar to the following:
<Application.Resources>
<DataTemplate DataType="{ x:Type vm:AgeIndicatorViewModel}">
<v:AgeIndicatorView />
</DataTemplate>
</Application.Resources>
I have two questions regarding this:
Does this method allow me to only link one View to each View Model (I think it does improse this limitation on me, but want to be sure)
When using this method, where should I put all of my DataTemplate declarations? At the moment there are only a few, and they are all in App.Xaml - Is there a better location for these, or is App.Xaml fine / Best location?
The most important question is the second really, as at the moment I want to link my ViewModel to my View in this way, as it requires no external libraries etc.
The way my ViewModels are setup, with their Properties and Commands etc is all working already.
Does this method allow me to only link one View to each View Model (I think it does improse this limitation on me, but want to be sure)
Yes. If you're trying to link multiple ViewModels to multiple Views, you need to encapsulate them within a separate VM, and add a new DataTemplate.
When using this method, where should I put all of my DataTemplate declarations? At the moment there are only a few, and they are all in App.Xaml - Is there a better location for these, or is App.Xaml fine / Best location?
App.Xaml is fine, or really any place in the visual hierarchy above where the DataTemplate will be used.
That being said, if the project gets to be a very large scale project, it's often nicer to start using Merged Resource Dictionaries - this allows you to setup resource dictionaries "near" where you define the View/ViewModel pairs, but then use them at a higher level (ie: merge them into App.Xaml).
Specifying the implicit DataTemplate like you do in your question does tie your View-Model to a single View. You can override this at any control level though, so you could have:
<Window.Resources>
<DataTemplate DataType="{x:Type vm:AgeIndicatorViewModel}">
<v:AgeIndicatorView2 />
</DataTemplate>
</Window.Resources>
This would change the view applied to a view-model for the given window. This can be done on any control at any level.
The benefit of doing this at the app-level though is that it is applied across all windows in your application. While my example above would only be applied to a single window.
In general, the app resources is the best place to define these. Since if you have multiple Windows (i.e. Window1 and Window2), then your view-model will always pick up your implicit DataTemplate.
I'm trying to learn WPF but I find it very difficult to understand bindings, the "resources" thing, and object creation.
My background is in C++/MFC and C#-Winforms.
My questions:
Most of the examples I see in XAML (in MSDN and in two other WPF books I've read) use StaticResource in the binding expression. Are these related in any way to static members? Or is this just a misleading name? When a reference is made to any object as a StaticResource, when is it instantiated?
As far as I can see StaticResources are used with "things" defined in the "Resources" section of the app/window/control etc.
Now, these Resources sections are very confusing to me.
What exactly are they? From my experience in MFC these were icons, strings, etc. However, judging by all the examples I've seen, in WPF these seem to be essentially a "dumping ground" for
(a) all kinds of global object definitions in markup (styles, data templates, etc)
(b) all kinds of global object instantiations in markup
Am I correct? This strikes me as very messy.
It essentially involves learning all sorts of semi-DSLs in XAML (for defining styles, for defining data templates, for creating objects etc), and sticking them together in the same place.
I keep thinking about something like editing the resource file (.rc) in MFC by hand. At least there the sections were well separated and the syntax for each resource was relatively simple.
To tie up the previous two questions: When I define an object instance in the Resources section, and later reference it from a StaticResource binding, when exactly is it instantiated?
MSDN says (in "How to: Make Data Available for Binding in XAML"):
one way you can make the object
available for binding is to define it
as a resource
However, this isn't very clear. What do they mean available? Do they mean created? Do they mean hooked up to the binding subsystem? And when exactly is that object created?
From playing around with a simple example I saw that WPF seems to create this object for me when it tries to attach the binding. And this is even more confusing.
EDIT:
After the clarification by karmicpuppet below, I'm still confused as to how this is connected to Binding.
Suppose I have in my resources:
<local:Person x:Key="MyPerson" Name="Title"/>
(where Person is a class with a property called Name) and then in the window I have:
<TextBlock Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/>
1) What does this do? Does it goes through the same steps - searching for the resource and then applying it to the Text property? Does the MyPerson object gets created at the time of Window creation, or later?
2) Do I have to use the Binding mechanism to bind to the Name property? Can't I bind to it directly like you did above with myBrush? Why can't I do something like this?
<TextBlock Text="{StaticResource MyPerson, Path=Name}"/>
Is it just a short-sightedness on the part of the framework? I think I'm missing very big here, but I can't seem to understand what...
3) I tried using DynamicResource, but I am very confused about each step I took.
a) Added a DependencyObject with a DependencyProperty above my single Window class in code (is this DependencyObject necessary?)
public class SomeText : DependencyObject
{
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(SomeText), new UIPropertyMetadata(0));
}
b) Added an instance of it to the Windows.Resources (is this necessary with DynamicResource? MSDN seems to say no, but if so I can't figure out how to do the next step in XAML)
c) I tried both:
Text="{Binding Source={DynamicResource HeaderText}, Path=Header}"
Which gave me an exception, and
Text="{DynamicResource HeaderText}"
But I couldn't understand where to put the path to the Header property.
This is my 5th or so attempt to fiddle around with WPF lately, and each time I get stumped by this seemingly simple things which don't work. I've read 2 books and I really try to understand the MSDN articles, however they're of no help at all.
First, an overall comment:
WPF is hard to learn. It's hard to learn because there are several different fundamentally new concepts that you have to get your head around at the same time. The struggle that you're having right now is that you're trying to learn at least three different things at once:
How the XamlReader (and particularly markup extensions) deserializes XAML into objects.
How the FrameworkElement's resource dictionaries work.
How data binding works.
Something like this:
<TextBox Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/>
is engaging (at least) three very different technologies at the same time. Those technologies are all designed to be as flexible as possible, which only makes them more confusing to the beginner. The idea that a binding source can be just about anything: that's hard to grasp. The idea that a markup extension is a special kind of serialization format that supports recursion: simple enough to understand in principle, but a little baffling when you first start working with real-world examples. The idea that a resource dictionary can contain just about anything, and that the resource searching algorithm essentially makes resources inheritable: again, pretty simple in concept, but easy to lose the thread of when you're trying to figure out data binding and XAML at the same time.
It's frustrating, because something that's conceptually simple - "I want to bind this control to a property of an object that I've created" - requires that you understand a great many things before you can actually express it in XAML.
The only solution is to be patient, and to make sure you understand things at the lowest level possible. When you see this:
{StaticResource MyPerson}
you should be able to think, "That's going to invoke the StaticResource markup extension handler, which retrieves an object from a resource dictionary using the key MyPerson when the XAML is deserialized.
It's extremely challenging at first. I've been developing software professionally for 35 years, and I've found WPF to be the most challenging technology platform that I've ever learned by a considerable margin. But all of this stuff is hard to learn because it's incredibly functional and flexible. And the payoff of learning it is huge.
To address a couple of issues that karmicpuppet didn't:
From my experience in MFC [resources] were icons, strings, etc.
That hasn't changed. You can still create resource files in WPF and load them into objects at runtime. There are lots of different ways of doing this - you can create resources in the resource editor and load them via the Properties.Resources object, you can add image files (for instance) to the project, have them compiled as resources, and load them using their URI, and there are plenty of other ways that I don't know about.
The resources available to FrameworkElements via their resource dictionaries are a different thing. Well, sort of. Here's an example:
<Window.Resources>
<Image x:Key="MyImage" Source="images/myimage.png"/>
</Window.Resources>
This creates an Image object and adds it to the Window's resource dictionary with a key of MyImage You can then reference that object via the StaticResource markup extension in XAML, or the FindResource method in code.
Setting the Source attribute on the Image element in XAML also makes the XamlReader use the ResourceManager to read the image data from the project's compiled resources at runtime when it creates the Image object.
In practice, this is nowhere near as confusing as it is when you're first learning WPF. I never get resources that ResourceManager loads and resources stored in resource dictionaries mixed up.
And when exactly is that object created?
Any object defined by a XAML element is created when the XamlReader reads the element. So this:
<Window.Resources>
<local:Person x:Key="MyPerson"/>
</Window.Resources>
instantiates a new Person object and adds it to the Window's resource dictionary with a key of MyPerson. It's exactly equivalent to doing this in the Window's code-behind:
AddResource("MyPerson", new Person());
So why don't you just do it in code-behind? Two reasons:
First, it's consistent. If you define all your resources in XAML, you only need to look in XAML files to find what your resources are. If you define them in both XAML and code-behind, you have to look in two places.
Second, the IDE knows about resources that you define in XAML. If you type
<TextBox Text="{Binding {StaticResource MyPerson}, Path=Name}"/>
in your XAML, the IDE will let you know if you haven't defined, somewhere in the hierarchy of resource dictionaries, a resource whose key is MyPerson. But it doesn't know about resources that you've added in code, and so even though the resource may actually be findable at runtime, the IDE will report it as a problem.
Think about it this way: all FrameworkElements (Windows, Buttons, other Controls, etc), as well as the Application object, contain a Dictionary of Resources. Whenever you define a resource in XAML as shown here:
<Window>
<Window.Resources>
<SolidColorBrush x:Key="myBrush" Color="Red"/>
<DataTemplate x:Key"myTemplate">
<!--Template definition here -->
</DataTemplate>
</Window.Resources>
</Window>
It's like doing something like this in code:
class Window
{
void Window()
{
this.Resources.Add("myBrush", new SolidColorBrush(Brushes.Red));
this.Resources.Add("myTemplate", new DataTemplate());
}
}
You can put all kinds of objects as Resources. Anything that you would like to re-use throughout your application, you can define it as a Resource.
Now, when you do use a "{StaticResource}" as follows:
<Button Background="{StaticResource myBrush}"/>
This is like telling WPF to search for the corresponding "myBrush" resource and apply it to the Background property. What will happen is WPF will first search the resource in the Button's resource dictionary, and if it's not found will search its parent, then its parent's parent, and so on up to the application's resources.
The "static" thing in "StaticResource" just distinguishes it from the other type of resource-lookup called "DynamicResource". The difference between the two is answered in this link.
When applied to Binding, it also works the same way. Say, for instance, you have the following resource in your XAML:
<local:Person x:Key="MyPerson" Name="Title"/>
and used it as:
<TextBlock Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/>
In this case, what will happen is something like this:
Binding b = new Binding();
b.Source = FindResource("MyPerson");
b.Path = "Name";
[TextBlock].SetBinding(TextBlock.TextProperty, b);
Again, the "{StaticResource}" markup in the XAML tells WPF to search for the corresponding resource and set it as the value for the a property. In this case, the property is Binding's "Source" property.
That's the basics. Hope you find this helpful
Does anybody have an idea how to change screens (views) in a MVVM View-First-Approach (The view instantiates the ViewModel:
DataContext="{Binding Source={StaticResource VMLocator},
Path=Find[EntranceViewModel]}"
)
For example:
In my MainWindow (Shell) I show a entrance view with a Button "GoToBeach".
<Window>
<DockPanel>
<TextBox DockPanel.Dock="Top" Text="{Binding Title}" />
<view.EntranceView DockPanel.Dock="Top" />
</DockPanel>
</Window>
When the button is clicked I want to get rid of the "EntranceView" and show the "BeachView".
I am really curious if somebody knows a way to keep the View-First Approach and change the screen (view) to the "BeachView".
I know there are several ways to implement it in a ViewModel-First Approach, but that is not the question.
Perhabs I missed something in my mvvm investigation and can't see the wood for the trees... otherwise i am
hoping for a inspiring discussion.
One possibility would be to have all views in the (MainWindow(Shell) and using Triggers for their visibility. But having a lot of different screens (views) all declared in the MainWindow doesnt feel right for me...
This question came up while reading this nice way of using MEF with MVVM I found on John Papas Blog: Simple ViewModel Locator for MVVM: The Patients Have Left the Asylum . But as nice as this marriage of view and viewmodel is, it seems like there is no way to change screens that satisfies me. :)
So in my opinion if you have a lot of screens(views) you better use a ViewModel-First-Approach...
This looks like it might help:
Creating a ViewModel : do it before or after model data is available?
Failing that, how about creating the ViewModel once only at startup, and assigning it to each View window as it's created (rather than creating a new ViewModel each time). Then just close the first View and open up a new View as required, reassigning the single ViewModel instance.
You may want to look at Prism (i.e. the composite application library). Prism facilitates navigation between views via the region manager. This might be overkill for your application and can take a while to get your head around. Prism also allows you to develop using the MVVM pattern as well.
You can find more information about prism and prism navigation in the Prism documentation.
I'm starting to use Binding in my WPF project and I'm actually confused about few things on the presentation side (XAML).
So I want to populate a TreeView with a List of Categories. I know how to write the right HierarchicalDataTemplate for my List of Category instances.
<HierarchicalDataTemplate ItemsSource="{Binding Path=ChildrenCategories}" DataType="{x:Type src:Category}">
<TextBlock Text="{Binding Path=Name}"></TextBlock>
</HierarchicalDataTemplate>
But what now I don't know is from where to get the list. I have here 2 solutions :
I got a Library Singleton class
which return me the right
arborescence, then I need to use an
ObjectDataProvider in my xaml which
would call the
Library.Instance.Categories method. (Which means that the controller has to be completely separated from the UI).
I got a Property ListCategories
in my page interactionLogic
(OpenUnit.xaml.cs), and bind the
tree with it.
I'm not sure about the purpose of the xaml.cs files, what are they made for? Is it normally used to store the properties (and act as a controller) or simply to have a back-end for the UI (for example get values from the UI?)?
In case the xaml.cs file is used as a controller, how do I bind my data to it, I've tried many solutions without success,my only success was with the use of static binding.
I would appreciate any comment or recommandation about UI and Logic Binding in WPF, hopefully I will get less confused.
Thanks in advance,
Boris
After reading this great article, I got a little bit less confused :
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
The article is about the Model View ViewController pattern, and how WPF integrates it. So it seems that xaml.cs files should be used as the ViewController here, and should hold the properties.
It actually make sense since it's not a good practice to mix the View and the Data, we want the designers should have a completely independant work to do.
Also for the solution 2) it is possible if you set the data context to the current file.