The parameter is incorrect error with stackpanel - c#

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!

Related

Button content does not change in real time

I have a button. I want it to be a favorite toggle button inside a listbox. See code below:
<Page
x:Class="W.Pages.ExPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Workout_EF.Pages"
xmlns:converter="using:W.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:W.Model"
mc:Ignorable="d">
<Page.Resources>
<converter:FavoriteValueConverter x:Key="favoriteConverter" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListBox Name="MyListbox"
SelectionMode="Single"
ItemsSource="{x:Bind exs}"
SelectionChanged="MyListbox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="data:Ex">
<StackPanel Orientation="Horizontal">
<Button Name="IsFavoriteToggle" Click="IsFavoriteToggle_Click">
<Button.Content>
<TextBlock
x:Name="isFavoriteTextBlock"
Text="{x:Bind IsFavorite, Converter={StaticResource favoriteConverter}}"
FontFamily="Segoe MDL2 Assets"/>
</Button.Content>
</Button>
<TextBlock
VerticalAlignment="Center"
FontSize="16"
Text="{Binding ExName}"
Margin="20,0,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Page>
My problem is when I hit this button it does not change the icon in it (from emtpy star to full star and vice versa) in real time.
If the listbox will be loaded again the correct icon is displayed.
The code behind is:
namespace W.Pages
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class ExPage : Page
{
ObservableCollection<Exs> exs = new ObservableCollection<Exs>();
public ExPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
List<Exs> tmpEx = e.Parameter as List<Exs>;
foreach (Exs item in tmpEx)
{
exs.Add(item);
}
}
private void IsFavoriteToggle_Click(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
int index = MyListbox.Items.IndexOf(button.DataContext);
Ex ex = (Exs)MyListbox.Items[index];
DAL.SetToFavorite(ex, !ex.IsFavorite);
}
}
}
I noticed that there is some problem with the itemsource maybe. It needed to change its content after hitting the button. But I am not sure.
This is a common mistake that everyone make and that is ObservableCollection<T> is actually informing the binders about the changes in the collection not the objects in the collection.
You have a IsFavorite property in your Esx class that the button need to know about changes but for that, Esx needs to implement INotifyPropertyChanged
See this and if you need more help post the code for Esx class maybe we can help.
As Emaud said, you have to implement the INotifyPropertyChanged interface in your Esx class. And you also have to set set the Mode to OneWay in your binding because for x:Bind the default mode is OneTime so it does NOT listen to any changes.
Text="{x:Bind IsFavorite, Mode=OneWay, Converter={StaticResource favoriteConverter}}"

UWP: ScrollViewer inside an ItemsPanel

I want to create a pivot, with a DataBinding to a List of PivotItems.
Each of these items should be surrounded by a ScrollViewer.
Unfortunately it doesn't work the way I was thinking....
My code:
MainPage:
<Page
x:Class="PivotSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PivotSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot Title="Pivot" SelectedItem="{Binding CurrentPivotItem, Mode=TwoWay}" ItemsSource="{Binding PivotItems}">
<Pivot.ItemTemplate>
<DataTemplate>
<ScrollViewer>
<UserControl Content="{Binding Content}"/>
</ScrollViewer>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
</Grid>
UserControl (the second UserControl is the same):
<UserControl
x:Class="PivotSample.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PivotSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<StackPanel Background="Yellow">
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
<TextBlock Text="Test" FontSize="30" HorizontalAlignment="Center"/>
</StackPanel>
ViewModel:
public class ViewModelMainPage : ViewModelBase
{
private IList<PivotItem> _pivotItems;
private PivotItem _currentPivotItem;
public IList<PivotItem> PivotItems
{
get { return _pivotItems; }
set { _pivotItems = value; }
}
public PivotItem CurrentPivotItem
{
get { return _currentPivotItem; }
set
{
OnPropertyChanged(nameof(CurrentPivotItem));
_currentPivotItem = value;
}
}
}
When I start the project comes following message: "The program '[2940] name.exe' has exited with code -1 (0xffffffff).
But when I replace the ScrollViewer with a Grid or StackPanel it will works but then I won't see all of my PivotItem.
Any ideas?
(Putting a new answer, as the question has changed it's context.)
Looks like the Pivot Control screws up, if you use a list of PivotItems at it'
s ItemsSource.
Anyway: That's not the way DataBindings are intended.
As the name suggests, you bind to Data, not to controls or UI Elements. PivotItems are UI Controls (although they are more of a logical than a visual representation) and should not be part of your ViewModel.
Just change the type in your ViewModel to some actual data (a List of String, Object, or whatever classes you create) and it works fine
Alternatively, if you want to place a fixed content inside a Pivot Control, you don't need to bind it at all and you can just place the PivotItems directly in Xaml:
<Pivot>
<PivotItem Header="First Item">
<!-- your content display here -->
</PivotItem>
<PivotItem Header="Secont Item">
<!-- your content display here -->
</PivotItem>
</Pivot>
(Outdated, as question was updated)
You can only set ItemControls as ItemsPanelTemplate and the Scrollviewer ist not an ItemsControl, but a ContentControl (it only wraps a single child and does not display multiple items).
Also, ItemsPanelTemplate is the wrong target for what you are trying to achieve: If you want to change the content of the PivotItems inside the Pivot, just set the regular ItemTemplate.
<Pivot>
<Pivot.ItemTemplate>
<DataTemplate>
<ScrollViewer>
<!-- your content display here -->
</ScrollViewer>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>

How to add controls dynamically to a UserControl through user's XAML?

I want to create a user control that contains a TextBlock and a StackPanel that will allow the user to add his/her own controls to the user control dynamically in XAML.
Here is the sample XAML for my UserControl:
<UserControl x:Class="A1UserControlLibrary.UserControlStackPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="300">
<StackPanel>
<TextBlock Text="I want the user to be able to add any number of controls to the StackPanel below this TextBlock."
FontFamily="Arial" FontSize="12" FontWeight="DemiBold" Margin="5,10,5,10" TextWrapping="Wrap"/>
<StackPanel>
<!-- I want the user to be able to add any number of controls here -->
</StackPanel>
</StackPanel>
</UserControl>
I would like the user to be able to embed this user control in their XAML and add their own controls to the stack panel of the user control:
<uc:A1UserControl_StackPanel x:Name="MyUserControl_Test" Margin="10" Height="100">
<Button Name="MyButton1" Content="Click" Height="30" Width="50"/>
<Button Name="MyButton2" Content="Click" Height="30" Width="50"/>
<Button Name="MyButton3" Content="Click" Height="30" Width="50"/>
</uc:A1UserControl_StackPanel>
Doing this using the above XAML does not work. Any ideas?
You can do that, although not quite like your example. You need two things. The first is to declare a DependencyProperty of type UIElement, of which all controls extend:
public static DependencyProperty InnerContentProperty = DependencyProperty.Register("InnerContent", typeof(UIElement), typeof(YourControl));
public UIElement InnerContent
{
get { return (UIElement)GetValue(InnerContentProperty); }
set { SetValue(InnerContentProperty, value); }
}
The second is to declare a ContentControl in the XAML where you want the content to appear:
<StackPanel>
<TextBlock Text="I want the user to be able to add any number of controls to the StackPanel below this TextBlock."
FontFamily="Arial" FontSize="12" FontWeight="DemiBold" Margin="5,10,5,10" TextWrapping="Wrap"/>
<StackPanel>
<ContentControl Content="{Binding InnerContent, RelativeSource={RelativeSource AncestorType={x:Type YourXmlNamspacePrefix:ContentView}}}" />
</StackPanel>
</StackPanel>
In my opinion, if you use StackPanels, you could find that your content does not get displayed correctly... I'd advise you to use Grids for layout purposes for all but the simplest layout tasks.
Now the one difference to your example is in how you would use your control. The InnerContent property is of type UIElement, which means that it can hold one UIElement. This means that you need to use a container element to display more than one item, but it has the same end result:
<YourXmlNamspacePrefix:YourControl>
<YourXmlNamspacePrefix:YourControl.InnerContent>
<StackPanel x:Name="MyUserControl_Test" Margin="10" Height="100">
<Button Content="Click" Height="30" Width="50"/>
<Button Content="Click" Height="30" Width="50"/>
<Button Content="Click" Height="30" Width="50"/>
</StackPanel>
</YourXmlNamspacePrefix:YourControl.InnerContent>
</YourXmlNamspacePrefix:YourControl>
And the result:
UPDATE >>>
For the record, I know exactly what you want to do. You, it seems, do not understand what I am saying, so I'll try to explain it one last time for you. Add a Button with the Tag property set as I've already shown you:
<Button Tag="MyButton1" Content="Click" Click="ButtonClick" />
Now add a Click handler:
private void ButtonClick(object sender, RoutedEventArgs e)
{
Button button = (Button)sender;
if (button.Tag = "MyButton1") DoSomething();
}
That's all there is to it.

Conditional rendering in DataTemplate

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.

Data binding for two textbox

I have 2 textbox, each in a different listview. First textbox is supposed to show data from a xml file. So when i click on the textbox, the data in the first textbox will show on the second textbox. I did this by doing a very big round about, getting the specific object when i click it and append to another listview. Is there a shorter way to do this through binding by element name in the xaml? My elementName in textbox1 will be the name for textbox2. I try doing it, but I am not sure what my path should be?
Sorry for not including my xaml.
<Window x:Class="GridViewTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:local="clr-namespace:GridViewTest"
Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="541" d:DesignWidth="858" SizeToContent="WidthAndHeight">
<Window.Resources>
<local:PacketList x:Key="PacketList"/>
<local:BindableSelectionTextBox x:Key="BindableSelectionTextBox"/>
</Window.Resources>
<Grid Height="500" Width="798">
<Grid.RowDefinitions>
<RowDefinition Height="142*" />
<RowDefinition Height="145*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="234*" />
<ColumnDefinition Width="233*" />
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding}" x:Name="lvItems" Grid.RowSpan="2" Grid.ColumnSpan="2">
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn Header="Header" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBox Name ="A" Tag="Header" Text="{Binding SelectedText, Path=headerObj.headervalue}" PreviewMouseLeftButtonUp="Handle_Click"
IsReadOnly="True" BorderThickness="0" >
</TextBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<ListView Margin="0,245,0,8" Grid.ColumnSpan="2" Grid.RowSpan="2" >
<TextBox Name="headText" Text="{Binding SelectedText,ElementName=A}"/>
</ListView>
</Grid>
Firstly let us have some education on NameScoping in WPF. In WPF any Bindings within Templates are scoped to that Template only. Also any element named within a template wont be available for Binding.ElementName reference outside the template.
So in your case TextBox A cannot be referred by TextBox headText as textbox A is name-scoped under GridViewColumn.CellTemplate.
Also why is headText textbox under a ListView? ItemsControls like ListBox, ListView, DataGrid should not be used as panels or containers to host single elements. Their intention is to show multiple items. Use Panels or ContentControl instead.
<Grid Margin="0,245,0,8" Grid.ColumnSpan="2" Grid.RowSpan="2" >
<TextBox Name="headText" Text="{Binding SelectedText,ElementName=A}"/>
</Grid>
OR
<ContentControl Margin="0,245,0,8" Grid.ColumnSpan="2" Grid.RowSpan="2" >
<TextBox Name="headText" Text="{Binding SelectedText,ElementName=A}"/>
</ContentControl>
Now to synchronize selection between two textboxes use the following trick...
XAML
<TextBox Name="SelectionSource"
Tag="{Binding ElementName=SelectionTarget}"
SelectionChanged="SelectionSource_SelectionChanged" />
<TextBox Name="SelectionTarget"
Text="{Binding SelectedText, ElementName=SelectionSource,
Mode=TwoWay, UpdateSourceTrigger=Explicit}" />
Code Behind ...
private void SelectionSource_SelectionChanged(object sender, RoutedEventArgs e)
{
var targetTextBox = ((TextBox) sender).Tag as TextBox;
if (targetTextBox != null)
{
var bndExp
= BindingOperations.GetBindingExpression(
targetTextBox, TextBox.TextProperty);
if (bndExp != null)
{
bndExp.UpdateTarget();
}
}
}
If you are using MVVM then handle this SelectionSource_SelectionChanged event in attached behavior.
EDIT 2:
Now in case if one text box is part of ListBox template and other is outside the template then use content control hack...
XAML:
<Window.Resources>
<TextBox x:Key="SelectionTarget"
Text="{Binding Tag.SelectedText,
RelativeSource={RelativeSource Self},
Mode=TwoWay,
UpdateSourceTrigger=Explicit}" />
</Window.Resources>
<StackPanel>
<ListBox>
<ListBox.ItemsSource>
<x:Array Type="{x:Type System:String}">
<System:String>Test String 1</System:String>
<System:String>Test String 2</System:String>
<System:String>Test String 3</System:String>
</x:Array>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="SelectionSource"
Text="{Binding Path=., Mode=TwoWay}"
Tag="{StaticResource SelectionTarget}"
SelectionChanged="SelectionSource_SelectionChanged" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ContentControl Content="{StaticResource SelectionTarget}">
</ContentControl>
</StackPanel>
Code Behind
private void SelectionSource_SelectionChanged(
object sender, RoutedEventArgs e)
{
var targetTextBox
= ((TextBox) sender).Tag as TextBox;
if (targetTextBox != null)
{
targetTextBox.Tag = (TextBox) sender;
var bndExp
= BindingOperations.GetBindingExpression(
targetTextBox, TextBox.TextProperty);
if (bndExp != null)
{
bndExp.UpdateTarget();
}
}
}
Hope this helps.
I'm not really sure what's going on with "SelectedText" you are trying to bind to, but if all you are trying to do is display the "lvItems" SelectedItem text in your "headText" TextBox the following should work
<TextBox Name="headText" Text="{Binding ElementName=lvItems, Path=SelectedItem.headerObj.headervalue}" />
You'll need to change your TextBox "A" binding as well.
<TextBox Name ="A" Tag="Header" Text="{Binding headerObj.headervalue}" IsReadOnly="True" BorderThickness="0" >
</TextBox>
Assuming that headerObj is a property of the Packet class, and headervalue is a property of that, and headervalue is the value you wish to bind to.
The text in "headText" will update when the SelectedItem is changed (not when the TextBox is clicked).

Categories