Silverlight 3 IValueConverter troubles - data-binding

First let me say I'm new to Silverlight. But I have most of the "basic" Silverlight stuff figured out. I'm using Silverlight 3 at the moment.
In a nutshell, I am not seeing my IValueConverter called inside a UserControl. But as with many things, it's not quite that simple. The UserControl is in a DataGrid cell, in a column whose DataColumnTemplate is generated at runtime by XAML.
Here's my DataTemplate for the Column:
StringBuilder CellTemp = new StringBuilder();
CellTemp.Append("<DataTemplate ");
CellTemp.Append("xmlns:aa='clr-namespace:InvTech.AA.Silverlight.UI;assembly=AASilverlight' ");
CellTemp.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
CellTemp.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
CellTemp.Append(">");
CellTemp.AppendFormat("<aa:ProductAssetView DataContext='{{Binding Products[{0}]}}' />", index);
CellTemp.Append("</DataTemplate>");
return CellTemp.ToString();
So the cell's contents are getting bound to my UserControl. This works; I just can't get my IValueConverter called to format the contents of the UserControl the way I want.
The operative parts of the UserControl XAML:
(declare prefix)
xmlns:aaConv="clr-namespace:InvTech.AA.Silverlight.Core;assembly=AA.Core"
(bound controls inside Grid layout)
<TextBox x:Name="txtSAA" Grid.Row="0" Grid.Column="0" Text="{Binding SAA, Converter={StaticResource PercentConverter}, Mode=TwoWay}" Width="35" FontSize="9"/>
<TextBox x:Name="txtOVR" Grid.Row="0" Grid.Column="1" Text="{Binding Overlay, Converter={StaticResource PercentConverter}, Mode=TwoWay}" Width="35" FontSize="9" />
<TextBox x:Name="txtTAA" Grid.Row="0" Grid.Column="2" Text="{Binding TAA, Converter={StaticResource PercentConverter}, Mode=TwoWay}" Width="35" FontSize="9" />
<TextBlock x:Name="tbkCurrent" Grid.Row="0" Grid.Column="3" Text="TODO" Width="35" FontSize="9" />
<Grid.Resources>
<aaConv:PercentValueConverter x:Key="PercentConverter" />
</Grid.Resources>
Is there something obviously wrong here? Is the dynamic XAML a factor? I feel like this should be trivial compared to the dynamic XAML template...
Thanks

Finally figured this out. By moving the Resource declaration to <UserControl.Resources> and putting that tag before the content, my IValueConverters were exercised.

Related

Drag and Drop on Xamarin Forms

We want to implement drag and drop functionality in Xamarin forms
and in this user should be able to drag an emoji from 1 place, and put on another. We don’t want the source emoji to go away though and should be able to come to know on which employee, rating is given .
Image how it is before
Image how it is after
Question also posted on:
https://forums.xamarin.com/discussion/184104/drag-and-drop-on-xamarin-forms/p1?new=1
We have checked a few links like below, but none of them seem to work:
Xamarin Forms Drag Image between Views
https://blog.francois.raminosona.com/drag-and-drop-in-xamarin-forms/
Will appreciate if could get some tips on how to do it and even if this was possible on forms?
You could check the code below.
xaml:
<StackLayout Margin="10">
<StackLayout Margin="10" Orientation="Horizontal">
<components:DragAndDropSample3ReceivingView
BackgroundColor="Beige"
HeightRequest="80"
WidthRequest="80" />
<components:DragAndDropSample3ReceivingView
BackgroundColor="Beige"
HeightRequest="80"
WidthRequest="80" />
<components:DragAndDropSample3ReceivingView
BackgroundColor="Beige"
HeightRequest="80"
WidthRequest="80" />
</StackLayout>
<BoxView
BackgroundColor="Blue"
HeightRequest="5"
WidthRequest="3" />
<StackLayout Margin="10" Orientation="Horizontal">
<components:DragAndDropSample3MovingView
BackgroundColor="Red"
CornerRadius="40"
HeightRequest="40"
WidthRequest="40" />
<components:DragAndDropSample3MovingView
BackgroundColor="Green"
CornerRadius="40"
HeightRequest="40"
WidthRequest="40" />
</StackLayout>
</StackLayout>
Code Behind:
public void OnDropReceived(IDragAndDropMovingView view)
{
if (view is DragAndDropSample3MovingView sender)
{
var control = new DragAndDropSample3MovingView()
{
BackgroundColor=sender.BackgroundColor,
CornerRadius=sender.CornerRadius,
WidthRequest=sender.WidthRequest,
HeightRequest=sender.HeightRequest,
};
Content = control;
}
}
Screenshot:
You could check the source file from the code project for reference.
https://github.com/WendyZang/Test/tree/master/Drag_Drop_Controls/Xamarin-Developer-Sample-master

Copy attached properties to new instance in xamarin forms

I am creating new instance of grid object which have two labels as following.
<Grid x:Name="Grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70*"></ColumnDefinition>
<ColumnDefinition Width="30*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Label x:Name="Label1" Text="Label1" Grid.Column="0" Grid.Row="0"></Label>
<Label x:Name="Label2" Text="Label2" Grid.Column="1" Grid.Row="0"></Label>
</Grid>
I am using Activator.CreateInstance method as given below:
Grid ClonedView =(Grid) Activator.CreateInstance(Grid.GetType());
foreach (PropertyInfo propertyInfo in Grid.GetType().GetProperties())
{
if (propertyInfo.CanRead && propertyInfo.CanWrite )
{
object PropertyValue = propertyInfo.GetValue(Grid, null);
propertyInfo.SetValue(ClonedView, PropertyValue);
}
}
When I use this ClonedView in my page, it Cloned Grid don't understand that Label2 should appear in second column of grid. I did a lot of research on it but could not find any solution. Please let me know if anybody has any solutions.
thanks
They way you're thinking about this, feels very JavaScript like to me. You want to create a deep copy by copying all properties. However the Xamarin objects are way too complex for something like this (even if you where able to do a deep copy, Bindings for example won't work with simple copying).
So instead of making a single Grid object and trying to create copies of it, another way of looking at it would be "I want to define a template, and then create multiple instances according to that template". For this Xamarin has the DataTemplate class, which enables us to do something like this in xaml:
<ContentPage>
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="MyGridTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70*"></ColumnDefinition>
<ColumnDefinition Width="30*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Label Text="Label1" Grid.Column="0" Grid.Row="0"></Label>
<Label Text="Label2" Grid.Column="1" Grid.Row="0"></Label>
</Grid>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<Button Text="Add Grid" Clicked="AddGridClicked">
</Button>
<StackLayout x:Name="GridHolder">
<StackLayout>
<ContentPage>
And in our code behind we can implement AddGridClicked like this:
private void AddGridClicked(object sender, EventArgs e)
{
var myGridTemplate = (DataTemplate) Resources["MyGridTemplate"];
GridHolder.Children.Add((View)myGridTemplate.CreateContent());
}
Now the downside is that you need to define a DataTemplate instead of just pointing at an object and saying getting a copy. Also keep in mind that x:Name of a View in the DataTemplate can't be accessed in code behind of your page, but with a good Xamarin setup that should not be needed. The upside is that this works, complete with possible bindings, so you're allowed to define a Label in your grid like this:
<Label Text="{Binding Name}" Grid.Column="0" Grid.Row="0"></Label>
And then you can give each instance if your templated Grid a different BindingContext to bind different data to it's views.
Hope this helps

Panorama Binding on WP7, Items collection must be empty before using ItemsSource

i keep getting this error: Items collection must be empty before using ItemsSource, when i attempt to bind data to a Panorama control. below is my xaml snippet.
<controls:Panorama x:Name="panorama">
<controls:PanoramaItem >
<StackPanel>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</controls:PanoramaItem>
</controls:Panorama>
in my code behind (xaml.cs), i do something like this:
protected override void OnNavigatedTo(NavigationEventArgs e) {
string id = NavigationContext.QueryString["id"];
ObservableCollection<MyObject> list = DataAccessService.get(id);
panorama.ItemsSource = list;
base.OnNavigatedTo(e);
}
note that MyObject has a Text property. any help is appreciated.
after modifying it per the link below, the same exception is still thrown.
<controls:Panorama x:Name="panorama">
<controls:Panorama.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</controls:Panorama.HeaderTemplate>
<controls:PanoramaItem >
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
</controls:PanoramaItem>
</controls:Panorama>
finally, after continuing further with the user below's help, this is the solution that got rid of the exception.
<controls:Panorama x:Name="panorama">
<controls:Panorama.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</controls:Panorama.HeaderTemplate>
<controls:Panorama.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
</controls:Panorama.ItemTemplate>
</controls:Panorama>
Your problem is that you're building the Panorama in XAML as though it were static rather than preparing it to be data-bound.
Take a look at this quick tutorial for a Data Binding Panorama Control:
Data Binding Panorama Control WP7 MVVM
Notice the difference in how your XAML is being constructed for the control. Instead of setting the Items collection on the Panorama control, you need to set the HeaderTemplate and ItemTemplate so that the control knows how to render things once data is bound to it.

How can I delete an item from a Databound windows phone application?

Starting with the stock Databound application, I replace the xaml on the MainPage
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
with this:
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Name="ItemName" Margin="10,10,0,0" Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextSubtleStyle}" Grid.Column="0" />
<Button Grid.Column="1" Click="Button_Click" BorderThickness="0" Height="40" HorizontalAlignment="Center">
</StackPanel>
In Button_Click(), I’d like to remove that item from Items. I know the syntax would be something like App.ViewModel.Items.Remove(something)
but I’m missing what that something is. How can I ensure the correct item is removed based on the value of LineOne that is displayed?
Thanks for looking.
There are a few ways to go about doing this. The best way is with an ICommand. But you also need to add a CommandButton class to hold the reference and the parameter.
If you want a quick workaround though, then the sender object in the button click event should be the button you clicked, and its DataContext property should be the list item. A nasty hack but a lot less work than going down the ICommand path if you are just messing around learning the tools.
private void Button_Click(object sender, RoutedEventArgs e) {
App.ViewModel.Items.Remove((ItemViewModel)((Button)sender).DataContext);
}

MVVM Light toolkit Interaction.Triggers does not fire in datatemplate

I can use Interaction.Triggers to catch the textchanged event on a textbox like so:
<TextBox Text="{Binding Title}" Style="{StaticResource GridEditStyle}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<cmd:EventToCommand Command="{Binding TextChanged}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
However when I use it in a datatemplate for a listview celltemplate as follows:
<ListView ItemsSource="{Binding LangaugeCollection}" SelectedItem="{Binding SelectedLangauge}" BorderThickness="0" FontFamily="Calibri" FontSize="11">
<ListView.View>
<GridView>
<GridViewColumn Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate >
<Grid>
<TextBlock Text="{Binding Title}" Style="{StaticResource GridBlockStyle}">
</TextBlock>
<TextBox Text="{Binding Title}" Style="{StaticResource GridEditStyle}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<cmd:EventToCommand Command="{Binding TextChanged}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
the event will not trigger.
Does anyone know why this does not trigger and how to fix it?
When you are in a DataTemplate, the DataContext might not be what you expect. Typically the DataContext in a DataTemplate is set to the item that the DataTemplate represents. If your TextChanged command is on the "main viewmodel" instead of the data item, you need to be more precise in the way that you specify the data binding, for example:
Command="{Binding Source={StaticResource Locator}, Path=Main.TextChanged}"
You can see the issue when you run the code in debug mode (F5) in Studio and observe the Output window. A Data Error will be shown if the DataContext is incorrectly set.
Cheers,
Laurent
It seems something handles the event before the TextBox. Maybe you could listen to Title property (collection) changed inside you ViewModel, because anyway you are calling TextChanged on ViewModel inside the trigger, I suppose.
Btw I think you're missing TwoWay mode in your binding expression.
Hope this helps.

Resources