Conditional rendering in DataTemplate - c#

I'm following the Absolute Beginners Series on Channel9 and we've been told to implement some features that are not presented in the series, just as a challenge to learn something else.
What we have is a DataTemplate used to build some "tiles"-like controls and we use them in a LongListSelector.
What I need to do is to add a context menu to those tiles to perform some extra operations on them.
Now, one of those operations must be performed only on a certain type of tile, depending on which was the collection bound to the LongListSelector.
Here's the page code:
<phone:PhoneApplicationPage
x:Class="SoundBoard.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DataContext="{d:DesignData SampleData/SampleData.xaml}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="SoundTileDataTemplate">
<Grid Name="TileGrid" Background="{StaticResource PhoneAccentBrush}" Margin="0,0,12,12">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="{Binding Path=LocalizedResources.PinToStartMessage, Source={StaticResource LocalizedStrings}}"/>
<toolkit:MenuItem IsEnabled="False" Header="{Binding Path=LocalizedResources.DeleteSoundMessage, Source={StaticResource LocalizedStrings}}"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Grid VerticalAlignment="Top" HorizontalAlignment="Right" Width="40" Height="40" Margin="0,6,6,0">
<Ellipse Stroke="{StaticResource PhoneForegroundBrush}" StrokeThickness="3"/>
<Image Source="/Assets/AppBar/Play.png"></Image>
</Grid>
<StackPanel VerticalAlignment="Bottom">
<TextBlock Text="{Binding Title}" Margin="6,0,0,6"/>
</StackPanel>
</Grid>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<Grid x:Name="LayoutRoot" Background="Transparent">
<MediaElement Name="AudioPlayer" Volume="1"/>
<phone:Pivot Title="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}">
<phone:PivotItem Header="{Binding Animals.Title}">
<phone:LongListSelector Margin="0,0,-12,0" ItemsSource="{Binding Animals.Items}" LayoutMode="Grid" GridCellSize="150,150" ItemTemplate="{StaticResource SoundTileDataTemplate}" SelectionChanged="LongListSelector_SelectionChanged">
</phone:LongListSelector>
</phone:PivotItem>
<phone:PivotItem Header="{Binding Cartoons.Title}">
<phone:LongListSelector Margin="0,0,-12,0" ItemsSource="{Binding Cartoons.Items}" LayoutMode="Grid" GridCellSize="150,150" ItemTemplate="{StaticResource SoundTileDataTemplate}" SelectionChanged="LongListSelector_SelectionChanged">
</phone:LongListSelector>
</phone:PivotItem>
<phone:PivotItem Header="{Binding Taunts.Title}">
<phone:LongListSelector Margin="0,0,-12,0" ItemsSource="{Binding Taunts.Items}" LayoutMode="Grid" GridCellSize="150,150" ItemTemplate="{StaticResource SoundTileDataTemplate}" SelectionChanged="LongListSelector_SelectionChanged">
</phone:LongListSelector>
</phone:PivotItem>
<phone:PivotItem Header="{Binding Warnings.Title}">
<phone:LongListSelector Margin="0,0,-12,0" ItemsSource="{Binding Warnings.Items}" LayoutMode="Grid" GridCellSize="150,150" ItemTemplate="{StaticResource SoundTileDataTemplate}" SelectionChanged="LongListSelector_SelectionChanged">
</phone:LongListSelector>
</phone:PivotItem>
<phone:PivotItem Header="{Binding CustomSounds.Title}">
<phone:LongListSelector Margin="0,0,-12,0" ItemsSource="{Binding CustomSounds.Items}" LayoutMode="Grid" GridCellSize="150,150" ItemTemplate="{StaticResource SoundTileDataTemplate}" SelectionChanged="LongListSelector_SelectionChanged">
</phone:LongListSelector>
</phone:PivotItem>
</phone:Pivot>
</Grid>
</phone:PhoneApplicationPage>
Now, what I need to do is to enable the second Toolkit:MenuItem only when the control is loaded in the last LongListSelector.
Is it possible to write a boolean expression in the item's IsEnabled that returns true if the items of the DataTemplate have the CustomSounds type or do I need to write two different DataTemplate to handle this situation?
EDIT:
I've changed some code
<phone:PhoneApplicationPage
x:Name="SBMainPage"
...
<toolkit:MenuItem IsEnabled="{Binding Path=IsDeleteEnabled, ElementName=SBMainPage}" Header="{Binding Path=LocalizedResources.DeleteSoundMessage, Source={StaticResource LocalizedStrings}}" Tap="DeleteSoundHandler"/>
but now the boolean value returned by IsDeleteEnabled property is never updated, so it takes the false that is given when the property is read the first time and it never changes it!

A converter will do what you want:
class TypeToBoolConverter :IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.GetType() == typeof(CustomSounds);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
and that you can use:
<toolkit:MenuItem IsEnabled="{Binding ,Converter={StaticResource myTypeConverter}}" ...

Verify that IsDeleteEnabled adheres to INotifyPropertyChanged. Frankly that is what I do/have done by simply adding a status flag boolean on the Model View and hooking up page logic by binding.

Related

wpf responsive ListBox / Grid

I am trying to recreate the following responsive grid (see 'Desired behavior' link below) in WPF. But, I am struggling to find the best way to achieve this.
Ideally, I would like a horizontal list of tiles that grow and shrink in size to fit the available space. As a starting point, I have a list box that wraps, but i'm left with white space when re-sizing. Any pointers would be appreciated.
Current Wrap Panel:
:
Desired behavior
My current Code:
<Window x:Class="WrappingListbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="Wrapping Listbox"
Width="525"
Height="350"
mc:Ignorable="d">
<Grid>
<ListBox x:Name="listbox1" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Vertical" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="20" HorizontalAlignment="Center">
<Viewbox>
<Grid x:Name="backgroundGrid"
Width="60"
Height="60">
<Rectangle x:Name="Rect" Fill="green" />
</Grid>
</Viewbox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<WrapPanel HorizontalAlignment="Left" VerticalAlignment="Top" />
</Grid>
this will solve the size problem for you (by binding the dimensions of the item to the dimensions of the listbox but I think you need to work more on it but here is just the start )
// add this in your window definition
xmlns:Local="clr-namespace:WpfApplication2"
//then here is your listbox
<ListBox x:Name="listbox1" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.Resources>
<Local:DimentionConverter x:Key="Converter" />
</ListBox.Resources>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Vertical" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="20" HorizontalAlignment="Center" VerticalAlignment="Center" >
<Viewbox>
<Grid x:Name="backgroundGrid"
Height="{Binding RelativeSource={RelativeSource AncestorType=ListBox},Path=ActualWidth,Converter={StaticResource ResourceKey=Converter},ConverterParameter=5}"
Width="{Binding RelativeSource={RelativeSource AncestorType=ListBox},Path=ActualWidth,Converter={StaticResource ResourceKey=Converter},ConverterParameter=5}" >
<Rectangle x:Name="Rect" Fill="green" />
</Grid>
</Viewbox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
public class DimentionConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return (double)value / double.Parse(parameter as string);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
}
Important Notice : you can't do it without the converter you have to use it to decide how big you want your item compared to the hosting listbox ofcourse you can change the value as you wish I made it 5 as an example

Setting VirtualizingStackPanel.IsVirtualizing in a Windows 8.1 Store App

I have a XAML page in a Windows 8.1 Store App. I set the data context for a ListView but I initially have it collapsed. What I am trying to do is toggle the visibility of some of the elements in the ListView before making it visible. But it doesn't load them unless it becomes visible. So, to forced it to load the items, I am trying to set "IsVirtualizing" to false so that I don't have to worry about it (and I don't mind the hit in performance since I won't have that many items). But for all the examples I look at, all I get is
The property "IsVirtualizing" does not have an accessible setter.
Not sure what is going on here.
Here is the relevant piece of code with the other contents stripped out.
<common:LayoutAwarePage
x:Class="FlashMe.DeckView"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FlashMe"
xmlns:common="using:FlashMe.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
>
<ScrollViewer x:Name="deckScrollViewer" Grid.Row="1" VerticalScrollMode="Disabled" HorizontalScrollMode="Enabled" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled" Margin="0,15,0,0">
<StackPanel x:Name="deckStackPanel" Orientation="Horizontal">
<Grid Width="100" x:Name="MarginBuffer" />
<ListView x:Name="cardsListViewDisplay" Visibility="Collapsed" SelectionMode="None" Width="500" ItemsSource="{Binding Path=FlashCardsAsList}" VirtualizingStackPanel.IsVirtualizing="False">
<ListView.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Vertical" Width="490" Height="400" RightTapped="FlashCardRightClicked">
<Grid Width="490" Height="200" Background="Gainsboro">
<TextBlock Text="{Binding Path=Front}"
Foreground="Black"
Style="{StaticResource GroupHeaderTextStyle}"
Margin="4,0,4,4"
FontWeight="SemiBold"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap"
MaxWidth="410"/>
</Grid>
<Grid Width="500" Height="200" Background="{Binding ElementName=deckStackPanel, Path=DataContext.DeckColorBrush}">
<TextBlock Text="{Binding Path=Back}"
Foreground="White"
Style="{StaticResource GroupHeaderTextStyle}"
Margin="4,0,0,4"
FontWeight="SemiBold"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap"
MaxWidth="410"/>
</Grid>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</ScrollViewer>
</common:LayoutAwarePage>
In Windows Store Apps, the IsVirtualizing property is read-only.
From the Remarks section on the VirtualizingStackPanel.IsVirtualizingProperty page on MSDN:
VirtualizingStackPanel.IsVirtualizing is an atypical attached property
because it does not have a Set accessor, and thus is not really a XAML
attached property with a markup usage. Instead,
VirtualizingStackPanel.IsVirtualizing functions as a sentinel whereby
child elements can query the VirtualizingStackPanel parent, and
determine whether virtualization is being used. ...

Binding to an element of the DataTemplate on Windows Phone

Plain and simple: I need to bind some properties of the ContextMenu items to a property of their parent in the DataTemplate.
I can't find a way to access it because ElementName doesn't work and RelativeSource allows me to use just Self or TemplatedParent.
Here's my code:
<telerikPrimitives:RadDataBoundListBox Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="3"
ItemsSource="{Binding Transfers.Keys, Source={StaticResource TransfersManager}, Mode=OneWay}">
<telerikPrimitives:RadDataBoundListBox.ItemTemplate>
<DataTemplate>
<toolkit:TransferControl x:Name="TransferControl"
Header="{Binding Converter={StaticResource TransferMonitorToDocumentTitleConverter}}"
IsContextMenuEnabled="False"
Icon="{Binding Converter={StaticResource TransferMonitorToDocumentIconUriConverter}}"
AutoHide="False"
Monitor="{Binding}"
Language="it-IT"
StatusTextBrush="Black"
Foreground="Black">
<toolkit:TransferControl.HeaderTemplate>
<DataTemplate>
<StackPanel>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="item1"
IsEnabled="{Binding Monitor Property in the TransferControl object}"
/>
<toolkit:MenuItem Header="item2"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Rectangle Fill="Transparent" Height="30"/>
<ContentControl Content="{Binding}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="Black" />
</StackPanel>
</DataTemplate>
</toolkit:TransferControl.HeaderTemplate>
</toolkit:TransferControl>
</DataTemplate>
</telerikPrimitives:RadDataBoundListBox.ItemTemplate>
What I'm trying to bind is:
<toolkit:MenuItem Header="item1"
IsEnabled="{Binding Monitor Property in the TransferControl object}"
/>
and I'd like to bind it to the Monitor property of the <toolkit:TransferControl x:Name="TransferControl" ... /> object.
I was able to solve this my simply creating a new UserControl that holds the content of your ListBox. I used the LongListSelector. Here is a solution that works.
First the XAML for the page:
<phone:LongListSelector Margin="0,0,-12,0" ItemsSource="{Binding Items}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<local:WindowsPhoneControl/>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
Then the UserControl. This was nothing special, just a wrapper.
<UserControl x:Class="PivotApp1.WindowsPhoneControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<phone:LongListSelector x:Name="TransferControl" Margin="0,0,-12,0"
ItemsSource="{Binding Items}"
toolkit:TiltEffect.IsTiltEnabled="True">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="item1"
IsEnabled="{Binding DataContext.Monitor, ElementName=TransferControl}"/>
<toolkit:MenuItem Header="item2"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<StackPanel Margin="0,0,0,17">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
</UserControl>
With this solution the Monitor property was hit when rendering the list. It will not be hit when opening the menu. Of course if you fire the propertyChanged for monitor, it will get the value again.
The property you want to bind to seems to be bound to the DataContext itself. Why not just bind to it (the DataContext) in the HeaderTemplate? All you need to do is bind the Header property to the DataContext, instead of converting it to something else, and then use the Converter inside the HeaderTemplate. Something like this:
<telerikPrimitives:RadDataBoundListBox.ItemTemplate>
<DataTemplate>
<toolkit:TransferControl x:Name="TransferControl"
Header="{Binding}"
IsContextMenuEnabled="False"
Icon="{Binding Converter={StaticResource TransferMonitorToDocumentIconUriConverter}}"
AutoHide="False"
Monitor="{Binding}"
Language="it-IT"
StatusTextBrush="Black"
Foreground="Black">
<toolkit:TransferControl.HeaderTemplate>
<DataTemplate>
<StackPanel>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="item1"
IsEnabled="{Binding}"
/>
<toolkit:MenuItem Header="item2"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Rectangle Fill="Transparent" Height="30"/>
<ContentControl Content="{Binding Converter={StaticResource TransferMonitorToDocumentTitleConverter}}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="Black" />
</StackPanel>
</DataTemplate>
</toolkit:TransferControl.HeaderTemplate>
</toolkit:TransferControl>
</DataTemplate>
</telerikPrimitives:RadDataBoundListBox.ItemTemplate>
On a side note, I think you may be doing too much binding. Bindings and converters can lead to bad performance and sometimes it's just faster and easier to do things without bindings.
Btw, may I ask what does the TransferMonitorToDocumentTitleConverter do?
Update
It seems there is a bug in the toolkit. The Header property's getter casts the object to string and so, even though the property is of type object, you can only set it to a string - otherwise an exception is thrown in the getter, which is used internally.
Here's a possible workaround:
Extend the TransferControl like this:
public class TransferControlFixed : TransferControl {
public static readonly DependencyProperty HeaderFixedProperty = DependencyProperty.Register("HeaderFixed", typeof(object), typeof(TransferControlFixed), new PropertyMetadata(null));
public object HeaderFixed {
get {
return GetValue(HeaderFixedProperty);
}
set {
SetValue(HeaderFixedProperty, value);
}
}
public override void OnApplyTemplate() {
base.OnApplyTemplate();
var control = (ContentControl)this.GetTemplateChild("Header");
control.SetBinding(ContentControl.ContentProperty, new Binding() {
Path = new PropertyPath("HeaderFixed"),
Source = this
});
}
}
Use TransferControlFixed instead of TransferControl and bind the HeaderFixed instead of the Header property.
It seems like a reasonably simple workaround.

How to change the properties of a contextmenu in a datatemplate in WP7?

What I want
change the properties(e.g. background) of a context menu in a datatemplate in the runtime from the code behind.
What is the XAML
<DataTemplate x:Key="ListsDataTemplate">
<StackPanel x:Name="stackPanel" Margin="0,0,0,10">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu x:Name="myMenu" IsFadeEnabled="False" IsZoomEnabled="False">
<toolkit:MenuItem x:Name="edit" Header="{Binding LocalStrings.bt_menu_Edit, Source={StaticResource LocalizedResources}}" Click="menuItemEdit_Click" />
<toolkit:MenuItem x:Name="postpone" Header="{Binding LocalStrings.bt_menu_Postpone, Source={StaticResource LocalizedResources}}" Click="menuItemPostpone_Click" />
<toolkit:MenuItem x:Name="email" Header="{Binding LocalStrings.bt_menu_Email, Source={StaticResource LocalizedResources}}" Click="menuItemEmail_Click" />
<toolkit:MenuItem x:Name="sms" Header="{Binding LocalStrings.bt_menu_Sms, Source={StaticResource LocalizedResources}}" Click="menuItemSMS_Click" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<ListBox
HorizontalAlignment="Left"
DataContext="{Binding}"
ItemTemplate="{StaticResource ListsDataTemplate}"
VerticalAlignment="Top"
Width="432"
Margin="0,81,0,0"
x:Name="myListBox">
</ListBox>
Add a Loaded="myMenu_Loaded" handler to myMenu, and in that handler declare var myMenu = (ContextMenu)sender;.
Since myMenu is in a DataTemplate and is a template for creating objects rather than the instance that will actually be used on the page, no field is auto-generated for it.

The parameter is incorrect error with stackpanel

So I am working on a windows phone app, and I am trying to move elements between two stackpanels (which are basically the two main screens of my app).
I have a pivot item which looks like this:
<controls:Pivot Title="MY APPLICATION">
<!--Pivot item one-->
<controls:PivotItem Header="All Tokens">
<ListBox x:Name="AllTokenListBox" Margin="0,0,0,0">
<StackPanel x:Name="AllTokenStack"></StackPanel>
</ListBox>
</controls:PivotItem>
<!--Pivot item two-->
<controls:PivotItem Header="My Tokens">
<ListBox x:Name="MyTokenListBox" Margin="0,0,0,0">
<StackPanel x:Name="myTokenStack"></StackPanel>
</ListBox>
</controls:PivotItem>
</controls:Pivot>
When an item in the AllTokenStack is double tapped, I want to move it over to the myTokenStack. When I do that, the program crashes and says "The parameter is incorrect".
It only does this if I am NOT in debugging mode (so if the phone is unplugged from the computer and I try to run the app). If it is in debugging mode, it works fine.
Here is the code I am using to transfer the object over:
private void container_Tap(object sender, GestureEventArgs e) {
if (AllTokenContainer.Children.Contains(this)) {
AllTokenContainer.Children.Remove(this);
MyTokenContainer.Children.Add(this);
}
}
Does anyone know how to resolve this strange bug?
EDIT
Just to make it clear. The C# code is inside a class which I called Token. The Token class is a user control. It is that control which the user taps to trigger the event. Is this the wrong way to do it?
Stacktrace from the exception:
at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
at MS.Internal.XcpImports.Collection_AddValue[T](PresentationFrameworkCollection`1 collection, CValue value)
at MS.Internal.XcpImports.Collection_AddDependencyObject[T](PresentationFrameworkCollection`1 collection, DependencyObject value)
at System.Windows.PresentationFrameworkCollection`1.AddDependencyObject(DependencyObject value)
at System.Windows.Controls.UIElementCollection.AddInternal(UIElement value)
at System.Windows.PresentationFrameworkCollection`1.Add(UIElement value)
at MTG_Token_Tracker.TokenGraphic.container_Tap(Object sender, GestureEventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
Rather than using UserControls, I would try to use databinding, with ObservableCollection's of token classes in the back end. Moving things around becomes a little easier when the GUI part gets taken care of by the binding.
For an example of how to do this, I created a Windows Phone project using the "Windows Phone Pivot Application" template to use as a base, and named it "TokenAnswer" (if you do this and paste in the code below, you should have a working example).
To MainPage.xaml, I added the DoubleTap event to the first list's item template, and set the SecondListBox binding to "Items2". I also set Tag={Binding}, which sets the Tag variable to the ItemViewModel behind the GUI item (this is done so I can access the item tapped, there are other ways to do this, but this one is easy enough for this example).
<phone:PhoneApplicationPage
x:Class="TokenAnswer.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Pivot Control-->
<controls:Pivot Title="MY APPLICATION">
<!--Pivot item one-->
<controls:PivotItem Header="first">
<!--Double line list with text wrapping-->
<ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel DoubleTap="Token_DoubleTap" Tag="{Binding}" Margin="0,0,0,17" Width="432" Height="78">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PivotItem>
<!--Pivot item two-->
<controls:PivotItem Header="second">
<!--Triple line list no text wrapping-->
<ListBox x:Name="SecondListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items2}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock Text="{Binding LineOne}" TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineThree}" TextWrapping="NoWrap" Margin="12,-6,0,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PivotItem>
</controls:Pivot>
</Grid>
</phone:PhoneApplicationPage>
In the MainViewModel.cs, I added a second collection ("Items2") and initialized it in the constructor, this collection is for the second listbox:
public MainViewModel()
{
this.Items = new ObservableCollection<ItemViewModel>();
this.Items2 = new ObservableCollection<ItemViewModel>();
}
/// <summary>
/// A collection for ItemViewModel objects.
/// </summary>
public ObservableCollection<ItemViewModel> Items { get; private set; }
public ObservableCollection<ItemViewModel> Items2 { get; private set; }
Finally, in MainPage.xaml.cs, I added the codebehind for the event handler, to remove the item from the first collection, and add it to the second.
private void Token_DoubleTap(object sender, GestureEventArgs e)
{
var token = (sender as StackPanel).Tag as ItemViewModel;
App.ViewModel.Items.Remove(token);
App.ViewModel.Items2.Add(token);
}
Hopefully you can use this as a guide to help your current project!

Categories