XAML Margin in resources - xaml

How do I define XAML margin in Windows universal app resources? I tried to define it as
<Thickness x:Key="MyMargin" Left="10" Top="20" Right="10" Bottom="20" />
by this does not compile, I get
XamlCompiler error WMC0100: XAML Thickness type cannot be constructed. In order to to be constructed in XAML, a type cannot be abstract, interface, nested, generic or a struct, and must have a public default constructor

The syntax for Windows XAML is as follows:
<Thickness x:Key="myMargin">10,20,10,20</Thickness>
which could be simplified to:
<Thickness x:Key="myMargin">10,20</Thickness>

I had it working by binding it to a String:
<x:String x:Key="MarginLeftPage" >120,0,0,0</x:String>
[...]
Grid Margin="{StaticResource MarginLeftPage}">

Related

XAML binding intellisense in a separate ContentView file used in a ListView

I have a ListView with this item template:
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<views:ProjectListEntry />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
ProjectListEntry is fairly complex and is used in another ListView, so I have it in its own file. I've set it up like this:
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...
BindingContext="{x:Static vms:DesignTimeData.ProjectListEntryVm}">
As you can see, to get binding Intellisense (using ReSharper), I tried to set BindingContext to a static member on the DesignTimeData class. This works fine for my Pages (where I replace the BindingContext at runtime), but for ContentViews used in ListViews, the ContentView's BindingContext seems to be inherited (from the ViewCell, I guess). This means that the explicit BindingContext on my ContentView will actually override the BindingContext set on the ViewCell by the ListView, and all my list elements will reflect the static design-time data at runtime. But if I remove the BindingContext, I get no intellisense for the members I bind to inside the ContentView file.
Is there a simple way to get Intellisense for bindings in a ContentView like this?
(As mentioned, I can't inline the ContentView in the ListView definition, because the ContentView is fairly complex and used in several lists. I also can't use some kind of VM locator, because although I'm using bindings, I'm not using "full" MVVM - I'm using a Redux-like architecture instead. And I guess a VM locator wouldn't work for this case anyway for the same reasons the above doesn't work.)
(Cross-posted from the Xamarin Forums where I didn't get any reply.)
This solution seems to work fine. In short: Add
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
and use d:DataContext instead of BindingContext. Going from the example above, it should look like this:
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
...
BindingContext="{x:Static vms:DesignTimeData.ProjectListEntryVm}">
This leads to working binding intellisense from ReSharper and does not cause issues when run.

PathGeometry in ResourceDictionary

In WPF I used to have my vector icons in ResourceDictionary like this:
<PathGeometry x:Key="BackIconGeometry">M9.5,0 L16,0 8.75,7 22,7 22,11 8.75,11 16,18 9.5,18 0,9 z</PathGeometry>
and reference it from application like this:
<Path Data="{StaticResource BackIconGeometry}" Style="..." />
In UWP I'm getting error:
A value of type 'String' cannot be added to a collection or dictionary
of type 'PathFigureCollection'
How can I store my icons data in resource dictionaries? I would like to avoid storing them as <Style TargetType="Path" /> since I would like to use different styles for the icons
Your Path is an actual string value that is used for Binding so instead of using PathGeometry use x:String in resource Dictionary.
<Application.Resources>
<x:String x:Key="BackIconGeometry">M9.5,0 L16,0 8.75,7 22,7 22,11 8.75,11 16,18 9.5,18 0,9 z</x:String>
</Application.Resources>
and in XAML you can use like below.
<Path Data="{StaticResource BackIconGeometry}" />

Using x:Bind inside the GridView's ItemTemplate layout User Control in UWP

In the Universal Windows Platform API, how do I use x:Bind inside of a User Control (intended to be the layout for a GridView's ItemTemplate) to bind to instance properties of a GridView's ItemSource?
Background
I'm trying to re-create the layout found in Windows 10 stock apps like Sports, News, Money, etc.
I'm using a two GridViews for the main area of the app; one for "featured articles" (2 large photos w/ headlines) and one for all the other articles (smaller photos w/ headlines).
I'm able to bind to a data source that I supply in the code behind (a List where NewsItem is a POCO with a Image and Headline property) Here's the pertinent parts of the MainPage.xaml:
<Page ...
xmlns:data="using:NewsApp.Models" />
....
<GridView Name="FeaturedItems" Grid.Row="0">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:NewsItem">
<Grid Name="mainPanel" HorizontalAlignment="Stretch" Width="500" >
<Image Source="{x:Bind Image}" HorizontalAlignment="Stretch" />
<TextBlock Text="{x:Bind Headline}" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
....
The Image and Headline bind just fine (even though they've not been styled correctly). However, instead I think I need to bind to a User Control to get the styling options I want, control over resizing esp. when using Visual State Triggers and to simplify the XAML in general (at least, this was the technique suggested to me.)
So, I added a new User Control to the project (FeaturedItemControl.xaml), and copied in the DataTemplate's child Grid:
<UserControl ... >
<Grid Name="mainPanel" HorizontalAlignment="Stretch" Width="500" >
<Image Source="{x:Bind Image}" HorizontalAlignment="Stretch" />
<TextBlock Text="{x:Bind Headline}" />
</Grid>
</UserControl>
And then back in the MainPage.xaml, I change the DataTemplate to reference the new FeaturedItemControl:
<GridView Name="FeaturedItems" Grid.Row="0">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:NewsItem">
<local:FeaturedItemControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
However, I get the error message for both Image and Headline properties: Invalid binding path 'Headline': Property 'Headline' can't be found on type 'FeaturedItemControl'.
I've tried a few things but am flailing just throwing code at the problem without understanding what I'm doing. Any help would be greatly appreciated.
Thank you for your kind attention.
Using Depechie's answer, I formulated this little cheat cheat for posterity:
Do note that you MUST use this technique to utilize the VisualStateManager with items inside your data bound controls' (GridView, ListView) data templates.
1) Create a User Control.
2) Cut the content of the DataTemplate in your page and paste it into the User Control replacing the template's Grid.
3) Reference the User Control from inside the Data Template:
4) Modify the contents of the User Control changing x:Bind statements to utilize object.property notation:
<UserControl>
<StackPanel>
<Image Source="{x:Bind NewsItem.LeadPhoto}" />
<TextBlock Text="{x:Bind NewsItem.Headline}" />
<TextBlock Text="{x:Bind NewsItem.Subhead}" />
</StackPanel>
</UserControl>
5) Add this in the User Control's Code Behind:
public Models.NewsItem NewsItem { get { return this.DataContext as Models.NewsItem; } }
public ContactTemplate()
{
this.InitializeComponent();
this.DataContextChanged += (s, e) => Bindings.Update();
}
Well it's possible to use x:Bind in user controls, but you'll need to add some extra code behind.
I encountered the same problem in my project, you can see the result here : https://github.com/AppCreativity/Kliva/tree/master/src/Kliva/Controls
So what you need to do is, create a property in the code behind of your user control that points to the correct DataContext.
If you do that, you can use properties of that DataContext in the xaml of your control: for example:
Do note that in the constructor of your control you do need to add: DataContextChanged += (sender, args) => this.Bindings.Update(); because the datacontext will change depending on the page where your control is used!
Then on the page where you are placing this control, you'll also need to do the same to enable the x:bind to work.
You'll see this in my example on the MainPage.DeviceFamily-Mobile.xaml and MainPage.xaml.cs files.
Hope this helps.
x:Bind isn't really hierarchical like Binding/DataContext is. Additionally when you're not directly inside a DataTemplate (such as inside your user control) the object that x:Bind tries to use is 'this' rather than 'this.DataContext'. My current line of thinking on how to solve this sort of issue is to try not to use UserControls anywhere. Instead preferring DataTemplates contained within a ResourceDictionary. There are some pretty strong caveats to this approach though, you will for example crash the xaml compiler if you use x:Bind inside a data template that was created from the ResourceDictionary item template (add new item). you can find a pretty complete example here https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBind its important to note in the sample where they show the ResourceDictionary being used that its not actually just a ResourceDictionary.xaml its also a ResourceDictionary.xaml.cs (this is where the generated code from x:Bind ends up)
Another option is to add Headline and Image as properties on your user control and x:Bind them from the template, then inside the user control x:Bind as you are currently doing, but now the x:Bind generated path 'this.Headline' will exist. Unfortunately the order things are actually bound means that the x:Bind's you have inside your user control will have to be OneWay rather than the default OneTime. this is because x:Bind OneTime does the bind inside the InitializeComponent call, and any set of properties/DataContext stuff doesn't get done until after that has already run.
So to sum this up, you have two options, use data templates everywhere, or bind to properties that are directly on the user control.

StaticProperties in Resource Dictionary

My XAML has been working fine, referencing a Static Property of a static class
<TextBox IsReadOnly="{x:Static loc:StateMachine.IsReadOnly}" />
I now want to refactor the above, so I can use a ResourceDictionary
So, my resource dictionary is
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:stat="clr-namespace:MyProjectHelper"
>
<stat:StateMachine x:Key="StaticResources" />
</ResourceDictionary>
On my XAML, I removed the namespace reference called loc (which I was using) and I add a reference to the resource dictionary (which works since my views show and converters do their job) but when I add the following code
<TextBox IsReadOnly="{StaticResource StaticResources.IsReadOnly}" />
I get a runtime exception
'Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' Line number '50' and line position '97'.
My research shows this is something wrong wit the XML - it could be a typo (checked) or an unexpected value but I can't see what I need to do to fix this despite looking over SO and Google
I also tried
<TextBox IsReadOnly="{Binding Source={StaticResource StaticResources}, Path=IsReadOnly}" />
but the exception is
'The invocation of the constructor on type 'SeoHelper.StateMachine' that matches the specified binding constraints threw an exception.' Line number '9' and line position '6'.
{StaticResource } binding needs to be able to instantiate your class, and it had problem to do so because the class was static. Your last trial would've worked if only the class wasn't declared as static.
Possible workaround if you need to keep your class static is, you can register the property instead of the class to resource dictionary using StaticExtension :
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:stat="clr-namespace:MyProjectHelper"
>
<x:StaticExtension Member="stat:StateMachine.IsReadOnly" x:Key="StaticResources"/>
</ResourceDictionary>
Then binding to the resource can be done as usual :
<TextBox IsReadOnly="{StaticResource StaticResources}" />

How to add a class to a xaml page

this is windows phone 8 app.
I have a class like this in namespace MyApp.Converters:
public class CustomConverter : IValueConverter
{
}
I want to add this to a XAML page, but I don't know how?!
I did this:
xmlns:MyApp.Converters="clr-namespace:MyApp.Converters"
and
<phone:PhoneApplicationPage.Resources>
<MyApp.Converters:CustomConverter x:Key="customConverter"/>
</phone:PhoneApplicationPage.Resources>
I get this error:
Length cannot be less than zero
How to add a class to a XAML page? thanks
we can have the following mapping to the namespace
<phone:PhoneApplicationPage xmlns:c="clr-namespace:MyApp.Converters">
<UserControl.Resources>
<c:CustomConverter x:Key="myconverter">
</c:CustomConverter>
</UserControl.Resources>
and you can bind the key as below wherever you need it
{Binding Converter={StaticResource myconverter}}
also you can refer to the following link which may help you
http://www.mindfiresolutions.com/Giving-alternate-color-to-each-row-of-ListBox-in-Windows-phone-7-2280.php
There seems to be an issue when you put a dot in the prefix name. If you remove it then it should work:
xmlns:MyAppConverters="clr-namespace:MyApp.Converters"
and
<phone:PhoneApplicationPage.Resources>
<MyAppConverters:CustomConverter x:Key="customConverter"/>
</phone:PhoneApplicationPage.Resources>