WPF Units and Code-Behind - wpf

Recently I discovered WPF supports different measurement units in XAML. Besides default DIPs, there is also support for pixels, inches and centimeters (as far as I know). This allows designer to write XAML such as this:
<Canvas>
<Line X1="0cm" X2="3cm" Y1="1cm" Y2="3cm" Stroke="Black"/>
</Canvas>
However, you cannot bind these values. Imagine we have a ViewModel with Dimension property which is a String, for example "7cm". Following won't work:
<Button Width="{Binding Dimension}">Test</Button>
FormatException gets thrown. Similarly, when creating a FrameworkElement in code-behind, like this:
Canvas1.Children.Add(new Button() { Width = "3cm", Content = "Test"});
Compilation fails because exception is thrown in constructor/wherever you try to create the control.
I wonder:
Is it possible to use natural units (in my case metric - centimeters) in code-behind?
How?
Is there a complete list of units WPF/XAML supports?
EDIT:
Here is a link from comment below, which resolves this question:
http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.width.aspx

You can do this in code behind by applying the same conversion the XAML-parser uses, you do not need to reimplement this logic if you don't mind passing around strings:
button.Width = (double)new LengthConverter().ConvertFrom("2cm");
The XAML-parser uses TypeConverters to convert strings to the needed values, in the documentation page of the Width property you can see that it has a TypeConverterAttribute specifying that a LengthConverter should be used. This attribute can be used to locally override how a property should be handled, but it can also be applied at class level, so if an Employee class has this attribute specifying that an EmployeeConverter should be used said converter will be the default for properties of type Employee.
I am a bit surprised the binding does not apply this type converter, but using it inside an IValueConverter would be simple enough, in fact you could create a markup extension which constructs an IValueConverter from a type converter to make it nicely generic.

For 1) and 2) Because DIPs are device independent, you can calculate any "natural unit" to and from without problems. The exception are (unnatural :) device dependent pixels.
Create a ValueConverter that converts string values to doubles where your desired units may be specified in the string. Then you can use the ValueConverter in your Binding and calculate in your ViewModel in "natural units".
For 3) and the implementation: I have quickly googled and found nothing, but maybe will a deeper search show something. Otherwise, creating your own converter should not be very difficult. Here some conversion infos:
96DIP == 1inch == 2.54cm;
1cm == 37.8DIP;
1zoll == 1inch == 2.54cm;

Related

Using MvxVisibilityValueConverter in 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)" />

How to generate predefined values for xaml property with typeconverter

If I have a control and I start typing a foreground property for it, it offers me a list of Colors, seemingly from the Colors class.
edit: I think it's actually the KnownColor enum, which is internal.
How is this achieved?
I have an attached property which is of type MyClass. I have a static class with some pre-cooked instances of MyClass. I want to achieve the same behavior described above.
I know I can use a type converter and convert from the string to an instance, but this seems a little more advanced
You will need to use a Type converter. The Xaml parser has built-in special handling of known types such as Brush and Color.

Silverlight - Sample Data - Complex objects

I really like using the sample data binding at design time for Silverlight.
It is easy to use it when you need to return string values.
In my case, I am trying to bind to my ViewModel one of whose properties returns a SolidColorBrush. How do I setup the sample data to return a SolidColorBrush value?
Here is what the string based properties look in the sampleData.xml file.
<ViewModels:MyViewModel AlphaValue="Abcd" ColorValue="????"/>
How should I format ColorValue to return a SolidColorBrush?
What I am trying to do:
I have a textblock with its foreground set to Foreground="{Binding ColorValue}". The TextBlock is invisible on the design surface as its not getting a value from the sampledata.xml file. Where as another textblock on which I have only text property set to a binding value, appears correctly on the design surface.
You need to look at creating a value converter. Look at this and it should give you an understanding of what you need to do. http://msdn.microsoft.com/en-us/library/system.windows.data.binding.converter.aspx

Manually parse string as XAML Attribute

How does the XAML Parser convert the string "Red" in Foreground="Red" to a SolidColorBrush? Allthough I know the Types have System.ComponentModel.TypeConverter defined, I doupt that the WPF XAML parser acutally always uses those to convert the string to the brush. Are there any XAML APIs apart from XamlReader.Load (wich wants a valid xml string) that I could use to parse a single string as if it where an attibute for a certain property?
The XAML parser (for WPF) really does actually use the type converter of the property or property type specified. There are a few hard-coded short-cuts but they are for performance and do not change the semantics. A parser, just using attribute information, can duplicate the parser semantics (which is, for example, what Blend and Cider do).
There is no API that will convert a value exactly as XAML would mainly because many type converts only work in the context of a XAML parse. For example, type converters can refer to namespaces defined in the XAML file (which changes depending on where the value is in the XML file) as well as other ambient information base URI base for the file. These are only really applicable when the XAML file is being parsed.
The closest you can come to is asking for the property descriptor for the property from the type descriptor and using the Converter property. This will scan the appropriate attributes to create the correct type converter.
I believe you can take advantage of this yourself. XamlReader knows the target type (the type of the property to which the string must be applied). You would register a TypeConverter for that property's type.
EDIT this will work for you when it comes to SolidColorBrush:
var colorString = ...;
var converter = new System.Windows.Media.BrushConverter();
var brush = (SolidColorBrush)converter.ConvertFromString(colorString);
Looking at SolidColorBrush in .NET Reflector, it seems the magic that does deserialization within XamlReader uses internal APIs around known types. I'm not sure whether you can register your own types to handle this.

Are value converters instantiated per-binding in WPF?

Is a separate WPF value converter object instantiated for each binding that a particular value converter class is used in?
I am trying to create a two-way bit-to-boolean value converter. I would like to be able to bind a bool property (such as IsChecked) to a bit in a value type (like a ushort). I'm using the converter's parameter arguments to specify the bit. Implementing the ConvertBack() method is easy, but Convert() is little trickier.
In Convert() I need to know what the value of the entire ushort is so I can toggle just the single bit I am interested in. I was thinking of just using a member variable in my value converter class to temporarily store this whenever ConvertBack() is called, thus leading to the above question: does each binding get its own value converter instance?
If you use a converter defined in your resources, it will be shared amongst your properties.
If you need unique converters:
If you create a specific converter for a property, however, it will not be shared. Either option is workable. You can even use multiple converters (of the same type, with different keys) in your resources, which will create unique instances.
Create a constructor and destructor in your converter and set breakpoints within to tell for sure. I just created a simple example and it looks like only one converter was created for my multiple viewmodels that were using the constructor

Resources