I've developed app on windows phone 8 with caliburn. On one of my pages, I have a button inside of a datatemplate and I have set trigger on mouse click:
<DataTemplate>
<Button>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<micro1:ActionMessage MethodName="GoToPage">
<micro1:Parameter Value="{Binding Path=PageId}" />
</micro1:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock Text="{Binding Path=PageDescription}" TextWrapping="Wrap"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Button>
</DataTemplate>
It works fine.
Now I've created new app on windows phone 8.1 (winrt), but with same code I've an error on trigger. How i can do it on wp 8.1 ? I have found winrttriggers.codeplex.com but it isn't compatible with wp 8.1 platform.
Thanks a lot!
EDIT 1:
With your code my view doesn't fire command.
Now I have:
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:InvokeCommandAction Command="{Binding OpenPageCommand}" CommandParameter="{Binding Path=PageId}" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
My command is delegate command:
public class DelegateCommand<T> : ICommand
{
private readonly Func<T, bool> _canExecuteMethod;
private readonly Action<T> _executeMethod;
#region Constructors
public DelegateCommand(Action<T> executeMethod)
: this(executeMethod, null)
{
}
public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
{
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
}
#endregion Constructors
#region ICommand Members
public event EventHandler CanExecuteChanged;
bool ICommand.CanExecute(object parameter)
{
try
{
return CanExecute((T)parameter);
}
catch { return false; }
}
void ICommand.Execute(object parameter)
{
Execute((T)parameter);
}
#endregion ICommand Members
#region Public Methods
public bool CanExecute(T parameter)
{
return ((_canExecuteMethod == null) || _canExecuteMethod(parameter));
}
public void Execute(T parameter)
{
if (_executeMethod != null)
{
_executeMethod(parameter);
}
}
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged(EventArgs.Empty);
}
#endregion Public Methods
#region Protected Methods
protected virtual void OnCanExecuteChanged(EventArgs e)
{
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, e);
}
}
#endregion Protected Methods
}
On my view model I have:
public ICommand OpenPageCommand { get; set; }
on constructor:
OpenPageCommand = new DelegateCommand<Guid>(GoToPage);
and my methods is:
public void GoToPage(Guid pageId)
{ .....
but it does not work. Any idea?
Thanks so much!
You should be able to do this with the Behaviors SDK. Include this namespaces:
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
And than you should be able to trigger a command like this:
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Click">
<core:InvokeCommandAction Command="{Binding GoToPage}" CommandParameter="{Binding Path=PageId}" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
Related
I added a button to player from PlayerFramework, when click that button, a ListView appear for select video quality.
But I dont know how to implement ItemClicked event to handle when user click a item in ListView. Anyone can help me?
My code:
Entertainment.xaml
<AppBarButton x:Name="QualityButton"
Grid.Column="3"
Width="30"
Height="30"
Margin="8,0,8,0"
Icon="Setting"
Style="{TemplateBinding TransportBarButtonStyle}"
Visibility="Visible">
<AppBarButton.Flyout>
<Flyout>
<ListView Name="listView"
IsItemClickEnabled="True"
ItemsSource="{Binding List}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Flyout>
</AppBarButton.Flyout>
</AppBarButton>
CustomInteractiveViewModel.cs
public class CustomInteractiveViewModel : InteractiveViewModel
{
public CustomInteractiveViewModel(List<string> list, MediaPlayer player)
: base(player)
{
List = list;
}
public List<string> List { get; set; }
}
MainPage.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
var list = new List<string> { "360p", "480p", "720p" };
player.InteractiveViewModel = new CustomInteractiveViewModel(list, player);
player.Source = new Uri(Video, UriKind.RelativeOrAbsolute);
}
MainPage.xaml
<Page x:Class="testPlayer.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:testPlayer"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mmppf="using:Microsoft.PlayerFramework"
xmlns:webvtt="using:Microsoft.PlayerFramework.WebVTT"
mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/Entertainment.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<mmppf:MediaPlayer Name="player" />
</Grid>
</Page>
It is not supported to binding event like ItemClick or SelectionChanged in ResourceDictionary, a simple method is to create the code behind of this ResourceDictionary, but to maintain the MVVM pattern integrity, it's better to register a Attached property, and bind events to this attached property.
You can change your code in Entertainment.xaml like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.PlayerFramework.Controls"
xmlns:local="using:Microsoft.PlayerFramework">
...
<AppBarButton x:Name="QualityButton" Grid.Column="3" Width="30" Height="30" Margin="8,0,8,0"
Icon="Setting" Style="{TemplateBinding TransportBarButtonStyle}" Visibility="Visible">
<AppBarButton.Flyout>
<Flyout>
<ListView Name="listView" IsItemClickEnabled="True" ItemsSource="{Binding List}" controls:CustomInteractiveViewModel.ItemClickCommand="{Binding ItemClickedCommand}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Flyout>
</AppBarButton.Flyout>
</AppBarButton>
...
</ResourceDictionary>
and the code in CustomInteractiveViewModel.cs:
public class CustomInteractiveViewModel : InteractiveViewModel
{
public CustomInteractiveViewModel(List<string> list, MediaPlayer player, DelegateCommand<string> itemclickedcommand)
: base(player)
{
List = list;
ItemClickedCommand = itemclickedcommand;
}
public List<string> List { get; set; }
public DelegateCommand<string> ItemClickedCommand { get; set; }
public static DependencyProperty ItemClickCommandProperty =
DependencyProperty.RegisterAttached("ItemClickCommand",
typeof(ICommand),
typeof(CustomInteractiveViewModel),
new PropertyMetadata(null, OnItemClickCommandChanged));
public static void SetItemClickCommand(DependencyObject target, ICommand value)
{
target.SetValue(ItemClickCommandProperty, value);
}
public static ICommand GetItemClickCommand(DependencyObject target)
{
return (ICommand)target.GetValue(ItemClickCommandProperty);
}
private static void OnItemClickCommandChanged(DependencyObject target,
DependencyPropertyChangedEventArgs e)
{
var element = target as ListViewBase;
if (element != null)
{
if ((e.NewValue != null) && (e.OldValue == null))
{
element.ItemClick += OnItemClick;
}
else if ((e.NewValue == null) && (e.OldValue != null))
{
element.ItemClick -= OnItemClick;
}
}
}
private static void OnItemClick(object sender, ItemClickEventArgs e)
{
GetItemClickCommand(sender as ListViewBase).Execute(e.ClickedItem);
}
}
Finally in your MainPage.cs:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
var list = new List<string> { "360p", "480p", "720p" };
var ItemClickedCommand = new DelegateCommand<string>(ItemClicked);
player.InteractiveViewModel = new CustomInteractiveViewModel(list, player, ItemClickedCommand);
}
public void ItemClicked(string item)
{
//TODO:
}
And the DelegateCommand<T> class is like this:
public class DelegateCommand<T> : ICommand
{
private readonly Action<T> _execute;
private readonly Func<T, bool> _canExecute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<T> execute, Func<T, bool> canexecute = null)
{
if (execute == null)
throw new ArgumentNullException(nameof(execute));
_execute = execute;
_canExecute = canexecute ?? (e => true);
}
public bool CanExecute(object p)
{
try { return _canExecute(ConvertParameterValue(p)); }
catch { return false; }
}
public void Execute(object p)
{
if (!this.CanExecute(p))
return;
_execute(ConvertParameterValue(p));
}
private static T ConvertParameterValue(object parameter)
{
parameter = parameter is T ? parameter : Convert.ChangeType(parameter, typeof(T));
return (T)parameter;
}
public void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
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));
}
}
I am using Windows Phone Toolkit nuget package (http://phone.codeplex.com/). I want to create a LoopingSelector in my WP8 application, where I can select day dates, but I don't want the LoopingSelector to show days before today in it's selection.
My control looks like this:
http://s2.postimg.org/6bgnxefnt/image.png
This is perfectly working until I select the first element of the source (today Dec 04), then my application becomes unresponsive (I can press buttons, effect are shown, but the event handlers won't execute). I guess this is an infinite loop or deadlock, but it's not in my own code (I debugged it).
The definition of the LoopingSelector's data source:
public class NextDatesDataSource : LoopingDataSource<NextDateModel>
{
public NextDatesDataSource() : base(NextDateModel.Create(DateTime.Today)) { }
protected override NextDateModel GetNext(NextDateModel relativeTo)
{
if (relativeTo.Date == DateTime.Today + TimeSpan.FromDays(10))
return null;
return NextDateModel.Create(relativeTo.Date + TimeSpan.FromDays(1));
}
protected override NextDateModel GetPrevious(NextDateModel relativeTo)
{
//if i comment the next two lines, then everything works perfect
if (relativeTo.Date == DateTime.Today)
return null;
return NextDateModel.Create(relativeTo.Date - TimeSpan.FromDays(1));
}
}
LoopingDataSource:
public abstract class LoopingDataSource<T> : ILoopingSelectorDataSource
{
protected LoopingDataSource() { selectedItem = default(T); }
protected LoopingDataSource(T initialSelection) { selectedItem = initialSelection; }
protected abstract T GetNext(T relativeTo);
protected abstract T GetPrevious(T relativeTo);
public object GetNext(object relativeTo)
{
if (relativeTo == null) return null;
return GetNext((T)relativeTo);
}
public object GetPrevious(object relativeTo)
{
if (relativeTo == null) return null;
return GetPrevious((T)relativeTo);
}
private T selectedItem;
public object SelectedItem
{
get
{
return selectedItem;
}
set
{
object oldVal = selectedItem;
selectedItem = (T)value;
if (SelectionChanged != null)
SelectionChanged(this, new SelectionChangedEventArgs(new object[] { oldVal }, new object[] { value }));
}
}
public T Selected
{
get { return (T)SelectedItem; }
set { SelectedItem = value; }
}
public event EventHandler<SelectionChangedEventArgs> SelectionChanged;
}
The definition of the control element:
<p:LoopingSelector
x:Name="DaySelector"
Grid.Column="0" Grid.Row="1"
ItemSize="230,110"
ItemMargin="6" Margin="10,5,5,5">
<p:LoopingSelector.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Header}" FontSize="28" VerticalAlignment="Top"/>
<TextBlock Text="{Binding Body}" FontSize="42" FontWeight="Bold" VerticalAlignment="Bottom"/>
</Grid>
</DataTemplate>
</p:LoopingSelector.ItemTemplate>
</p:LoopingSelector>
I do this in the constructor:
DaySelector.DataSource = new NextDatesDataSource();
Thank you very much!
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; }
}
I am writing a windows 8 store application and have the following problem:
I have a textblock binded to a long property of an object.
The long value is 123456789, however, on the screen i only see the char 1.
How can i solve this, and why the convertion to string doesn't work like it should?
Try this and let me if it works for you or not.
XAML
<Page.DataContext>
<local:myVm />
</Page.DataContext>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<GridView ItemsSource="{Binding col}">
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Margin="20" FontSize="20" />
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid MaximumRowsOrColumns="3" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</Grid>
myVm.cs
public class myVm : INotifyPropertyChanged
{
public myVm()
{
col.Add(long.MaxValue);
col.Add(long.MaxValue);
col.Add(long.MaxValue);
col.Add(long.MaxValue);
col.Add(long.MaxValue);
col.Add(long.MaxValue);
}
private ObservableCollection<long> _col = new ObservableCollection<long>();
public ObservableCollection<long> col
{
get { return _col; }
set
{
_col = value;
NotifyPropertyChanged("col");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}