UWP Get Clicked Item in DataTemplate - c#

I'm sure this has been asked before, however I cannot find the appropriate answer.
I am using an ItemTemplate to display a list of users, this list consists of StackPanels with user details. How can I get the user object that I clicked on?
Current code:
<GridView Name="usersList">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel PointerPressed="UserClicked">
<TextBlock Text="{Binding Forename}"/>
<TextBlock Text="{Binding Surname}"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
This is being populated via an async API call:
usersList.ItemsSource = null;
var task = Users.UserAsync<User>();
usersList.ItemsSource = await task;
How can I capture the User object that has been clicked on PointerPressed?

Like this:
private void UserClicked(object sender, PointerRoutedEventArgs e)
{
User clickedOnUser = (sender as StackPanel).DataContext as User;
}
This approach is more direct than the one using usersList.SelectedItem, so I recommend sticking with it. E.g., it will work if you set SelectionMode="None" for the GridView, whereas the approach based on usersList.SelectedItem won't.
Also, as Sean O'Neil rightfully noticed, you might want to use Tapped event instead of PointerPressed for the most general case scenario.

Use GridView.SelectedItem to reference the object you want when you click on it.
private void UserClicked_PointerPressed(object sender, PointerRoutedEventArgs e)
{
var whatYouWant = usersList.SelectedItem;
}

Related

ScrollIntoView property not working for gridview in windows 10 universal app

I tried this below code:
XAML Code:
<GridView x:Name="listgrid">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="15,15,0,0">
<Image Height="170" Width="170" Source="{Binding}"></Image>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
Cs code:
for (int i = 1; i < 50; i++)
{
list.Add("ms-appx:///Images/A-aa.jpg");
}
listgrid.ItemsSource = list;
listgrid.ScrollIntoView(listgrid.Items[30]);
I above code to scroll view to my selected item, but it's not showing any changes, i think i used this property in a wrong way any one please help me to scroll to gridview position.
I have replied your same question in MSDN: https://social.msdn.microsoft.com/Forums/windowsapps/en-US/d0a772b3-80b9-4a11-92a9-89963c29a52f/scrollintoview-property-not-working-for-gridview-in-windows-10-universal-app?forum=wpdevelop
You need to have something more to distinguish items, for example, give every image a name since items you bind to GridView are same, ScrollIntoView default find the first one.
And commonly you need to set a height property for the GridView.
For more complex requirements, there is a good thread you can reference:
Windows 10 ScrollIntoView() is not scrolling to the items in the middle of a listview
Try to subscribe on Loaded event and call ScrollIntoView inside event handler:
listgrid.Loaded += Listgrid_Loaded;
....
private void Listgrid_Loaded(object sender, RoutedEventArgs e)
{
listgrid.ScrollIntoView(listgrid.Items[30]);
}
Try this
private void Gridview_Loaded(object sender, RoutedEventArgs e)
{
if (ShellPage.Current.SelectedRecItem != null)
{
this.gridview.SelectedItem = ShellPage.Current.SelectedRecItem;
this.gridview.UpdateLayout();
this.gridview.ScrollIntoView(ShellPage.Current.SelectedRecItem);
}
}

WPF ListView binding to the collection

I implemented a collection of Hyperlink elements using WPF:
var controlLinks = new List<Hyperlink>();
if (issueLinks != null)
{
foreach (var link in issueLinks)
{
var tempLink = new Hyperlink()
{
NavigateUri = new Uri(link.link)
};
controlLinks.Add(tempLink);
}
}
ListIssueLinks.ItemsSource = controlLinks;
Collections is successfuly filled, now I link ListIssueLinks view to this collection.
<ListView Name="ListIssueLinks" Height="100" >
<ListView.View>
<GridView>
<GridViewColumn/>
</GridView>
</ListView.View>
</ListView>
Here I've got a problem, the issue is I'm new to WPF and have no idea how properly implement formatting (for example, to present NavigateUri or Name only on UI) and implement generic handler for click on any element. Something like this:
private void Hyperlink_OnClick(object sender, RoutedEventArgs e)
{
var clickedLink = (Hyperlink) sender;
System.Diagnostics.Process.Start(clickedLink.NavigateUri.ToString());
}
I tried DataTemplate, tried a lot of other variants, googled really a lot, but still have no clue how to do that. Could you please suggest any easy and elegant solution?
DataTemplate is your best bet, here's how you could implement it in your case.
<ListView Name="ListIssueLinks" Height="100">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink NavigateUri="{Binding}" RequestNavigate="Link_RequestNavigate">
<TextBlock Text="{Binding}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then in your code behind, I would simply bind directly to your issueLinks (no need to build up HyperLinks in code).
List<string> issueLinks = new List<string>()
{
"http://www.google.com",
"http://www.stackoverflow.com",
};
ListIssueLinks.ItemsSource = issueLinks;
Then your RequestNavigate event handler needs to start your process
private void Link_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
I didnt fully understand what is your problem but i have two things that you should know that exist.
ObservableCollection
i think you should consider use it instead of a simple List because it has advantages if you need to bind the List to The View with your ListView for example. for more info read here: ObservableCollection Class
XAML side
the second thing i think you tried to explain is how to take properties and show them in your list view. this means you need to write it on the XAML side and explore about it farther, you can bind the properties after that with inotifypropertychanged if the data in the list is going to change with any reason.
hope i helped.

c# How to get Listbox selection from Observable Collection

I'm probably not even asking this correctly, I am new to c#, but trying to help my 14 year-old son learn. I've created a listbox with items created with an ObservableCollection. Here is the XAML:
<ListBox x:Name="listBox1" ItemsSource="{Binding}" Margin="105,205,886,63"
IsTabStop="True" SelectionChanged="PrintText"
ScrollViewer.VerticalScrollBarVisibility="Hidden" TabIndex="5" FontSize="36"
Background="Transparent" Foreground="#FF55B64C" FontFamily="Arabic Typesetting"
FontWeight="Bold" IsDoubleTapEnabled="False" SelectionMode="Single" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="blockNameList" Text="{Binding name}"/>
<TextBlock Text=" #"/>
<TextBlock Name="blockIdList" Text="{Binding id}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here is how I created the ListBox Items:
var client = new HttpClient();
var uri = new Uri("http://theurlImusing");
Stream respStream2 = await client.GetStreamAsync(uri);
// DataContractJsonSerializer ser2 = new DataContractJsonSerializer(typeof(RootObject));
// RootObject feed2 = (RootObject)ser2.ReadObject(respStream2);
DataContractJsonSerializer ser = null;
ser = new DataContractJsonSerializer(typeof(ObservableCollection<RootObject>));
ObservableCollection<RootObject> feed2 = ser.ReadObject(respStream2) as ObservableCollection<RootObject>;
var cardList = new List<RootObject>();
foreach (RootObject returnfeed in feed2)
{
string cid = returnfeed.id;
string cardname = returnfeed.name;
listBox1.Items.Add(new RootObject { id=cid, name=cardname });
}
I thought I would just use the SelectionChanged="PrintText" property of the listbox so that when I clicked on a listbox item, it would just change a textblock's text value. Ultimately, that is all I am trying to do...set a textblock or textbox to be equal to the "id" value that is clicked on in the ListBox.
void PrintText(object sender, SelectionChangedEventArgs args)
{
//What do I put in here??
}
Thanks very much for any insight! I need it!!
This is something that is much easier to do using data binding. You can bind the TextBlock.Text property directly to the ListBox using an ElementName binding:
<TextBox Text="{Binding ElementName=listBox1,Path=SelectedItem.id}" />
Alternatively, if you set set SelectedValuePath="id" on the ListBox, then binding to SelectedValue will give you the "id" property:
<ListBox x:Name="listBox1" SelectedValuePath="id" ... />
<TextBox Text="{Binding ElementName=listBox1,Path=SelectedValue}" />
As a side note (as #Rachel already noted in comments): you may as well just set the ItemsSource, rather than looping through and adding each manually. All you need is this:
listBox1.ItemsSource = feed2;
Edit
Ok, if you wanted to use the procedural approach, here's how you would do it. (No one would recommend this approach, especially if you're learning/teaching. Try to make full use of data binding, and view-viewmodel separation.)
void PrintText(object sender, SelectionChangedEventArgs args)
{
var listBox = (ListBox)sender;
RootObject selectedItem = listBox.SelectedItem;
someTextBox.Text = selectedItem.id;
}
If all you want to do is click an item in the ListBox and get it to show up in the TextBox, you don't need fancy binding (in that other answer) to do it. You can simply add a MouseUp event in the ListBox XAML:
MouseUp="ListBox1_MouseUp"
This would work similar to the SelectionChanged event you wanted to use.
You then right-click that function name in the XAML page and select "Go to definition". It will create the next function for you:
private void ListBox1_MouseUp(object sender, MouseButtonEventArgs e)
{
}
Simply add in there to update the TextBox you want with the SelectedItem values from sender:
private void ListBox1_MouseUp(object sender, MouseButtonEventArgs e)
{
ListBox lstBox = (ListBox)sender;
ListBoxItem item = lstBox.SelectedItem;
if (item != null) // avoids exception when an empty line is clicked
{
someBox.Text = item.name;
someOtherBox.Text = item.id;
}
}
I later found that blockNameList and blockIdList are not accessible via intellisense because they are within the DataTemplate of the ListBox, so I put someBox and someOtherBox, as references to other TextBoxes you would have to add to the XAML, outside of the ListBox. You would not re-write data inside the ListBox on the same item by clicking it. Even if you could reach the template's TextBlock to do it, you'd just be re-writing that same item with its own values, since it would be the SelectedItem!
Even though there are those that don't recommend this approach because they like binding everything - and in some cases you want binding to occur so that controls on the page update as a result of dependencies (i.e. do one thing to cause another), I find that manual methods of clicking a button/item/control to update something are just fine and avoid all the model/MVVM BS that has taken over WPF and over-complicated it.

passing tag field to other view wf7

ok I need to pass the tag in this code to the next page but I dont know how to access it. Can someone help with this.
code :
<ListBox x:Name="AgendaList" Width="450" Height="520" Margin="10" SelectionChanged="event_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="100" Stretch="Uniform" HorizontalAlignment="Center" Source="/SuperAgenda;component/Images/calendar.jpg" />
<TextBlock Text="{Binding Title_}" Tag="{Binding EventId_}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I am using a button to send it over so I need to know how I can get at the tag data and have the button send it to the next page.
my button looks like this but it sends no data:
private void viewEvent_Click(object sender, RoutedEventArgs e)
{
string uri = String.Format("/Views/Event_View/Event_View.xaml?id={0}", clickedLink.Tag);
NavigationService.Navigate(new Uri(uri, UriKind.Relative));
}
Any help would be nice thanks.
Actually, to transfer data between pages you should use PhoneApplicationService class.
PhoneApplicationService.Current.State["field"] = someField;
at your button tap/click event.
Then, on your next page get that value using cast
someField = (fieldType)PhoneApplicationService.Current.State["field"];
Is that what you want?
Simply use the Navigation Context property of the page you navigated to.
if (this.NavigationContext.QueryString.ContainsKey("ProductId"))
{
productID = this.NavigationContext.QueryString["ProductId"];
}
else
{
productID = App.Current.Resources["FeaturedProductID"].ToString();
}
Using the Tag property here is superfluous, as the DataTemplate in a bound control contains all the properties of your object. Use the DataContext to retrieve the object. Add a Tap event to the StackPanel in your DataTemplate (so the user can tap either the image or text):
private void StackPanel_Tap( object sender, GestureEventArgs e ) {
int eventid = (( sender as StackPanel ).DataContext as MyObject).EventId_;
string uri = String.Format("/Views/Event_View/Event_View.xaml?id={0}", eventid);
NavigationService.Navigate(new Uri(uri, UriKind.Relative));
}
Then use the NavigationContext in paiden's answer to retrieve the value on the recieving page.

How to get GridViewItem from its child element?

Suppose I have a code in XAML like this:
<GridView>
<GridView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding test}" Click="ButtonClick" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Then how can I get which GridViewItem was selected? Because, normally what is done is to add the ItemClick functionality to the GridView itself, but in this case I am doing something customized and need to get the SelectedItem starting from the Button.
I tried code something like this:
void ButtonClick (object sender, RoutedEventArgs e)
{
var g = (GridViewItem)((Button)sender).Parent;
}
But it does not work (returns null). Please help!
Thanks!
Sure! Here's the code that I use when the ad control fails to load an ad (like when the machine is offline). In that case I remove it form the gridview. To do that I have to locate the ad's parent gridviewitem and remove the whole thing. I do it like this:
private void AdControl_ErrorOccurred_1(object sender, Microsoft.Advertising.WinRT.UI.AdErrorEventArgs e)
{
var _Item = sender as DependencyObject;
while (!(_Item is GridViewItem))
_Item = VisualTreeHelper.GetParent(_Item);
HubGrid.Items.Remove(_Item);
}

Categories