silverlight expression in binding - xaml

I am styling a usercontrol of mine.
I have some "constants" regarding the size of the object, and in my template object I have something like
<UserControl ...>
<UserControl.Resources>
<sys:Double x:Key="width">10</sys:Double>
<sys:Double x:Key="margin">30</sys:Double>
</UserControl.Resources>
...
<ControlTemplate ...>
<Grid x:Name="width_plus_margin">
...
If I wanted the width of the "witdh_plus_margin" to be "width" value I just added something like
Width="{StaticResource width}"
but what I really need is to set something like
Width="{StaticResource width} + {StaticResource margin}"
this syntax is wrong. Is there a way to specify what I need?

You can't bind to more than one source property in a Binding. Therefore you need some kind of aggregator that offers an output property you can bind against.
Here are some variations of the same pattern:
<UserControl.Resources>
<sys:Double x:Key="width">10</sys:Double>
<sys:Double x:Key="margin">30</sys:Double>
<BindableResult x:Key="widthPlusMargin" ArithmeticOperation="Add" LeftOperand="{StaticResource width}" RightOperand="{StaticResource margin}"/>
</UserControl.Resources>
<Grid Width="{StaticResource widthPlusMargin}">
with BindableResult having an implicit cast operator to double:
public static implicit operator double(BindableResult source)
{
return source.InternalResult;
}
or something like this:
<UserControl.Resources>
<sys:Double x:Key="width">10</sys:Double>
<sys:Double x:Key="margin">30</sys:Double>
</UserControl.Resources>
<Grid>
<i:Interaction.Behaviors>
<SetCombinedWidth Value1="{StaticResource width}" Value2="{StaticResource margin}"/>
</i:Interaction.Behaviors>
</Grid>
You can also google for silverlight multibinding implementations and see if that is more to your taste. But in the end it is just another variation of the aggregator.

Related

Cannot bind my Converter class in my XAML command that pass parameter

This is my XAML that is trying to have my ListView pass a parameter to the ViewModel command.
xmlns:mvvm="http://www.galasoft.ch/mvvmlight"
<ListBox x:Name="MyListView" ItemsSource="{Binding Objects}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<mvvm:EventToCommand Command="{Binding MyCommand}"
PassEventArgsToCommand="True"
EventArgsConverter="{StaticResource ParamConverter }"
EventArgsConverterParameter ="{Binding Name}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And this is my converter:
public class ParamConverter : IEventArgsConverter
{
public object Convert(object value, object parameter)
{
var args = (SelectionChangedEventArgs)value;
var name = parameter as string;
return (string)name.ToString();
}
}
But I got the following error:
The resource "ParamConverter" could not be resolved
Your converter is not declared in XAML, you should add something like
<ListBox.Resources>
<yournamespace:ParamConverter x:Key="ParamConverter"/>
</ListBox.Resources>
inside your listbox tags.
EDIT: I'm not an expert at all, so bear with my "imprecise" terms if any. I think you're missing something: there is no magic that allows your XAML to be aware of your C#. You need to tell XAML that somewhere in your code (in yournamespace) there will be a ParamConverter object, that can be referenced inside xaml with ParamConverter key.
You can declare your resource locally inside ListBox tags as suggested, or at outer scope if needed.
Once resource is declared inside XAML, you can access it via StaticResource.

Cannot bind to button events using x:Bind in DataTemplates - generates XAML error

With the {x:Bind} markup syntax you can bind to events provided the method meets the following requirements:
Match the signature of the event.
OR have no parameters.
OR have the same number of parameters of types that are assignable from the types of the event parameters.
This works perfectly fine outside of a DataTemplate. Once the binding happens inside the DataTemplate the compiler generates the following error:
Xaml Internal Error error WMC9999: Object reference not set to an
instance of an object.
What is the fix for binding to events inside DataTemplates?
Full example code here.
Snippet of the example code below - note the first button (line 2) is fine and the second button (line 6) is also fine. If you comment out line 6 and and comment in line 7, the error occurs.
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Tapped="{x:Bind Click}" Content="WORKING"/>
<ListView ItemsSource="{x:Bind Names}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Customer">
<Button Content="{x:Bind Title}"/>
<!--<Button Tapped="{x:Bind Clicky}" Content="{x:Bind Title}"/>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
I was able to get it to work with the following code:
<DataTemplate x:DataType="local:Customer">
<StackPanel Orientation="Vertical">
<Button Tapped="{x:Bind Clicky}" Content="{x:Bind Title}" />
</StackPanel>
</DataTemplate>
It seems as though you need to have it inside a container for it work. I have no idea why I am guessing magic.
The parser cannot find Clicky from the datacontext of the button while in the template. Because the object that is being handed to the button in the template (from the Names on the ItemSource of the parent) is not the same as outside the template which has a Clicky. You will need to bind Clicky to the page's datacontext to get it to work.
Otherwise turn off any design time operations by setting Tapped="{x:Bind Clicky, IsDesignTimeCreatable=False}.

Binding events to buttons in an ItemsControl

I have a windows phone 7 app with some xaml that looks like:
<Grid x:Name="ContentGrid" Grid.Row="1">
<ItemsControl x:Name="MyView" ItemTemplate="{StaticResource MyInner}"/>
</Grid>
The item template here looks like:
<DataTemplate x:Key="MyInner">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{StaticResource MyInner_Item}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
And finally, the MyInner_Item template looks like:
<DataTemplate x:Key="MyInner_Item">
<Button x:Name="MyButton">
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="myborder">
<Image Source="{Binding Path=ImageUri}" Width="{Binding Path=Width}" Height="{Binding Path=Height}" Stretch="Fill" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
So, it's an ItemsControl, which contains an ItemsControl, which contains buttons. This essentially creates a 2D array of buttons.
What I want to do is add an event handler to the Click event of the buttons.
Here's the catch: the code that sits behind this is written in F#. I can't, to the best of my knowledge, specify my event handler in the XAML, as F# doesn't talk to WPF in any nice way. So I need to add my event handler(s) manually in code.
Is there an easy way of doing this?
Currently, I have some F# which looks like:
let myView : ItemsControl = this?MyView
do myView.ItemsSource <- viewModel.BoardData
Here, the BoardData is a list of lists.
I was wondering if it's possible to loop through the controls in the ItemsControl, to add my event handlers? I'm having a bit of trouble doing this though. For example, in the following:
let container = myView.ItemContainerGenerator.ContainerFromItem(myView.Items.[0])
...sets container to null. In fact, all the methods I've tried from myView.ItemContainerGenerator returns null.
So, how should I go about attaching my event handler, so that I can respond to the buttons being clicked?
I have not done any Windows 7 Phone development, but I have done plenty of XAML + Silverlight development with C# and now I'm getting into doing some F# development. The approach I would take is by not using event handler's at all. Since you are using a button, make a class that derives from ICommand and add that type as a public property on your ViewModel so you could bind it to the Command property of the button. The benefits of using the ICommand interface over event handlers is that you could also have a condition on when the button is enabled to do the action.
Also, take notice that when you are doing binding expressions within (i.e. ItemTemplate) items in an ItemsControl control, the scope of what properties you can bind to are reduced to the properties of the current item. So all of the properties of the ViewModel are out of scope, unless you specify it fully i.e. <Button Command={Binding Source=ViewModel, Path=Property1.Property2.etc} />. Let me know if this helped.

eventocommand not working

I am making one application in MVVM using Galasoft MVVM Light toolkit. However i can't make EventToCommand make it work with Telerik Context Menu. Here is my code :-
<ListBox x:Name="lstPhotoAlbums" ItemsSource="{Binding AlbumsCollection}"
Margin="3,0" Grid.Row="1" ItemsPanel="{StaticResource wrapPanelItemsPanelTemplate}"
ItemTemplate="{StaticResource ListboxPhotosDataTemplate}"
ItemContainerStyle="{StaticResource ListboxPhotoAlbumsContainerStyle}" Height="500" HorizontalAlignment="Left" VerticalAlignment="Top" Width="178">
<telerik:RadContextMenu.ContextMenu>
<telerik:RadContextMenu x:Name="albumsCtxMenu">
<telerik:RadMenuItem Header="Delete" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding DeleteAlbumCommand}" CommandParameter="{Binding SelectedItem, ElementName=lstPhotoAlbums}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</telerik:RadMenuItem>
</telerik:RadContextMenu>
</telerik:RadContextMenu.ContextMenu>
</ListBox>
I do hit the breakpoint in my viewmodel. However the command parameter is always null. Any ideas where i am wrong?
Thanks in advance :)
As this is an old post, you might have found the answer to your question. However, as I was trying to do the same, I did not find a precis answer to this and if others are looking for the same, I hope this might help them.
You will need to remove the CommandParameter argument from your EventToCommand and change it to this:
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding DeleteAlbumCommand}" PassEventArgsToCommand="True" />
Your RelayCommand in your ViewModel or whereever you are implementing your RelayCommand would have to look something like this:
RelayCommand<EventArgs> DeleteAlbumCommand = new RelayCommand<EventArgs>(CallbackMethod);
CallbackMethod should then look something like this:
private void CallbackMethod(EventArgs eventArgs)
{
...
}
Hope this will help.

Retrieving value from static extension XAML

How do I retrieve the value (Int32.MaxValue) from the static extension:
<x:Static
x:Key="TooltipTimeout"
Member="s:Int32.MaxValue"
/>
...
<blablalba TooltipService.ShowDuration="{StaticResource TooltipTimeout}"/> <-- this does not work by the way
Methinks you're doing something else wrong. Slap this in kaxaml:
<Page
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<x:Static x:Key="Derp" Member="sys:Int32.MaxValue"/>
</Page.Resources>
<Grid>
<TextBlock
ToolTipService.ShowDuration="{StaticResource Derp}"
ToolTip="Derp" Text="Herp" />
</Grid>
</Page>
Mod tested, mother approved.
If I had to guess, I think you're not defining your xml namespace for Int32 correctly.
In WPF, You can access static member directly, like this,
<TextBlock TooltipService.ShowDuration="{x:Static s:Int32.MaxValue}"/>
However, you cannot do the same in Silverlight, as it wouldn't work. In silveright, you've to write a wrapper class, like this,
public class StaticMemberAccess
{
public int Int32Max { get { return Int32.MaxValue; } }
//define other wrapper propeties here, to access static member of .Net or your classes
}
Then do this in XAML,
<UserControl.Resources>
<local:StaticMemberAccess x:Key="SMA"/>
</UserControl.Resources>
<TextBlock TooltipService.ShowDuration="{Binding Source={StaticResource SMA}, Path=Int32Max}"/>
.
Try to bind to your resource by setting it as the Source of your binding:
{Binding Source={StaticResource TooltipTimeout}}