The application that I'm building has several (10+) [Module] executables.
I would like to specify something like this in [Module]View.xaml file.
<Window ...
mef:ExportView ExpectingViewModel={x:Type [Module]ViewModel}
>
</Window>
where mef:ExportView is a MarkupExtension which prepares the parts for the MEF composer.
Currently,...
In [Module]View.xaml.cs file I mark my View with an ExportView(typeof([Module]ViewModel)) attribute inside the . (The typeof param specifies the expected ViewModel.)
I also mark my ViewModel with an [ExportViewModel] attribute.
(Both attributes derive from ExportAttribute.)
Each executable's Application class also inherits from an ApplicationBase class which does the MEF composition and marries/links the View/ViewModel.
Now, I would like to be able to remove all code-behind from the [Module]View.xaml.cs to prevent myself and my co-workers from forgetting to markup the code-behind file.
I'm thinking this would require a custom MarkupExtension. I'm familiar with the basics of MEF, as well as creating custom export attributes with metadata. However, I think this solution would require deriving from some of the MEF primitives.
Related
I'm building an application using PRISM and MVVM. I have a view model that needs to display a non-modal dialog box to the user indicating an operation is in progress. I'm using essentially an abstracted IDialogService.
My question is: where should I store the strings for the title and the message shown in this dialog box? The view model's logic causes the dialog box to be displayed and determines when it should be closed. Hence, I have code that looks like this in my view model:
let! closeDlgAction =
dialogSvc.ShowDialogModeless (
"Opening File",
"Please wait while your selected file is opened.") |> Async.AwaitTask
I'm thinking about localization scenarios. WPF has its own mechanism for providing localization through resource dictionary, etc. It seems like these strings belong in a resource dictionary, but the view model shouldn't have a dependency on WPF resource directories - especially because the same view model is going to be used on a Xamarin Forms application later.
The best solution that comes to mind is to use a service that abstracts the resource library away (e.g. IDialogStringService), but I wonder if there's a better or more preferred approach?
You shouldn't use resource dictionaries (xaml) to store text. Instead you have to use Resources (*.resx). In VS:
Right click on project
Add -> New Item...
Find "Resources File" template, type name, and click Add
Opt. Open this file (special editor will opened) and on top bar switch Access Modifier to Public, if you want get access to text from another project or from XAML. Add some key\value strings.
Right click on resource file and click Run Custom Tool. New class will generated with static properties with names based on your keys from Step 4.
How to use (if file has name Localizations.resx and has string with key "AppTitle")
From code:
let! closeDlgAction =
dialogSvc.ShowDialogModeless (
Localizations.AppTitle,
"Please wait while your selected file is opened.") |> Async.AwaitTask
From xaml:
<Window
x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{x:Static Localizations.AppTitle}"/>
*.resx file and *.cs file that is generated both don't depend on any WPF assemblies, so you can use them in different assemblies: in shared view models, from wpf views and from xamarin views. Just put you *.resx file in separate netstandard assembly and refer to it where do you need it from
Cons of this way:
resx generates class with strings and each string is public property, so static code analyze works
You don't have add new abstraction level
You can ref strings from code files or from XAML
I liked Vadim's answer, and I have used that approach before. If my View Models lived in the same project as the WPF project, that would be the best solution.
However, my View Models are in a different library (and a different language) and will be shared between a Prism MVVM WPF project and a Prism MVVM Xamarin Forms project. I could still use resources in the View Model library, but then localization concerns would exist separately in both the WPF project (for the Views) and the View Model library. IMO the localization concern should be centralized.
As such, I decided to abstract the resources behind a service. Implementing the resource service turned out to be more straightforward than I thought. To use an indexer intuitively, I defined a "resource container object" that is returned by IResourceService, as seen below:
public struct ResourceContainer
{
private readonly Func<string, string> _resourceGetter;
public string this[string resourceId] => _resourceGetter(resourceId);
public ResourceContainer(Func<string, string> resourceGetter) => _resourceGetter = resourceGetter;
}
public interface IResourceService
{
ResourceContainer Resources { get; }
}
And the service implementation in the WPF library is as follows:
public class ResourceService : IResourceService
{
public ResourceService()
{
Resources = new ResourceContainer((s) => Application.Current.Resources[s] as string);
}
public ResourceContainer Resources { get; }
}
In the WPF layer's XAML resource directory:
<s:String x:Key="FileOpenDialogTitle">Opening File</s:String>
<s:String x:Key="FileOpenDialogMessage">Please wait while your selected file is opened.</s:String>
And, finally, the View Model consumes this service by requesting IResourceService on its constructor, and is used as follows:
let! closeDlgAction =
dialogSvc.ShowDialogModeless (
resourceSvc.Resources.["FileOpenDialogTitle"],
resourceSvc.Resources.["FileOpenDialogMessage"]) |> Async.AwaitTask
This approach will ultimately require implementing the resources twice - once for the WPF project and once for the XF project, but I have to implement the Views twice, anyway. At least the localization concerns are centralized in both cases (or perhaps a shared resource library can be used between both projects).
EDIT: This technique could also leverage Vadim's suggestion by putting the localization resource (.resx) in the WPF project as well, and either having the XAML resource directory reference the static resources, or have the ResourceService return the resource directly. Having the resources in .resx format may make sharing them between multiple projects more straightforward.
I'm just getting started with MVVMCross, so forgive me if this seems like a simple question. I'm trying use the MVVMCross Visibility plugin in WPF, mentioned here:
https://github.com/MvvmCross/MvvmCross/wiki/Value-Converters
I installed the plugin, and am trying to follow these steps:
Windows - use Native wrappers or Tibet Binding as described above:
Visibility="{Binding VMProperty, Converter={StaticResource
Visibility}}"
When I try to do so, it can't find the resource "Visibility."
So I figured, I can add the namespace:
xmlns:visibility="clr-namespace:Cirrious.MvvmCross.Plugins.Visibility;assembly=Cirrious.MvvmCross.Plugins.Visibility"
...and then add the converter to my resources:
<visibility:MvxVisibilityValueConverter x:Key="Visibility"></visibility:MvxVisibilityValueConverter>
...but now I get:
An object of the type "Cirrious.MvvmCross.Plugins.Visibility.MvxVisibilityValueConverter" cannot be applied to a property that expects the type "System.Windows.Data.IValueConverter".
Do I have to make my own Converter for this, like this:
class MyVisibilityConverter : MvxNativeValueConverter<MvxVisibilityValueConverter>
{
}
...or am I missing something? The docs seem to indicate there's less work involved.
IValueConverter isn't currently a portable interface, and this was a deliberate decision from Microsoft. I've talked to one of the guys from the PCL team about this - he seemed very clear that they expected most value converters to be platform specific and so not to sit in shared code.
Because of this - and because MvvmCross believes many value converters will be shared - we had to introduce our own IMvxValueConverter interface inside MvvmCross. This IMvx interface can't be used directly by XAML and the Microsoft bindings - so that's the reason you need the "native" wrapping currently.
You can work around this - if you want to - by using the MvvmCross "Tibet" binding framework instead of the Microsoft one, but I think most MS-based devs are still using the MS-binding.
am I missing something? The docs seem to indicate there's less work involved.
For using value converters on Windows, the wiki says the text below - if you think this can be improved, please do contribute changes back - we're keen to keep on improving.
Using Value Converters in Windows (conventional Xaml binding)
The IMvxValueConverter interface is closely based on the IValueConverter interface used in Windows WPF and Silverlight Xaml binding. This interface is also similar (but slightly different) to the IValueConverter interface used in Windows WinRT Xaml binding.
Because these Xaml IValueConverter interfaces are not 100% identical to each other, nor to the IMvxValueConverter version, shared Mvx ValueConverters cannot be used directly in Windows Xaml binding - they must instead be wrapped for use in Xaml.
The steps to do this are similar on each Windows platform:
for each IMvxValueConverter class, e.g. for
public class TheTruthValueConverter
: MvxValueConverter<bool, string>
{
public string Convert(bool value, Type targetType, CultureInfo cultureInfo, object parameter)
{
return value ? "Yay" : "Nay";
}
}
in your UI project, create a 'native' wrapper using the MvxNativeValueConverter class:
public class TheNativeTruthValueConverter
: MvxNativeValueConverter<TheTruthValueConverter>
{
}
in your Xaml, include an instance of your ValueConverter as a static resource - this can be done in the Resources at App, Page or Control Xaml level, e.g.:
<converters:TheNativeTruthValueConverter x:Key="TheTruth" />
now your converter can be used - e.g.:
<TextBlock Text="{Binding HasAccepted, Converter={StaticResource TheTruth}}" />
Using Value Converters in Windows (Tibet binding)
In addition to 'traditional' Xaml bindings, MvvmCross also allows 'Tibet' binding within Windows - for more on this see wiki/Databinding.
When Tibet binding is used, then Value Converters can be accessed by name - exactly as in Droid and Touch binding - without the above native Xaml wrapping.
Further, if using 'Tibet' binding then an entire assembly's worth of value converters can be registered using the Reflection sweep technique and this can be specified at the Xaml level - meaning it can be used in both design and run-time.
To include all value converters within an Assembly at the Xaml level, then use an mvx:Import block with an inner From attribute which contains an instance of a class from that Assembly.
This may sound complicated… but actually it is quite simple.
Suppose you have an Assembly MyTools containing FooValueConverter, BarValueConverter, etc
Within this Assembly add a simple, instanciable public Class which we will use only for the import - e.g. public class MarkerClass {}
Then within the xaml, you can include a static resource import block like:
<mvx:Import x:Key="MvxAssemblyImport0">
<mvx:Import.From>
<myTools:MarkerClass />
<mvx:Import.From>
</mvx:Import>
After this is done, then the ValueConverters Foo and Bar will be available for use within 'Tibet' bindings - e.g. as:
<TextBlock mvx:Bi.nd="Text Foo(Name)" />
Windows Phone 8 project, XAML. I have a ListBox inside a pivot item that's of my own class MyPivotItem (derived from vanilla PivotItem) inside a page. The listbox has an ItemTemplate with some controls. I'd like to bind an event in one of those controls to a method in MyPivotItem. The plain syntax Click="OnClick" does not work - the frameword searches for the method in the Page class only.
I could derive the control itself and do some trickery with tree navigation and event forwarding and so on, but I wonder if such a scenario can be served by XAML's internal means.
Is there any way to bind methods non-programmatically to a class that's deeper in the hierarchy than the root object of the XAML file?
Without using something like behaviors or attached properties, it is not possible. XAML file is always associated with partial C# class and in this class you define your controls and events. For every Page.xaml, a Page.g.xaml file is generated that actually creates controls and binds events. However, those events must be defined in root object - the partial class itself.
Even if you create a workaround using either attached properties or behaviors, you are simply offloading that programmatic code to some other place and hiding it behind XAML syntax.
When would you want to bind to control's specific event handlers anyway? Can you simply use UserControls for that?
Can someone give me a quick summary of what a ViewModelLocator is, how it works, and what the pros/cons are for using it compared to DataTemplates?
I have tried finding info on Google but there seems to be many different implementations of it and no striaght list as to what it is and the pros/cons of using it.
Intro
In MVVM the usual practice is to have the Views find their ViewModels by resolving them from a dependency injection (DI) container. This happens automatically when the container is asked to provide (resolve) an instance of the View class. The container injects the ViewModel into the View by calling a constructor of the View which accepts a ViewModel parameter; this scheme is called inversion of control (IoC).
Benefits of DI
The main benefit here is that the container can be configured at run time with instructions on how to resolve the types that we request from it. This allows for greater testability by instructing it to resolve the types (Views and ViewModels) we use when our application actually runs, but instructing it differently when running the unit tests for the application. In the latter case the application will not even have a UI (it's not running; just the tests are) so the container will resolve mocks in place of the "normal" types used when the application runs.
Problems stemming from DI
So far we have seen that the DI approach allows easy testability for the application by adding an abstraction layer over the creation of application components. There is one problem with this approach: it doesn't play well with visual designers such as Microsoft Expression Blend.
The problem is that in both normal application runs and unit test runs, someone has to set up the container with instructions on what types to resolve; additionally, someone has to ask the container to resolve the Views so that the ViewModels can be injected into them.
However, in design time there is no code of ours running. The designer attempts to use reflection to create instances of our Views, which means that:
If the View constructor requires a ViewModel instance the designer won't be able to instantiate the View at all -- it will error out in some controlled manner
If the View has a parameterless constructor the View will be instantiated, but its DataContext will be null so we 'll get an "empty" view in the designer -- which is not very useful
Enter ViewModelLocator
The ViewModelLocator is an additional abstraction used like this:
The View itself instantiates a ViewModelLocator as part of its resources and databinds its DataContext to the ViewModel property of the locator
The locator somehow detects if we are in design mode
If not in design mode, the locator returns a ViewModel that it resolves from the DI container, as explained above
If in design mode, the locator returns a fixed "dummy" ViewModel using its own logic (remember: there is no container in design time!); this ViewModel typically comes prepopulated with dummy data
Of course this means that the View must have a parameterless constructor to begin with (otherwise the designer won't be able to instantiate it).
Summary
ViewModelLocator is an idiom that lets you keep the benefits of DI in your MVVM application while also allowing your code to play well with visual designers. This is sometimes called the "blendability" of your application (referring to Expression Blend).
After digesting the above, see a practical example here.
Finally, using data templates is not an alternative to using ViewModelLocator, but an alternative to using explicit View/ViewModel pairs for parts of your UI. Often you may find that there's no need to define a View for a ViewModel because you can use a data template instead.
An example implementation of #Jon's answer
I have a view model locator class. Each property is going to be an instance of the view model that I'm going to allocate on my view. I can check if the code is running in design mode or not using DesignerProperties.GetIsInDesignMode. This allows me to use a mock model during designing time and the real object when I'm running the application.
public class ViewModelLocator
{
private DependencyObject dummy = new DependencyObject();
public IMainViewModel MainViewModel
{
get
{
if (IsInDesignMode())
{
return new MockMainViewModel();
}
return MyIoC.Container.GetExportedValue<IMainViewModel>();
}
}
// returns true if editing .xaml file in VS for example
private bool IsInDesignMode()
{
return DesignerProperties.GetIsInDesignMode(dummy);
}
}
And to use it I can add my locator to App.xaml resources:
xmlns:core="clr-namespace:MyViewModelLocatorNamespace"
<Application.Resources>
<core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
And then to wire up your view (ex: MainView.xaml) to your viewmodel:
<Window ...
DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">
I don't understand why the other answers of this question wrap around the Designer.
The purpose of the View Model Locator is to allow your View to instantiate this (yes, View Model Locator = View First):
public void MyWindowViewModel(IService someService)
{
}
instead of just this:
public void MyWindowViewModel()
{
}
by declaring this:
DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"
Where ViewModelLocator is class, which references a IoC and that's how it solves the MainWindowModel property it exposes.
It has nothing to do with providing Mock view models to your view. If you want that, just do
d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"
The View Model Locator is a wrapper around some (any) Inversion of Control container, such as Unity for example.
Refer to:
How to handle dependency injection in a WPF/MVVM application
http://blog.qmatteoq.com/the-mvvm-pattern-dependency-injection/
I have read multiple posts on the subject but still cannot manage to make it work.
I want 2 user controls slidertype1 and slidertype2 which should inherit from slidercommontype, all are in same namespacecommon, can someone knows the syntax for this simple use case ?
Inspiring from http://jamescrisp.org/2008/05/26/wpf-control-inheritance-with-generics/
I tried:
<namespacecommon:slidercommontype x:Class="namespacecommon.slidertype1">
but I got namespacecommon:slidercommontyp doesn't exist in xml namespace.
As long as the base class doesn't have a XAML file associated with it, it's pretty easy. Trying to incorporate the visual aspect of the user control using XAML is not really a supported scenario.
Having said that, just create your class SliderCommonType (although I would call it SliderBase or something.)
namespace MyControls {
public class SliderBase : UserControl {
}
}
Then create your two controls based on it. I'll show one example and the other should be obvious.
<Local:SliderBase x:Class="MyControls.SliderType1"
xmlns:Local="clr-namespace:MyControls">
</Local:SliderBase>
And the code-behind would look like this:
namespace MyControls {
public class SliderType1 : SliderBase {
}
}
The key point being that your XAML file has to reference the base class which requires changing the <UserControl> element to <Local:SliderBase> which in turn requires a XAML namespace import.
When you add a UserControl using the default template, you can just change the code it creates to reflect the above changes. It's much easier than trying to create it from scratch.
One last thing to note - you will need your application to compile successfully before you can use the visual designer on your derived controls. This is because the designer needs to be able to instantiate SliderBase at design-time.