I have a listview where each row has few images and some text blocks.
If I use ItemClick event for ListView, I can easily get the clicked item (binded object) using something like this:
private void MainListView_ItemClick(object sender, ItemClickEventArgs e)
{
var device = (Device)e.ClickedItem;
}
But I want to distinguish between clicks on different elements (images) within the ListView row. So I use Tapped event for ImageView (which is inside ListView) where event handler looks like this:
private void image_Tapped(object sender, TappedRoutedEventArgs e)
{
}
How can I get the clicked ListView item in this case?
You can get the item from the data context of the tapped element
var fe = sender as FrameworkElement;
var device = fe.DataContext as Device;
Related
I am a student learning xamarin forms, I am trying to create a basic chat app in this I want to know how to get position of current item in listview that's user watching. When a new message received i want to know if user is at bottom or not if at bottom focus the new and if not at the bottom then just add not by adding focus to it.
you get the selected item from the Xamarin.Forms.ListView.SelectedItem property of your ListView.
If your ListView.ItemSource is of a type that allows using IndexOf you can now do something like
int position = (yourlistview.ItemSource as ObservableCollection<your type>).IndexOf(yourlistview.SelectedItem)
Update:
ok I think i understood what you want.
In most cases more than one item is currently shown when using a listview. So their exists not a single index
but i think you just want to know if the last item of the list is visible/the user has scrolled to the end?
If so ListView has an ItemAppearing event. I use it for example to load more data from an websource if the user scrolled through the first 100 items.
You could do something like this
listview.ItemAppearing += listviewItemAppearing;
listview.ItemDisappearing += listviewItemDisappearing;
bool m_scrolledToEnd;
private void listviewItemDisappearing(object sender, ItemVisibilityEventArgs e)
{
if(e.Item == yourlastiem)
m_scrolledToEnd = false;
}
private void listviewItemAppearing(object sender, ItemVisibilityEventArgs e)
{
if(e.Item == yourlastiem)
m_scrolledToEnd = true;
}
if you realy need to know if a specific index is shown you could create a List<int> m_idxlist;
and in the appearing event add the index of the item to the list
and in the disappearing event remove the index of the item from the list.
Then you will have a list where all indexes of the items currently shown are stored.
From the Documentation
ListView supports selection of one item at a time. Selection is on by
default. When a user taps an item, two events are fired: ItemTapped
and ItemSelected. Note that tapping the same item twice will not fire
multiple ItemSelected events, but will fire multiple ItemTapped
events. Also note that ItemSelected will be called if an item is
deselected.
To detect selecting an item, you can add a method, onSelection:
void OnSelection (object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null) {
return; //ItemSelected is called on deselection, which results in SelectedItem being set to null
}
DisplayAlert ("Item Selected", e.SelectedItem.ToString (), "Ok");
//((ListView)sender).SelectedItem = null; //uncomment line if you want to disable the visual selection state.
}
To disable selection just set the selectedItem to null:
SelectionDemoList.ItemSelected += (sender, e) => {
((ListView)sender).SelectedItem = null;
};
I'm having some trouble with Drag and Drop between different ListViews. I have a GridView that contains multiple ListView all from the same ObservableCollection. Basically, I want to be able to drag items from one ListView into another Listview but within the same GridView.
Below is the ListView Which is part of the DataTemplate for the GridView. The ListView is Bound to a ObservableCollection of string. Which is a Property or the ObservableCollection the GridView is bound too.
<ListView Name="ListingView" Height="200" HorizontalAlignment="Center" Grid.Row="1" CanDragItems="True" AllowDrop="True"
DragItemsStarting="ListView_DragItemsStarting"
DragOver="ListView_DragOver"
CanReorderItems="True"
DragItemsCompleted="ListView_DragItemsCompleted"
Drop="ListView_Drop" ItemsSource="{Binding Listing}"
/>
And here is the Code Behind for the ListView
private void ListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
var item = string.Join(",", e.Items.Cast<string>());
e.Data.SetText(item);
e.Data.RequestedOperation = DataPackageOperation.Move;
}
private void ListView_DragOver(object sender, DragEventArgs e)
{
if (e.DataView.Contains(StandardDataFormats.Text))
{
e.AcceptedOperation = DataPackageOperation.Move;
}
}
private async void ListView_Drop(object sender, DragEventArgs e)
{
if (e.DataView.Contains(StandardDataFormats.Text))
{
var item = await e.DataView.GetTextAsync();
var destinationListView = sender as ListView;
var listViewItemsSource = destinationListView?.ItemsSource as ObservableCollection<string>;
if (listViewItemsSource != null)
{
listViewItemsSource.Add(item);
}
}
}
private void ListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
var item = string.Join(",", args.Items.Cast<string>());
var destinationListView = sender as ListView;
var listViewItemsSource = destinationListView?.ItemsSource as ObservableCollection<string>;
listViewItemsSource.Remove(item);
}
}
The Problem I have is finding a way to stop a ListView from becoming completely empty if I drag all the items out of the a ListView. Once the ListView becomes empty I can't go back and drag something into it.
The Second problem is when I drag an item and then let go of it in the same ListView it was dragged from then it deletes and does no re-add the item.
I think I need to add an If statement to the DragItemCompleted method to see If the source is the same as the target before removing the item.
Edit I seem to have fixed" the second problem by removing the CanReorderItemsProperty from the listView. I'm not sure why but it seems to have fixed up that issue. But now i can't reorder the lists :(
Look into this windows sample program https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop/cs
I have two views of WPF (Vista1.xaml and Vista2.xaml), and they are part of a MainWindow.xaml.
In the Vista1.xaml i have a listview, where the user selects some items by clicking and the Vista2.xaml has a button.
I want that when the user clicks on the button of Vista2.xaml, get the items that the user previously selected in the listview of Vista1.xaml.
I have class in the Vista1.xaml.cs ListViewItem_PreviewMouseLeftButtonDown method that captures the user selects the item in the listview.
the code is as follows
private void ListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var item = sender as ListViewItem;
if (item != null && item.IsSelected)
{
...
}
}
I appreciate your help
Add a public property to you MainPage that contains the data you want to pass between Vista1 and Vista2. Then, in your event handler of Vista1, set the property and on the button click of Vista2 read the property.
In my item template in longlistselector I have a hyperlink button.
When I'm clicking on button, that item should be deleted.
The problem is that if there is no selected item, I need to click twice on button, because after first click SelectedItem in LonglistSelector is null.
How to fix it, that click on button will automatically set selection on list to button's parent?
You can do this in two different ways (ignoring MVVM pattern). You can delete the item in the Click eventhandler of the HyperLinkButton or you can set the SelectedItem of the LongListSelector, so you can delete it right after.
public ObservableCollection<object> List { get; set; }
public MainPage()
{
InitializeComponent();
List = new ObservableCollection<object>() { "aaaa", "bbb", "cccc", "dddd", "eeee"};
LongList.ItemsSource = List;
}
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
var hyperLinkButton = sender as HyperlinkButton;
var boundItemDataContext = hyperLinkButton.DataContext;
List.Remove(boundItemDataContext); // #1 Delete it directly from the list that automatically gets updated because it's an ObservableCollection.
LongList.SelectedItem = boundItemDataContext; // #2 Set the SelectedItem property to the current DataContext, so you can delete it in the SelectionChanged eventhandler.
}
private void LongList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var longListSelector = sender as LongListSelector;
List.Remove(longListSelector.SelectedItem);
}
I need to retrieve components from a listbox item. Not from a Tap or selection changed events. Is there a simple way to achieve this?
If I remember correct, in Android you can just write:
layoutRoot.findViewById(R.id.name);
Is there a similar way to do this on Windows Phone?
Update: Here's what I tried so far, but does not work:
What Daniela said in option 5 seems to work when I have the ListBoxItem. So this works fine when I have for example a Tap event on the ListBoxItem:
private void ListBoxItem_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
ListBoxItem item = sender as ListBoxItem;
// I can now retrieve a component inside the ListBoxItem
TextBox textBox = item.FindName("myTextBox") as TextBox;
}
But I want to do this when not triggering any events from a ListBoxItem.
What JoonasL said looks like something I could use but I can't get it to work.
// will not compile ( Cannot implicitly convert type 'object' to... )
ListBoxItem item = x.Items[0];
// if cast the value will be null
ListBoxItem item = x.Items[0] as ListBoxItem;
// will return the object used to populate that ListBoxItem, not the actual ListBoxItem.
// item will have a ItemViewModel object.
List<ItemViewModel> list = ....
this.myListBox.ItemsSource = list;
var item = x.Items[0]
When searching on Google I found something that I could use to find a component inside a ListBoxItem but I think there should be a easier way. Here they use a VisualTreeHelper.
Edit:
add a name to your lisbox (x:Name="something")
Cast ALL items as a List or pick out an item and cast the item as the correct type. Example:
private void Button_Click(object sender, RoutedEventArgs e)
{
var list = yourListbox.Items;
var itemCastAsCorrectObjectInstance = (ItemViewModel)list.FirstOrDefault();
textblock.Text = itemCastAsCorrectObjectInstance.LineOne;
}
ItemViewModel is a class we have created, and a list of ItemViewModels are used as itemssource for the listbox.
Here is an app example I've made for you
There are several ways to do that (some of the examples are WPF, but code is quite similar, it's just to give you a general idea)
Create listbox in code and retrieve item as in the example provided my JoonasL
private void GetUserRecommendations()
{
var obj = _helper.GetList<Recommendations>(#"http://localhost:1613/Home/GetAllRecommendations");
_items.Clear();
foreach (var item in obj)
{
_items.Add(item);
}
itemListView.ItemsSource = _items;
}
Retrieve a selected item on a changed event (or other event bound to the listbox)
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
var itemProperty = ((ListBoxItem) e.ClickedItem).SomeProperty;
}
Provide the listbox a name and access the items by refering to the name in the code
var item = itemListView.SelectedItem as SomeClass;
Access the selected item by binding to another element (XAML only)
<Border Margin="10" BorderBrush="Silver" BorderThickness="3" Padding="8">
<DockPanel>
<TextBlock>Choose a Color:</TextBlock>
<ComboBox Name="myComboBox" SelectedIndex="0">
<ComboBoxItem>Green</ComboBoxItem>
<ComboBoxItem>Blue</ComboBoxItem>
<ComboBoxItem>Red</ComboBoxItem>
</ComboBox>
<Canvas>
<Canvas.Background>
<Binding ElementName="myComboBox" Path="SelectedItem.Content"/>
</Canvas.Background>
</Canvas>
</DockPanel>
Search the layoutroot
var myTextBlock = (TextBlock)this.FindName("myTextBlock");
Or maybe something like:
private void Somepage_Loaded(object sender, RoutedEventArgs e)
{
if (SomeCondition())
{
var children = (sender as Panel).Children;
var child = (from Control child in children
where child.Name == "NameTextBox"
select child).First();
child.Focus();
}
ListBox x = new ListBox();
ListBoxItem item = x.Items[0];
Or do you want something else?
RadDataBoundListBox has an event called ItemTap (not sure about normal ListBox) but my solution went something like this:
private void FocusTextBox(object sender, ListBoxItemTapEventArgs e)
{
txtBox = e.Item.FindChildByType<TextBox>();
var item = itemListView.SelectedItem as PanoramaApp1.//Your Selected Item Type Here;
//Do Something With item Here
itemListView.SelectedItem = null;
}