I have a listbox. Every item has an image and title (binding from my list). When I click an item of the listbox, how do I get the title value of that item.
create an event in ListBox called "SelectionChanged" and map it the method in the code behind of the XAML file. In the .cs file get the value from myListBox.SelectedItem and cast it to your list item type.
EX: in XAML file
<ListBox x:Name="myListBox" ItemsSource="{Binding Items}"
SelectionChanged="myListBox_SelectionChanged">
in xaml.cs file:
private void myListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var mySelectedItem = myListBox.SelectedItem as myObject;
}
I hope this helps.
There are already few similar questions (first, second). I'll try to show you an example (little extending this what #KirtiSagar (if it helps accept his solution as it's the same method) has said):
Let's assume that your ItemClass look like this:
public class ItemClass
{
public Uri ImagePath { get; set; }
public string Tile { get; set; } // I used string as an example - it can be any class
}
And you Bind it to your ListBox like this:
<ListBox Name="myList" Grid.Row="2">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImagePath}"/>
<TextBlock Text="{Binding Tile}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
It is a very simple example but should show you an overview how it works.
Then in my Page and Constructor I need to add my Collection and subscribe to events:
ObservableCollection<ItemClass> items = new ObservableCollection<ItemClass>();
public MainPage()
{
InitializeComponent();
myList.ItemsSource = items;
myList.SelectionChanged += myList_SelectionChanged;
}
The SelectinChanged event can be used for your purpose in many ways. For example you can use its SelectionChangedEventArgs properties. I will show some methods which will produce the same result. I mixed some things on purpose just to show how it can be done.
private void myList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myList.SelectedItem != null)
{
string myTile = ((sender as ListBox).SelectedItem as ItemClass).Tile;
// you can also get your item like this - using EventArgs properties:
string myTileToo = ((ItemClass)(e.AddedItems[0])).Tile;
}
// also you can get this by SelectedIndex and your Item Collection
if ((sender as ListBox).SelectedIndex >= 0)
{
string myTileThree = items[myList.SelectedIndex].Tile;
}
}
Note that your LisBox can work in different SelectionModes for example Multipe - you can also try to use that if you need it (there are properties SelectedItems and AddedItems / RemovedItems, which are IList).
Related
What I want to achieve may not be possible in XAML. If it is possible then its probably due to a XAML feature worth knowing. If not, then I've also learned something.
I have a button flyout which is data-bound to a view model. The view model provides a new instance of an object to the content of the flyout, via a get accessor.
Each time the button is pressed I want the flyout to present a new instance of the object.
The problem: The object is created only once, and re-presented each time the flyout is opened.
ViewModel.cs
class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
class ViewModel
{
static int itemCount;
public Item GetNewItem {
get {
itemCount++;
Debug.WriteLine("Created item: " + itemCount);
return new Item() { Id = itemCount, Name = "Item_" + itemCount} ;
}
}
}
MainPage.xaml.cs
<Page.Resources>
<local:ViewModel x:Key="ViewModel"/>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{StaticResource ViewModel}">
<Button Content="Create Item">
<Button.Flyout>
<Flyout>
<StackPanel DataContext="{Binding Path=GetNewItem}">
<TextBlock Text="{Binding Path=Id}"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</Grid>
Output:
The trace statement "Created item: Item_1" appears, but not "Created Item_2", etc..
The same data ("1" and "Item_1") is presented each time the button is pressed.
Investigation
I can make it work in the code-behind of the main page. I name the grid, and add an Opening event handler to the flyout
private void Flyout_Opening(object sender, object e) {
var gridDataContext = (ViewModel)this.grid.DataContext;
this.stackPanel.DataContext = gridDataContext.GetNewItem;
}
Works fine now! (but I want to do it in XAML)
I have tried implementing INotifyPropertyChanged on the ViewModel, but this didn't work.
class ViewModel : INotifyPropertyChanged
{
static int itemCount;
public Item GetNewItem {
get {
itemCount++;
Debug.WriteLine("Created item: " + itemCount);
OnPropertyChanged("GetNewItem");
return new Item() { Id = itemCount, Name = "Item_" + itemCount} ;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name) {
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(name));
}
}
Hi Listpicker not binding proper items.it binding project name list if i use async method.In case if i use same code inside constructor it working perfectly.
i tried this code:
c#:
List<Orderlist> GetOrderItems = new List<Orderlist>();
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
var resultOrderReq = await this.objOrderMgr.GetOrders(objOrderReq, this.objRequestHeaderHelper.GetRequestHeaders());
var reslistOrder = resultOrderReq.orderlist;
foreach (var item in reslistOrder)
{
GetOrderItems.Add(new Orderlist() { OrderId = item.orderid });
}
this.ProductSub.ItemsSource = GetOrderItems;
}
}
public class Orderlist
{
public long OrderId { get; set; }
}
XAML
<toolkit:ListPicker Grid.Row="0" x:Name="ProductSub" ItemTemplate="{StaticResource PickerItemTemplate}" ExpansionMode="ExpansionAllowed" FullModeItemTemplate="{StaticResource PickerFullModeItemTemplate}"/>
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Name="PickerItemTemplate">
<TextBlock Text="{Binding OrderId}"></TextBlock>
</DataTemplate>
<DataTemplate x:Name="PickerFullModeItemTemplate">
<TextBlock Text="{Binding OrderId}"></TextBlock>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
Usually, a problem like this comes down to one of two things:
You forgot to implement INotifyPropertyChanged for properties that change.
You are using a non-observable collection, e.g., List<T> instead of ObservableCollection<T>.
I can't tell for sure based on your problem description, but it looks like it might be the observable collection problem. Try replacing List<Orderlist> with ObservableCollection<Orderlist>.
//I made little changes in your code. may this will help you.
List<Orderlist> GetOrderItems = new List<Orderlist>();
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.NavigationMode != NavigationMode.Back)
{
var resultOrderReq = await this.objOrderMgr.GetOrders(objOrderReq, this.objRequestHeaderHelper.GetRequestHeaders());
var reslistOrder = resultOrderReq.orderlist;
foreach (var item in reslistOrder)
{
GetOrderItems.Add(new { OrderId = item.orderid });
}
this.ProductSub.ItemsSource = GetOrderItems;
}
}
public class Orderlist
{
public long OrderId { get; set; }
}
In my app I need to display a collection of Images exactly like in the Windows Phone 8 Photo App where you can swipe right and left between the images.
I've tried both the Panorama and Pivot control but both controls don't behave like WinRTs FlipView.
Panorama fits quite well but appears to have the "Right-Peek" Amount hardwired into the control. (please correct me if I'm wrong)
Pivot in turn shows blackness during swipes (finger still down) and only displays the next image when you release your finger and the control scrolls the next item into place.
Any suggestions?
Here is the customized FlipView control for WP8 like WINRT FlipView Control...
Step 1 : Add a new Usercontrol and name it as "FlipView.xaml"
Step 2 : Add following xaml in "FlipView.xaml"
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<ContentPresenter Name="contentPresenter"/>
<Button BorderThickness="0" Name="leftButton" FontSize="70" Margin="-25" HorizontalAlignment="Left" VerticalAlignment="Center" Content="<" Click="Button_Click"/>
<Button BorderThickness="0" Name="rightButton" FontSize="70" Margin="-25" HorizontalAlignment="Right" VerticalAlignment="Center" Content=">" Click="Button_Click_1"/>
</Grid>
Step 3 : Add the following code in the "FlipView.cs"
public partial class FlipView : UserControl
{
public FlipView()
{
InitializeComponent();
Datasource = new List<object>();
SelectedIndex = 0;
}
private IList Datasource;
public static readonly DependencyProperty ItemTemplateProperty =
DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(FlipView), new PropertyMetadata(default(DataTemplate)));
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set
{
SetValue(ItemTemplateProperty, value);
contentPresenter.ContentTemplate = value;
contentPresenter.Content = SelectedItem;
}
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IList), typeof(FlipView), new PropertyMetadata(default(IList)));
public IList ItemsSource
{
get { return (IList)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
Datasource = value;
SelectedIndex = SelectedIndex;
}
}
public static readonly DependencyProperty SelectedIndexProperty =
DependencyProperty.Register("SelectedIndex", typeof(int), typeof(FlipView), new PropertyMetadata(default(int)));
public int SelectedIndex
{
get { return (int)GetValue(SelectedIndexProperty); }
set
{
SetValue(SelectedIndexProperty, value);
rightButton.Visibility = leftButton.Visibility = Visibility.Visible;
if (SelectedIndex == 0)
{
leftButton.Visibility = Visibility.Collapsed;
}
if (SelectedIndex + 1 == Datasource.Count)
{
rightButton.Visibility = Visibility.Collapsed;
SelectedItem = Datasource[SelectedIndex];
}
if (Datasource.Count > SelectedIndex + 1)
{
SelectedItem = Datasource[SelectedIndex];
}
}
}
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(FlipView), new PropertyMetadata(default(object)));
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set
{
SetValue(SelectedItemProperty, value);
contentPresenter.Content = SelectedItem;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SelectedIndex--;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
SelectedIndex++;
}
}
Step 4 : Now at the mainpage, add the namespace to use the flipview Usercontrol
Example:
xmlns:FlipViewControl="clr-namespace:ImageFlip" (Note: It differs according to your Solution name).
Step 5 : Using the namespace, add the flipview control as follow as..
<Grid x:Name="LayoutRoot" Background="Transparent">
<FlipViewControl:FlipView Name="imgViewer">
<FlipViewControl:FlipView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Stretch="Fill"/>
</DataTemplate>
</FlipViewControl:FlipView.ItemTemplate>
</FlipViewControl:FlipView>
</Grid>
Step 6 : Add the following code in mainpage.cs
// Constructor
public MainPage()
{
InitializeComponent();
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
imgViewer.ItemsSource = new List<string> { "/Images/1.jpg", "/Images/2.jpg", "/Images/3.jpg" };
}
Hope this will help.
Thanks
There is no direct equivalent to the FlipView in Windows Phone. The Panorama and Pivot controls have very different functionalities and are designed fro different purposes.
Telerik have a SlideView control which is very similar to the native control used by the photos app.
You can also get the Telerik controls free as part of the Nokia Premium Developer Program. (Worth investigating if you don't have a Dev Center subscription.)
I know it is not the same solution, but maybe you can tweak this coverflow example here... so that the images are not stacked but side by side?
I am trying create UserControl with below requirements.
Usercontrol contains a gridview and in side gridview, I need to add a button element. So, the idea is :- if usercontrol is used in any other page by providing a collection to ItemSource then list of buttons should be generated and Button content value should be one of the property value of type present in Itemsource collection.
I am pretty newbie to windows store app programming. I am trying to expose the gridview ItemSources property by creating dependency property so that ObservableCollection of any type can be mapped and trying expose a dependency property to bind to button content property. but not able to achieve the same. I would really appreciate if you could point to a sample application doing the same.
Thanks a lot in advance.
here is a small sample (i hope that's what you wanna do)...
EDIT: I finally edited my answer to provide the property which takes the property path. IF ANYONE HAS ANOTHER SOLUTION FOR THIS QUESTION, PLEASE LET ME KNOW!
Add a dependency property for the binding path:
First we create a dummy model which provides the title for our buttons:
public class SampleModel
{
public string Title { get; set; }
}
Then, the usercontrol. The important thing here is the ItemsSource-Binding (ElementName = UserControl). Otherwise you'll bind to the UserControlItemsSource in the Parent-DataContext.
EDIT: The button has changed since my last answer!
<UserControl
x:Class="StackOverflow.ListUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:StackOverflow"
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"
x:Name="SampleUserControl">
<Grid>
<ListView ItemsSource="{Binding UserControlItemsSource, ElementName=SampleUserControl}" Background="DeepSkyBlue" SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<Button Loaded="FrameworkElement_OnLoaded"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>
... and the usercontrol's code-behind including the UsercontrolItemsSource:
EDIT: i added the dependency property BindingPropertyPath and the FrameworkElement_OnLoaded method since my last answer.
public sealed partial class ListUserControl : UserControl
{
public ObservableCollection<SampleModel> UserControlItemsSource
{
get { return (ObservableCollection<SampleModel>)GetValue(UserControlItemsSourceProperty); }
set { SetValue(UserControlItemsSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for UserControlItemsSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UserControlItemsSourceProperty =
DependencyProperty.Register("UserControlItemsSource", typeof(ObservableCollection<SampleModel>), typeof(ListUserControl), new PropertyMetadata(null));
public string BindingPropertyPath
{
get { return (string)GetValue(BindingPropertyPathProperty); }
set { SetValue(BindingPropertyPathProperty, value); }
}
// Using a DependencyProperty as the backing store for BindingPropertyPath. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BindingPropertyPathProperty =
DependencyProperty.Register("BindingPropertyPath", typeof(string), typeof(ListUserControl), new PropertyMetadata(string.Empty));
public ListUserControl()
{
this.InitializeComponent();
}
private void FrameworkElement_OnLoaded(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
Binding contentBinding = new Binding();
contentBinding.Path = new PropertyPath(this.BindingPropertyPath);
button.SetBinding(Button.ContentProperty, contentBinding);
}
}
Now we add the usercontrol to our main page (ListPageHost):
EDIT: Set the new dependency property BindingPropertyPath to the name of the property of the ItemsSource that you wanna use for the button.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Add Item to ItemsSource" Click="ButtonBase_OnClick"></Button>
<local:ListUserControl Grid.Row="1" UserControlItemsSource="{Binding SampleCollection}" BindingPropertyPath="Title"/>
</Grid>
In the mainpage's code-behind, we declare our mainpage-viewmodel (ListPageHostViewModel):
public class ListPageHostViewModel
{
private readonly ObservableCollection<SampleModel> _sampleCollection = new ObservableCollection<SampleModel>();
public ObservableCollection<SampleModel> SampleCollection
{
get { return _sampleCollection; }
}
}
... and the MainPage's (ListPageHost) code behind:
public sealed partial class ListPageHost : Page
{
public ListPageHost()
{
this.InitializeComponent();
this.DataContext = new ListPageHostViewModel();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as ListPageHostViewModel;
if (vm != null)
{
vm.SampleCollection.Add(new SampleModel() { Title = string.Format("new item {0}", DateTime.Now.Ticks)});
}
}
}
Hope that's what you're looking for. If you have any questions - let me know.
Regards, Alex
My ICommand will not trigger unless I move the DataContext field into the the DataTemplate (contlisttemplate) for the Button. I have images set in a style resource, those disappear as soon as I move the DataContext field into the DataTemplate. Both images and ICommand should be using the same DataContext so I am unsure of why it will not work.
Here is a snippet of my code below.
DataContext="{Binding LongListViewModel, Source={StaticResource viewModelLocator}}"
<i:Interaction.Behaviors>
<GamePad:XboxBehavior StartFocusControlName="continuousList1" IsTopLevelViewForFocus="True"/>
</i:Interaction.Behaviors>
<UserControl.Resources>
<DataTemplate x:Key="contlisttemplate" >
<Button
Command="{Binding Gotodetailpage}"
Style="{StaticResource custherotile}">
</Button>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<xbox:ContinuousList
HorizontalAlignment="Left"
Name="continuousList1"
VerticalAlignment="Top"
ItemTemplate="{StaticResource contlisttemplate}"
ItemsSource="{Binding LongListItems}" Height="316" Width="1280"
Grid.Row="1"
>
<i:Interaction.Behaviors>
<GamePad:XboxBehavior IsContinuousListVuiEnabled="True" HasFocusRetention="True"/>
</i:Interaction.Behaviors>
</xbox:ContinuousList>
public class LongListViewModel : ViewModelBase<LongListViewModel>
{
private readonly IDialogService dialogService;
public Navigateto compass = new Navigateto();
public LongListViewModel()
{
LongListItems = new ObservableCollection<object>();
dictionaryListwithkey = new Dictionary<string, object>();
Gotodetailpage = new RelayCommand(PerformGotoDetailPage);
}
public LongListViewModel(IDialogService dialogService)
: this()
{
this.dialogService = dialogService;
}
public Program getherovideo
{
get { return (Program)LongListItems[0]; }
set
{
//SetProperty(ref currentVideo, value,x => x.CurrentVideo);
}
}
public ObservableCollection<object> LongListItems
{
get;
set;
}
public Dictionary<string, object> dictionaryListwithkey
{
get;
set;
}
public ICommand Gotodetailpage { get; private set; }
private void PerformGotoDetailPage()
{
// Console.WriteLine("List item clicked");
compass.goToDetailsPageWithPath("89");
}
}
In case anyone was wondering what the answer was . As per Aaron Hill ATG :
This looks like an issue of scope. The outer DataContext is your LongListViewModel class, which contains the desired ICommand, but the ItemsSource for the container is set to the LongListItems collection exposed by the view-model. This means the effective DataContext for the DataTemplate is an individual member of the collection, not the overall view-model.
Overriding the DataContext of the DataTemplate would let you point back to the view-model and access the ICommand, however it also means you lose any data present within the individual elements of the LongListItems collection. That is probably why the images no longer work in this case.
Since each item in the collection has its own button, it probably makes sense for the ICommand property to be exposed on the individual item rather than the view-model.