I'm using the MVVM pattern with MVVM Light. I have a ViewModelLocator defined in App.xaml which holds all the ViewModels which are bound to from the Views using Blend.
I have an AppViewModel which basically contains all the important global info for my app, like user preferences. AppViewModel is instantiated by ViewModelLocator, which is in turn, instantiated by app.xaml.
The trouble is, I need to access AppViewModel from inside OnLaunched, however, at this stage of the application lifecycle, it appears app.xaml has not yet instantiated its declared resources. It appears to only do this after a Frame.Navigate().
I need to access AppViewModel because I have to inspect the properties on there in order to work out which Page to load. Hence it's a chicken-and-egg situation.
If I separately instantiate AppViewModel inside OnLaunched, then I can access AppViewModel, but then ViewModelLocator gets instantiated twice which causes problems with my IoC.
Is there a way of manually instantiating items declared inside app.xaml? Or is there a way to get app.xaml to load its resources before presenting a UI?
Or am I doing this wrong? Generally speaking, I regard the application to be the view model layer and the views essentially observe that... so hence I need the ViewModels available before I present any UI.
XAML:
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
</Application.Resources>
Code:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
var vml = App.Current.Resources["Locator"] as ViewModelLocator; // exception raised
Exception:
WinRT information: Cannot find a resource with the given key.
thanks
How about you instantiate the ViewModelLocator when you first need it and then add it to Application.Resources once Application.Resources is otherwise initialized or whenever you need? You don't need to add key value pairs to the ResourceDictionaries in XAML always.
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";
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.
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've got a Windows 8.1 Store application.
Have a singleton class in which I keep some data. I've defined a static property of the singleton as an app resource-
Application.Current.Resources.Add("CSettings", CSettings.Instance.Data);
and I'm binding various xaml properties to appropriate properties in it
<ToggleSwitch x:Name="m_cConnectionModeToggle" OnContent="Enabled" OffContent="Disabled"
IsOn="{Binding IsTCPConnection, Source={StaticResource CSettings}, Mode=TwoWay}" />
I thought that I'd be able to access my singleton through the usual ...Instance getter- but when I go to CSettings.Instance.Data I'm getting a different instance from the one that's been bound (and changed).
Are there 2 singleton instances of the same class being created here?
One at CSettings with the .Instance getter and another on this.Resources["CSettings"] ?
Did I fail in implementation somewhere? I mean is this a plausible approach to having a changeable, application- wide resource, that I'd be able to both bind and use programmatically ?
it looks to me that when you add a value to the Resources dictionary it doesn't store it as a reference but it creates a new value.
My suggestion would be to use an IoC container like the ones used by MVVM frameworks. For example SimpleIoc from MVVM light. You don't have to implement MVVM in your application, just use the container.
The way this would work would be to create a class and register it as a resource in App.xaml. In that class register your container like that
App.xaml
<MyC:MyClass x:Key="Locator" d:IsDataSource="True" xmlns:MyC="clr-namespace:MyProject.MyClassFolder" />
MyClass.cs
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MyData>();
public MyData { get {return ServiceLocator.Current.GetInstance<MyData>();}}
Note: You will need Microsoft.Services.ServiceLocation and Galasoft.Mvvmlight.Ioc.SimpleIoc you can get both from Nuget.
Then in xaml you can access the MyData.IsTCPConnection field like that
IsOn="{Binding MyData.IsTCPConnection, Source={StaticResource Locator}, Mode=TwoWay}"
and in code
MyData myData = SimpleIoc.Default.GetInstance<MyData>();
myData.IsTCPConnection = ...;
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/