ICommand will not trigger - xbox360

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.

Related

Instantiate new object from Binding in xaml for Flyout

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));
}
}

How to popup ContextMenu in ListBox programmatically on Windows Phone?

I have a ListBox in my page, I want some items in the ListBox can popup ContextMenu when you long press it, and some items don't, how can I implement this requriment programmatically?
Here is one possible solution. Define your Item's class with some information about popup:
public class Item
{
public string Info { get; set; }
// Menu attached or not
public bool OptionsEnabled { get; set; }
}
In XAML you will have to define your ListView (or ListBox) with apropriate ItemTelplate:
<ListView Name="myList" Holding="myList_Holding">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Info}" FontSize="24" Margin="7">
<FlyoutBase.AttachedFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="First option"/>
<MenuFlyoutItem Text="Second option"/>
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then upon Holding event you can check OptionsEnabled property if to show a menu,if yes then do so:
private void myList_Holding(object sender, HoldingRoutedEventArgs e)
{
if (e.OriginalSource == null || !(e.OriginalSource is TextBlock)) return;
TextBlock listItem = e.OriginalSource as TextBlock;
if (listItem.DataContext == null) return;
Item itemData = listItem.DataContext as Item;
if (itemData.OptionsEnabled)
FlyoutBase.ShowAttachedFlyout(listItem);
}
A working sample you can download here.

Windows phone 8: get value item of listbox

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).

using Gridview control inside a usercontrol

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

Using a progress indicator that gets hidden within a Panorama control is causing the panorama item to just to 1st one

I have a really strange and annoying issue on my WP8 app.
It's using a Panorama control to view items that it downloads from the Net. It has a view that is displayed whilst it's downloading content but then gets collapsed after the content has completed loading.
When the "loading" view is collapsed I'm finding that the Panorama control jumps back to the first item in the control regardless of what item you have selected.
I have the following very basic test code that demonstrates the issue.
XAML:
<phone:PhoneApplicationPage
x:Class="Wp8.GUI.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converters="clr-namespace:Wp8.Gui.Converters"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.Resources>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Grid.Resources>
<phone:Panorama ItemsSource="{Binding PanoramaItems}">
<phone:Panorama.HeaderTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Title}" />
</Grid>
</DataTemplate>
</phone:Panorama.HeaderTemplate>
<phone:Panorama.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel x:Name="Visible1" Visibility="{Binding ShowFirst, Converter={StaticResource BooleanToVisibilityConverter},ConverterParameter=True}" >
<ProgressBar IsIndeterminate="True" />
<TextBlock Text="ShowFirst" />
</StackPanel>
<StackPanel x:Name="Visible2" Visibility="{Binding ShowFirst, Converter={StaticResource BooleanToVisibilityConverter},ConverterParameter=False}" >
<TextBlock Text="Show Second" />
</StackPanel>
</Grid>
</DataTemplate>
</phone:Panorama.ItemTemplate>
</phone:Panorama>
</Grid>
</phone:PhoneApplicationPage>
The VM and Code Behind is as follows:
namespace Wp8.GUI
{
public class PanItemVm : INotifyPropertyChanged
{
private readonly string _title;
private bool _showFirst = true;
public PanItemVm()
{
_title = "Control";
}
public PanItemVm(string title)
{
_title = title;
}
public string Title { get { return _title; } }
public bool ShowFirst
{
get { return _showFirst; }
set
{
_showFirst = value;
RaisePropertyChanged("ShowFirst");
}
}
private void RaisePropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class PanItemVm2 : PanItemVm
{
public PanItemVm2() : base ("Items")
{
Task.Run(() => Task.Delay(TimeSpan.FromSeconds(5)))
.ContinueWith(t => ShowFirst = false,
TaskScheduler.FromCurrentSynchronizationContext());
}
}
public class TestVm : INotifyPropertyChanged
{
public IEnumerable<PanItemVm> PanoramaItems
{
get {
return Enumerable.Range(0, 2)
.Select(i => i == 0 ?
new PanItemVm() : new PanItemVm2()); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
DataContext = new TestVm();
}
}
}
If you run up the code in an emulator and then flick to Item2 in the Panorama. After 5 seconds it'll flick back to the page marked "Control".
In this test code I can get around the problem by either
a) Changing the StackPanel that the ProgressIndicator is contained in to a Grid
b) Removing the ProgressIndicator
Neither of these solutions work for my proper project however but if I remove Visibility code that uses the BooleanToVisibilityConverter then it doesn't flick back.
Does anybody have any ideas what might be causing this?
I can post the entire sample code if that's useful.
Thanks
--- EDIT ---
Here is the code for the BooleanToVisibilityConverter
using System.Windows;
using System.Windows.Data;
namespace Wp8.Gui.Converters
{
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value is bool)
{
bool visibilityValue = true;
if(parameter != null)
{
if(parameter is string)
{
bool.TryParse((string)parameter, out visibilityValue);
}
}
return (bool)value == visibilityValue ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Visible;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
}
I've been having the same problem. I have a Panorama (modified to fill the full screen) that I'm using to display pictures in a carousel. I have to turn the pictures on/off based on Panorama position to keep the memory low. However, whenever a picture loads, the panorama returns to the default item... the first item.
So I took a hint from another question and went to look at the source code for Panorama. While you can't see the current code, you can see what Panorama was when it was part of the WP Toolkit. It seems that anytime there is a change in size of the panorama, the internal scrollviewer is reset.
void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
// clip to control layout
LayoutRoot.SetValue(Panel.ClipProperty, new RectangleGeometry() { Rect = new Rect(0, 0, this.Width, this.Height) });
// reset scroll viewer
Dispatcher.BeginInvoke(() =>
{
ScrollView.Invalidate(false);
});
}
OK. That was a clue. So I played around with my itemtemplate (my header is non-existent) trying to see what was changing size. SOMETHING was changing size... not sure what. So I wrapped everything in a Grid and hardcoded the Width/Height/MaxWidth/MaxHeight to be equal to the Screen Height/Width. They are bound to calculated values in my viewmodel that change according to device orientation.
<controls:PanoramaFullScreen.ItemTemplate>
<DataTemplate>
<Grid Width="{Binding LayoutWidth}"
MaxWidth="{Binding LayoutWidth}"
Height="{Binding LayoutHeight}"
MaxHeight="{Binding LayoutHeight}">
{rest of stuff}
</Grid>
</DataTemplate>
It works! No more switching back to item one!
So I suspect your code is changing the overall height/width of a PanoramaItem, which is in turn changing the Panorama size and resetting the internal scrollviewer.