Using MvxVisibilityValueConverter in WPF - wpf

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)" />

Related

How does this type of static XAML Binding work?

I cam across the following code in a XAML document, and I do not understand the syntax, nor do I understand how it is supposed to work.
The XAML contains the following Binding (or I guess it's some sort of Binding):
<Button Content="Export all" Command="{atf:CommandService {x:Static MyProgramme:ExportCommands+Commands.ExportAll}}">
In this project, there is a class indeed called CommandService (which is quite large so I can't share the full code, but see the ATF framework), and another class:
public class ExportCommands
{
private enum Commands
{
ExportAll
}
}
I do no understand the syntax of the XAML expression. How does it relate the CommandService class to the actual command? Are there similar examples that use this syntax?
The ATF CommandService is a custom MarkupExtension provided by the framework. An example of a mark up extension can be found here

Export an MVVM View using MEF

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.

Blend Behaviours - can you bind to their properties?

I am currently migrating a number of attached behaviours I have created to Blend Behaviours so that they support drag and drop within Expression Blend. I have noticed that authors of Blend behaviours tend to define the behaviour properties as dependency properties.
I have created a behaviour, TiltBehaviour, which exposes a public dependency property, TiltFactor, of type double. Within Expression Blend I can set the value of this property, however, the option to add a "Data Binding ..." is grayed out:
I have also noticed that Behaviors extend DependencyObject, therefore they do not have a DataContext and therefore cannot inherit the DataContext of the element to which they are attached. This feels like a real weakness to me!
So, the bottom-line is, if I cannot set a binding to my behaviors dependency property in Blend, and it does not inherit a DataContext, why bother using dependency properties at all? I could just use CLR properties instead.
Blend behaviors would be almost useless unless they supported binding! I recreated your tilt behavior and it supports binding in Blend 4 with no problems so I don't know exactly where you went wrong. Perhaps you can reproduce my simple example and then infer what's wrong with your setup.
Here's the (non-functional) tilt behavior with dependency property:
public class TiltBehavior : Behavior<FrameworkElement>
{
public double TiltFactor
{
get { return (double)GetValue(TiltFactorProperty); }
set { SetValue(TiltFactorProperty, value); }
}
public static readonly DependencyProperty TiltFactorProperty =
DependencyProperty.Register("TiltFactor", typeof(double), typeof(TiltBehavior), new UIPropertyMetadata(0.0));
}
Then just create a new window and drop the behavior onto the grid and Blend creates this:
<Grid>
<i:Interaction.Behaviors>
<local:TiltBehavior/>
</i:Interaction.Behaviors>
</Grid>
and the Blend "Data Binding..." option is available in the properties tab.
I tested this with both WPF and Silverlight projects. The built-in behaviors, triggers and actions all support binding by virtue of using being dependency properties and all the Blend samples use binding heavily and so this has to work.
In fact you can just drop a built-in behavior like FluidMoveBehavior onto your grid and check that Duration, which is a dependency property, supports binding. If that doesn't work, I have no idea what's going on!
Let's consider then how binding works for these strange beasts called behaviors.
As WPF or Silverlight programmers we are very familiar with binding for things like FrameworkElement. It has a property called DataContext that we can manipulate to control the default binding source and that property is inherited by nested elements when we don't override it.
But behaviors (and triggers and actions) are not of type FrameworkElement. They are ultimately derived from DependencyObject, as we might expect. But while we can using binding on any class derived from DependencyObject, our familiar DataContext is missing at this low-level and so the binding has to supply the source. That's not very convenient.
So behaviors are derived (on WPF anyway) from Animatable and Animatable is derived from Freezable. The Freezable class is where the simplicity of dependency objects intersects with the complexity of framework elements. The Freezable class is also the base class for more familiar things like brushes and image sources. These classes don't need the full complexity of a framework element, but they want to participate, in a limited way with the elements that they are associated with.
Through a complicated magical process, Freezable instances acquire an inheritance context: the framework element they are most closely associated with, and when a default binding is used (one without a source), the Freezable uses the DataContext of it's associated element instead.
In fact as you learn about behaviors the AssociatedObject is a central concept; for a behavior it is the thing that the behavior is attached to. But the important point is that all Freezable objects can use the DataContext of their AssociatedObject by proxy.
All this magic is what Josh Smith calls the:
Hillberg Freezable Trick
And so all this leads up to saying that due to the Hillberg Freezable Trick, Blend behaviors support binding using the data context of their associated element as the default source. As a result, bindings for behaviors seem to "just work" without any effort on our part. Behaviors are a thousand times more useful because of this.
Edit: dain is correct you can still bind to the DataContext which is created artificially, how often have you seen people bind to a SolidColorBrush.Color? It also works even though SolidColorBrush inherits from DependencyObject and hence has no DataContext.
See this blog post on the inheritance context.
The thing is that since the behaviours are attached, they do not appear in the logical tree and hence would not inherit a DataContext anyway.

WPF Generic Windows

I want to make a reusable WPF Window suitable for different types T.
I have a designer and a codebehind file.
can I do something like this?
/* Code behind file */
public partial class MyWindows<T> : Window
{}
Shamelessly copied from here (and thus not tested)
public class ViewBase<T> : Window, IView where T : class, IViewModel
{
public virtual T Model
{
get { return DataContext as T; }
set { DataContext = value; }
}
}
and XAML
<src:ViewBase
x:Class="View"
x:TypeArguments="src:IViewModel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:MyNamespace"
Height="480" Width="640">
...
</src:ViewBase>
Unfortunately, what you want isn't quite possible.
Update: Before .NET 4.0 (i.e. when this answer was originally written), XAML support for consuming generic types was very limited; e.g. generics only worked on the root element. In .NET 4.0, some restrictions were lifted.
In .NET 4.0, you can construct a fully specialized generic type. So while XAML itself still has no concept of generic types, it can refer to specializations of generic types. (By analogy, XAML can't express the notion List<> but it can express the notion List<int>). For full details, see the MSDN page "Generics in XAML".
You can construct instances of specialized generic types with the x:TypeArguments Directive. For example, with x bound to XAML's namespace, sys to the System namespace, and scg to System.Collections.Generic, and your own MyWindows' namespace bound to my then:
<my:MyWindows x:TypeArguments="x:String"> would construct a MyWindows<string> instance.
<scg:List x:TypeArguments="sys:Tuple(sys:String,sys:Int32)"> would construct a List<Tuple<string,int>>
Using generic types is therefore no longer a problem in XAML!
Alas, you want to define a generic type in XAML. That's not possible. There are two workarounds here. Firstly (and based on your comments on another question I think this is what you want) you can simple pass a type as a plain parameter. If you do this, you lose all the compile-time safety features that generics provide, but often enough those aren't relevant. Secondly, you can define a normal non-generic class with codebehind in XAML, and simply use a generic base class for code reuse. That way you get at least some proper generics safety and reuse.

WPF MVVM: Convention over Configuration for ResourceDictionary?

Update
In the wiki spirit of StackOverflow, here's an update:
I spiked Joe White's IValueConverter suggestion below. It works like a charm.
I've written a "quickstart" example of this that automates the mapping of ViewModels->Views using some cheap string replacement. If no View is found to represent the ViewModel, it defaults to an "Under Construction" page. I'm dubbing this approach "WPF MVVM White" since it was Joe White's idea. Here are a couple screenshots.
The first image is a case of "[SomeControlName]ViewModel" has a corresponding "[SomeControlName]View", based on pure naming convention. The second is a case where the ModelView doesn't have any views to represent it. No more ResourceDictionaries with long ViewModel to View mappings. It's pure naming convention now.
I posted a download of the project here:
Mvvm.White.Quickstart.zip
Original Post
I read Josh Smith's fantastic MSDN article on WPF MVVM over the weekend. It's destined to be a cult classic.
It took me a while to wrap my head around the magic of asking WPF to render the ViewModel.
It's like saying "Here's a class, WPF. Go figure out which UI to use to present it."
For those who missed this magic, WPF can do this by looking up the View for ModelView in the ResourceDictionary mapping and pulling out the corresponding View. (Scroll down to Figure 10 Supplying a View ).
The first thing that jumps out at me immediately is that there's already a strong naming convention of:
classNameView ("View" suffix)
classNameViewModel ("ViewModel" suffix)
My question is:
Since the ResourceDictionary can be manipulated programatically, I"m wondering if anyone has managed to Regex.Replace the whole thing away, so the lookup is automatic, and any new View/ViewModels get resolved by virtue of their naming convention?
[Edit] What I'm imagining is a hook/interception into ResourceDictionary.
... Also considering a method at startup that uses interop to pull out *View$ and *ViewModel$ class names to build the DataTemplate dictionary in code:
//build list
foreach ....
String.Format("<DataTemplate DataType=\"{x:Type vm:{0} }\"><v:{1} /></DataTemplate>", ...)
Rather than writing code to explicitly add things to the ResourceDictionary, how about just generating the right view on demand? You can do this with a ValueConverter.
Your resources would look like this:
<Views:ConventionOverConfigurationConverter x:Key="MyConverter"/>
<DataTemplate DataType="{x:Type ViewModels:ViewModelBase}">
<ContentControl Content="{Binding Converter={StaticResource MyConverter}}"/>
</DataTemplate>
You still need a DataTemplate resource, but as long as your ViewModels all have a common base class, you'll only need one DataTemplate to take care of all of them.
Then define the value converter class:
public class ConventionOverConfigurationConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
// value is the ViewModel. Based on its GetType(), build a string
// with the namespace-qualified name of the view class, then:
return Activator.CreateInstance(Type.GetType(viewName));
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
All you'd need to do is write the logic inside Convert, which will depend on things like whether your Views and ViewModels are in the same namespace or not.
I decided to do pretty much hthe same thing so I load my DataTemplates directly into the ResourceDictionary using
private void RegisterResources()
{
ResourceDictionary dictionary = new ResourceDictionary();
dictionary.Source = new Uri("pack://application:,,,/StartupModule;Component/UIResources.xaml");
Application.Current.Resources.MergedDictionaries.Add(dictionary);
}
where the UIResources file is a ResourceDictionary xamls file containing all of our DataTemplates

Resources