LongListMultiSelector blocks gesture events for selected items - c#

In the following XAML when any TextBlock is selected in LongListMultiSelector, that TextBlock stops recieving Tap event (and any other gesture events) but instead becomes unselected when I tap it again. How can I change this behavior such that TextBlock will be always responding to Tap regardless of it's selection state?
<toolkit:LongListMultiSelector ItemsSource="{Binding Items}">
<toolkit:LongListMultiSelector.ItemTemplate>
<DataTemplate>
<!-- When TextBlock is selected, Debug_WriteLine_Tapped does not get called -->
<TextBlock Text="{Binding name}" Tap="Debug_WriteLine_Tapped" />
</DataTemplate>
</toolkit:LongListMultiSelector.ItemTemplate>
</toolkit:LongListMultiSelector>
Basically what I'm looking for is a behavior similar to that of standard Mail app where after selecting a bunch of letters they still recieve Tap events because I can still expand/collapse any of them (except that in my case it's a simple TextBlocks and not ExpanderViews).

Works OK on my machine. When I tap these 3 items I get the expected messages in the debug log.
<phone:LongListSelector ItemsSource="{Binding}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid >
<TextBlock Text="{Binding}" Tap="TextBlock_Tap_1" />
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = "Foo Bar Baz".Split(' ');
}
private void TextBlock_Tap_1(object sender, GestureEventArgs e)
{
Debug.WriteLine("TextBlock_Tap_1");
}
Depending on your Scenario WP8 exposes the UseOptimizedManipulationRouting property which might prove useful. Setting UseOptimizedManipulationRouting=false causes LongListSelector, Pivot and other controls to not swallow events for nested controls. A good place to set that would be on the root control of your LongListSelector.ItemTemplate.

The toolkit uses this sig to respond to the tap.
private void OnItemContentTap(object sender, System.Windows.Input.GestureEventArgs e)
The sample defines the datatemplate separate from the LongListMultiSelector construct in the
<phone:PhoneApplicationPage.Resources>
section and references it as
ItemTemplate="{StaticResource EmailItemTemplate}.
See LongListMultiSelectorSample.xaml in the toolkit for the example. The sample is actually incomplete and can be confusing at first. Just ignore the BuddiesPivotItem and the GridModeItem, unless you want to finish it and make the whole thing work.

Related

Why are my custom controls not always receiving MouseEnter events?

Alright, I'm fairly new to WPF and I ran into a very strange problem. The relevant section of my XAML defines a Border around a ScrollViewer around a StackPanel which is populated using an ItemsControl that is then databound to a CollectionViewSource which in turn wraps a standard ObservableCollection. The ItemsControl defines a DataTemplate that contains only one tag: a custom control I've made called a StackElement. I'm handling three events from this control — MouseEnter, MouseLeave, and PreviewMouseLeftButtonUp. These events can fire, but do so unreliably.
For example, after some new StackElements are added, the MouseEnter event generally doesn't fire on the first StackElement until I've moused over a few others. Once a MouseOver manages to fire once, it continues to fire correctly on that StackElement from there on out.
However, the first time mousing over a StackElement doesn't always fail. If I approach the StackElements from beneath and try the last one first, it will always fire. When I do this, sometimes the first one will work, but the second one won't fire. Once, both of them did manage to operate correctly, but it happens infrequently.
I'm not multithreading anything, none of my parent controls handle events of their own, all event handlers consist only of a WriteLine() statement for debugging purposes, and the StackElement code-behind isn't handling any events either.
I've tried decoupling the ItemsControl from the CollectionViewSource in favor of binding it directly to the ObservableCollection, which did nothing other than (as I expected) bypass the sorting functionality I added to the ViewSource. I tried handling the events in the StackElement class itself, in addition to making them be tied to other controls contained within StackElement. I tried using DataTriggers, which if I remember worked as expected, but I need to include more advanced logic such as multiselection and the inability to lightly highlight an already-selected StackElement.
For context, I'm intending to use these events to lightly highlight StackElements when the user drags the mouse over them and to strongly highlight them when the mouse is pressed — basically, I need something that looks and feels like Windows File Explorer. From what I've seen this can't be accomplished in an elegant fashion with DataTriggers alone.
Here's my event handlers (in MainWindow.xaml):
private void StackElement_OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Console.WriteLine("OnPreviewMouseLeftButtonUp fired for a StackElement.");
}
private void StackElement_OnMouseEnter(object sender, MouseEventArgs e)
{
Console.WriteLine("OnMouseEnter fired for a StackElement.");
}
private void StackElement_OnMouseLeave(object sender, MouseEventArgs e)
{
Console.WriteLine("OnMouseLeave fired for a StackElement.");
}
Here's how I'm adding to the bound collection (for testing, which is why it's hooked up to a random button):
private void Btn_File_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
InitiativeStackElement t = new InitiativeStackElement(new Entity("TestName", 10, 11, 12, 13, null)); //InitiativeStackElement implements INotifyPropertyChanged so the databindings work
_entityProvider.Elements.Add(t); //_entityProvider is just a reference to a XAML-defined resource class, which is loaded up in the constructor so I don't have to call TryGetResource() whenever I want to use it. it's currently used for testing purposes only
}
Finally, here's the portion of my XAML containing the StackElements:
<Border Grid.Row="1"
Margin="0,1,0,0"
Style="{StaticResource StandardBorder}">
<ScrollViewer Name="Scv_InitiativeStack">
<StackPanel Name="Stp_InitiativeStack">
<ItemsControl Name="Its_InitiativeStack" ItemsSource="{Binding Source={StaticResource SortedInitiativeStack}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<con:StackElement Element="{Binding}" PreviewMouseLeftButtonUp="StackElement_OnPreviewMouseLeftButtonUp" MouseEnter="StackElement_OnMouseEnter" MouseLeave="StackElement_OnMouseLeave"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</Border>
The StackElement class just defines a single DependencyProperty of type InitiativeStackElement. The properties of this object are bound to a few controls within the StackElement, which always displays correctly. It's the behavior of the events that have me confused.
As described, I'm expecting the MouseEnter event to fire whenever the mouse is dragged onto the StackElement. However, it's only firing after I fulfill seemingly random conditions that shouldn't affect it's functionality, like mousing over another StackElement first. There are no error messages.
Alright, I was able to get the functionality I wanted using ListBox:
<Window.Resources>
<DataTemplate x:Key="InitiativeStackTemplate">
<con:StackElement Element="{Binding}"/>
</DataTemplate>
</Window.Resources>
<Border Margin="0,1,0,0"
Grid.Row="1"
Style="{StaticResource StandardBorder}">
<ScrollViewer Name="Scv_InitiativeStack">
<ListBox Name="Lbx_InitiativeStack"
SelectionMode="Extended"
ItemsSource="{Binding Source={StaticResource SortedInitiativeStack}}"
ItemTemplate="{StaticResource InitiativeStackTemplate}"
HorizontalContentAlignment="Stretch"/>
</ScrollViewer>
</Border>
Everything works as expected.

ListView Grid Item Holding not working

I'm using a ListView with more than one DataTemplate. I'm trying to detect when the user clicks on an Item to show a Flyout.
GridItem_Holding is never called.
XAML:
<DataTemplate x:Key="myKey1">
<Grid Holding="GridItem_Holding">
...
</Grid>
</DataTemplate>
<DataTemplate x:Key="myKey2">
<Grid Holding="GridItem_Holding">
...
</Grid>
</DataTemplate>
Code behind:
private void GridItem_Holding(object sender, HoldingRoutedEventArgs e)
{
}
Try like this
<Grid x:Name="GridListItem" Holding="Grid_Holding">
Have you remembered IsHoldingEnabled on Grid or children? Holding event is not triggered unless it is set true.

How to determine which child element of a ListView Item was clicked?

I'm developing a windows phone 8.1 app in XAML and C#. I have a ListView getting its Items from a bound list and displaying them through a DataTemplate. Now, in this DataTemplate there are multiple child elements, and when the user taps on an item in the list, I want to be able to determine what child element he actually touched. Depending on that, the app should either expand a view with more details inside the Item, or navigate to another page.
The ItemClick event handler of the ListView is ListView_ItemClick(object sender, ItemClickEventArgs e), and I thought e.OriginalSource would maybe give me the answer, but this just gave me the clicked ListItem.
I have yet to try if encapsulating the children with buttons and intercepting their click events would work, but I'm happy to try any alternative there might be for this.
I just found the solution myself. I set the ListView to SelectionMode="None" and IsItemClickEnabled="False", and then I added Tapped handlers for the individual child elements. Works just as I wanted.
I've got a TextBlock and an Image in one ListViewItem and have just used the Image_PointerPressed event. Doing that also fires the ItemClick event for the ListView so I disable it first, do the stuff I want, then re-enable the ItemClick event so that still fires when the TextBlock is pressed.
Code behind:
private async void imgDone_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// disable click event so it won't fire as well
lvwCouncils.IsItemClickEnabled = false;
// do stuff
MessageDialog m = new MessageDialog("User Details");
await m.ShowAsync();
// Re-enable the click event
lvwCouncils.IsItemClickEnabled = true;
}
Xaml:
<ListView x:Name="lvwCouncils" ItemClick="lvwCouncils_ItemClicked" IsItemClickEnabled="true" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock
Grid.Column="1"
Text="{Binding council_name}"
FontSize="24"
Margin="10,10,30,10"
/>
<Border Height="20" Width="20" Margin="10,10,0,10" >
<Image x:Name="imgDone"
Source="Assets/user_earth.png" Stretch="UniformToFill" PointerPressed="imgDone_PointerPressed"/>
</Border>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Use the SelectionChanged event.
Cast the sender object to ListView type and then retrieve the item from the SelectedItem property.
Similar question here but for a different control :
Get the index of the selected item in longlistselector

How to have a ListBox child item event not call parent event?

Problem
When I click on a ListView item, it calls the "Tapped" event to navigate to another page. I have an Up Vote event within the ItemTemplate and when they call that specific event, I DO NOT want to call the ListView's tapped event. Any idea how I might do that?
ListView XAML:
Parent event, "listboxFeedbackItem_Tapped", occurs anytime any part of the listview is clicked
<Grid x:Name="gridMainData" Grid.Row="2">
<ProgressBar x:Name="prgBar" IsIndeterminate="True" VerticalAlignment="Top" Visibility="{Binding Path=FeedbackVM.IsLoading, Mode=TwoWay}"/>
<ListView ItemTemplate="{StaticResource FeedbackTemplate}" ItemsSource="{Binding FeedbackVM.FeedbackCollection}" Tapped="listboxFeedbackItem_Tapped"/>
</Grid>
ItemTemplate Xaml:
Event "UpVoteItem_Tap" should not trigger "listboxFeedbackItem_Tapped"
<DataTemplate x:Key="FeedbackTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,0,30,0" Text="{Binding UpVotes}" Tapped="UpVoteItem_Tap"/>
</StackPanel>
</DataTemplate>
Perhaps there's a method in C# to prevent subsequent events from occurring?
Thanks, I'm still trying to wrap my head around XAML.
When you receive the UpVote tapped event, you can tell it not to pass the event to the parent listview by setting e.Handled=true:
void UpVoteItem_Tap(object sender, TappedRoutedEventArgs e)
{
// Processing here
...
// don't send event to parent
e.Handled = true;
}

Hold Event Longlistselector

Hej
I want to create a standard holdevent. When you hold an element, there would appear some options you could chose like a new list.
How do you create this, is it just simply done with a popup or is there a smarter way?
Extra
After finding the answer, see answer below, some nice info is:
Put the context creation inside the hold event.
Then you can change to different contextmenus depending on the item. You can get the item that was holded by the following
private void StackPanel_Hold(object sender, GestureEventArgs e)
{
ItemViewModel itemViewModel = (sender as StackPanel).DataContext as ItemViewModel;
string t = itemViewModel.LineOne;
}
And
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Height="78" Hold="StackPanel_Hold">
<TextBlock Text="{Binding LineOne}" />
<TextBlock Text="{Binding LineTwo}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
A good link for easy implementation is also youtube link below, replicated here :
Youtube
A ContextMenu is one option..
http://blogs.msdn.com/b/msgulfcommunity/archive/2013/05/19/windows-phone-toolkit-context-menu-getting-selected-item-within-a-long-list-selector.aspx

Categories

Resources