I am using a ContextMenu within a LongListSelector so that I can delete some items in the list bounded to the LLS.
I am following a recent guide here in order to implement the LLS (though I am not using the JumpList). The only thing I've changed is to have the base group class extend ObservableCollection instead of List.
The issue I am having is that once I've implemented the ContextMenu and delete from there, I can delete from the same "location" in teh visible list twice and then it would crash.
Debugging shows that after the second delete, the Datacontext of the MenuItem returns the previous item that was deleted. So when I search for it in the list, the index I get is -1. I can catch this but I don't know how to then find out what was really selected as the item.
My XAML section for the contextMenu is as below:
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid toolkit:TiltEffect.IsTiltEnabled="True">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu x:Name="conmen" Loaded="ContextMenu_Loaded">
<toolkit:MenuItem Header="Delete" Click="DeleteItem_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="{StaticResource PhoneInverseBackgroundBrush}" Padding="{StaticResource PhoneTouchTargetOverhang}">
<TextBlock Text="{Binding Usr, StringFormat='x{0}'}" FontSize="32" HorizontalAlignment="Left" Width="48"/>
</Border>
<Border Grid.Column="1" Background="{StaticResource PhoneInverseBackgroundBrush}" Padding="{StaticResource PhoneTouchTargetOverhang}">
<TextBlock Text="{Binding Name}" FontSize="32" HorizontalAlignment="Left" />
</Border>
<Border Grid.Column="2" Background="{StaticResource PhoneInverseBackgroundBrush}" Padding="{StaticResource PhoneTouchTargetOverhang}">
<TextBlock Text="{Binding Type, StringFormat=\{0:C\}}" FontSize="32" HorizontalAlignment="Right" />
</Border>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
And this is the start of my delete_click function to remove the item:
private void DeleteItem_Click(object sender, RoutedEventArgs e)
{
var menItem = (MenuItem)sender;
editCartItem = (Model.Cartitem)menItem.DataContext;
cartIndex = editCartItem.Id;
deleteIndex = this.cartList.FindIndex(FindItem);
After two deletes, the (Model.Cartitem)menItem.DataContext returns the previously deleted item.
I have been searching for a while and have found similar cases for different frameworks and scenarios from some years before. I wanted to know if there was an updated method for doing this in WP8.
I have seen suggestions in manually re-assigning the datacontext of the ContextMenu with a Loaded or Opened event, but the DataContext still relies on a specific item in the LLS. So I can't just point it's context to the LLS's.
I've also seen that it's been pointed to as a bug with a patch here which seems exactly like my issue, but I had no idea on how to apply the patch or if it even pertained to my situation with WP8.
I've also been ensuring that the LLS's selected item is cleared and have tried re-assigning it's itemSource after each operation to no avail.
Any help or advice in the right direction would be great. I've seen some posts on here about this, but I believe I've already passed those points (such as simply getting the menuItem and using an ObservableCollection...).
xaml:
<toolkit:ContextMenu Opened="ContextMenu_Opened">... </toolkit:ContextMenu>
c#
private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
var menu = (ContextMenu)sender;
var owner = (FrameworkElement)menu.Owner;
if (owner.DataContext != menu.DataContext)
menu.DataContext = owner.DataContext;
}
you can see: Windows Phone Toolkit Context Menu Items have wrong object bound to them when an item is removed and then added
I just came across a simular issue:
When adding items to a listbox the datacontext of the menuitem belonging to the newly added items is not set correctly.
The workaround I ended up implementing was to rebuild the listbox after adding an item:
MyListBox.ItemsSource = null;
MyListBox.Items.Clear( );
MyListBox.ItemsSource = theList;
Not sure, if would also work for your issue...
Also the performance impact for listboxes with many items should be considered.
Related
I have an app where I save the user's contacts in a local Database, then bind this contacts in a LongListSelector using ObservableCollection to update the UI (when a new item is add or deleted).
But I'm having a strange behavior when the ObservableCollection is changed...
The item is add to the UI correctly, but after this, when I scroll fast, a blank space appears in the middle of the list.
Then I found out that, apparently, the list is cutting some items...
I was testing with a list of 140 items (strings), having at least one item starting with each alphabetic letter.
When this problem happens, I saw that after items with C letter, started the items with P letters (D to O disappeared!).
Does anybody can tell me what is happening?
I bind the items on LongListSelector this way:
XAML:
<Grid x:Name="ContentPanelContatos" Grid.Row="1" Margin="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<Grid x:Name="gridContatos" Grid.Row="1" Margin="12,2,12,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="0,0,0,12" >
<TextBox x:Name="tbxSearch" VerticalAlignment="Top" HorizontalAlignment="Stretch" Visibility="Collapsed" TextChanged="TbxSearch_TextChanged" LostFocus="TbxSearch_LostFocus" Style="{StaticResource TextBoxStyle}" />
</Grid>
<phone:LongListSelector Grid.Row="1" x:Name="llsContacts" ItemsSource="{Binding}" SelectionChanged="llsContacts_SelectionChanged" >
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<ListBoxItem local:TiltEffect.IsTiltEnabled="true">
<Grid Margin="0,0,0,10" >
<TextBlock Text="{Binding COLUMN_NAME, Mode=TwoWay}" FontFamily="Segoe WP" FontSize="28" Margin="77,0,0,0" />
<TextBlock Text="{Binding Path=COLUMN_NUMBER, Mode=TwoWay}" FontFamily="Segoe WP Light" FontSize="17" Margin="77,33,0,0"/>
</Grid>
</ListBoxItem>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
<!-- more 2 grids with contents -->
</Grid>
CS:
public ObservableCollection list;
public Main()
{
InitializeComponent();
list = new ObservableCollection<MyClass>(GetDataFromDatabase);
llsContacts.DataContext = list;
}
When I insert or remove something on DataBase, I alter on the list too:
list.Add(newData);
Am I doing something worng??
Reading this article: Frame rate counters in Windows Phone, I noticed that when this problem happens, some of the numbers that are on the side of the screen when debugging, stops changing...
They stops like this:
User Interface Thread FPS: 000
Texture Memory Usage: 007181
Surface Counter: 050
Intermediate Texture Counter: 002
Does this numbers means something?
I have an app for windows phone 8 that displays data loaded from my website.
At the moment, I have setup 4 'holders' for the data, that contain a few TextBlocks and Images. When the app is loaded, these 4 holders display the data for the first 4 'records'. To display the next 4 'records', the user has to click a button, 'Next'.
I want to change this so that all 'records' are displayed in a ScrollView so the user simply has to scroll down to view records rather than click the 'Next' button.
I have also written the app for Android using Eclipse and Java. To do the above, I created a layout of the 'holder' in xml and then this is used as a template for the data. I only have to define the layout once and it is repeated at runtime, populated with the data from each record.
How do I achieve the same in Windows Phone, using vb.net and xaml?
I have googled and possibly DataTemplate is what I need however I'm not sure and have no idea how to implement it.
If you could point me in the right direction I'm sure I can figure it out!
Thanks in advance.
EDIT:
Ok, I've tried the following but the ListBox is empty:
Basically I have a List populated at runtime from my website (I know this bit works):
Public WebData As New System.Collections.Generic.List(Of WebInfo)
WebInfo Class:
Public Class WebInfo
Public ID As Integer
Public H1 As String
Public A1 As String
Public C1 As String
Public C2 As String
Public K1 As Date
End Class
xaml:
<ListBox x:Name="MainList" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Grid.Row="3" Grid.RowSpan="6" Grid.Column="0" Grid.ColumnSpan="3">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="H1" Text="{Binding H1}" FontSize="15" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Right" TextAlignment="Right" FontWeight="Bold" Foreground="Black"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I try to set the ItemsSource using:
MainList.ItemsSource = WebData
The ListBox does not populate.
Any Thoughts?
I think LongListSelector works for you, but you should edit DataTemplate for your needs.
<phone:LongListSelector ItemsSource="{Binding ArticleList}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Title:" />
<TextBlock Text="{Binding Title}" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
The problem was, I was using variables in my class rather than properties:
Public Class WebInfo
Public Property ID As Integer
Public Property H1 As String
Public Property A1 As String
Public Property C1 As String
Public Property C2 As String
Public Property K1 As Date
End Class
Thanks for your help.
I need to show items in dropdown menu in line. How can i make it?
You will probably need to build the Control yourself. You can make a Composite Control consisting of a <Button> and a <ListBox> to emulate what you're trying to do. It is actually pretty easy.
For example:
<Button Content="{Binding SelectedItem.Song, FallbackValue=Show List, ElementName=myListBox}" Height="100" Click="Button_Click"></Button>
<ListBox x:Name="myListBox" Height="60" Visibility="Collapsed">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="1" Height="50" Padding="15,0">
<TextBlock VerticalAlignment="Center">
<Run Text="{Binding Song}"></Run>
</TextBlock>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What I did here is programmed a Button with its Content Binded to the ListBox's SelectedItem which has .Song Property, if none is selected it falls back to "Show List"
When the user clicks on the button it should hide/show the list box depending on its current Visibility.
private void Button_Click(object sender, RoutedEventArgs e)
{
if (this.myListBox.Visibility == System.Windows.Visibility.Collapsed)
{
this.myListBox.Visibility = System.Windows.Visibility.Visible;
}
else
this.myListBox.Visibility = System.Windows.Visibility.Collapsed;
}
Your job is to wrap all this up inside a nice UserControl or you can just use it as is.
Here are some screenshots of it in action:
i have a longlistselector and use contextmenu. I have problem when use NavigationService.
For each list item there is a context menu to delete or edit the item and that appears to work okay for pre-existing lists of items.
However, if I add a new person, add a new item to that person, edit it, then add another item, when I try to edit the second item, the first item is selected instead.
IS A BUG?
My Xaml code looks like this:
<DataTemplate x:Key="LongListSelectorItemTemplate">
<StackPanel Orientation="Horizontal" Margin="4,4">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu cal:Action.TargetWithoutContext="{Binding DataContext, ElementName=LayoutRoot}">
<toolkit:MenuItem Header="Edit" cal:Message.Attach="[Event Tap] = [Action ContextMenuEdit_EventTap($datacontext)]" />
<toolkit:MenuItem Header="Delete" cal:Message.Attach="[Event Tap] = [Action ContextMenuDelete_EventTap($datacontext)]" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Name2}" />
</StackPanel>
</DataTemplate>
I'm not sure if this is the solution for your problem, but i had a same sort of problem and it works for me.
Add a name to the phoneApplicationPage (top of the xaml)
<phone:PhoneApplicationPage
......
Your settings
......
x:Name="Page">
And change this code:
<toolkit:ContextMenu cal:Action.TargetWithoutContext="{Binding DataContext, ElementName=LayoutRoot}">
Into this:
<toolkit:ContextMenu cal:Action.TargetWithoutContext="{Binding ElementName=Page, Path=DataContext}">
I have a LongListSelector like that
<phone:LongListSelector Name="ListRecentFiles"
LayoutMode="Grid"
ItemsSource="{Binding}"
GridCellSize="140,140"
SelectionChanged="ListRecentFiles_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid Background="Red" Margin="0,0,5,5">
<TextBlock Text="{Binding NoteTitle}" Style="{Binding PhoneTextNormalStyle}" />
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu x:Name="ContextMenu">
<toolkit:MenuItem x:Name="Delete" Header="Delete" Click="DeleteNote_Click" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
this is DataContext: public static ObservableCollection<Note> NoteItems;
And i try to delete an item from LongListSelector
private void DeleteNote_Click(object sender, RoutedEventArgs e)
{
Note selectedNote = (sender as MenuItem).DataContext as Note;
ListRecentFiles.ItemsSource.Remove(item);
NoteItems.Remove(selectedNote);
}
It's not work except i navigate to a other XAML page and return
I have visited this page but can't fix link
Without seeing more of the code, it's hard to be sure what's going wrong. But if you are setting
ListRecentFiles.DataContext = NoteItems;
that is incorrect. You want to set
ListRecentFiles.ItemsSource = NoteItems;
The XAML declaration:
ItemSource="{Binding}"
Could do that (depending on the rest of the code). Once .ItemsSource is set correctly, then the line:
NoteItems.Remove(selectedNote);
Should succeed in removing the visual item from the LongListSelector. In any case, you should not do the line:
ListRecentFiles.ItemsSource.Remove(item);
That would do the wrong thing when the list gets so big that it doesn't all fit in memory at once.