UWP XAMl ListView Item Template MVVM Events - xaml

If I want to implement the MVVM patern. What is the correct procedure for implementing a event such as DoubletTapped on TextBlock inside a Datatemplate of a ListView.ItemTemplate?
<ListView.ItemTemplate>
<DataTemplate x:DataType="classes:Person">
<TextBlock
DoubleTapped="{x:Bind}"//what goes here to call a method on the ViewModel
Foreground="Green"
Text="{x:Bind Name}" />
</DataTemplate>
</ListView.ItemTemplate>

Please modify your TextBlock Xaml as below:
<TextBlock Foreground="Green" Text="{x:Bind Name}" >
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="DoubleTapped">
<core:InvokeCommandAction Command="{Binding ElementName=RootPage, Path=DataContext.YourCommandMethod}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBlock>
RootPage is the name of Root Element, which in my case is a Page.

Related

UWP Bind to ObservableCollection declaratively

I have a simple UWP page; there is a public ObservableCollection in the page code-behind:
public ObservableCollection<Book> MyObservableColl{ get; } = new ObservableCollection<Book>();
(note the collection consists of a single item)
I would like to bind to the collection; here is what I tried:
<StackPanel x:Name="stackPanel"
Grid.Row="2"
Margin="50"
DataContext="{x:Bind MyObservableColl, Mode=OneWay}">
<TextBox x:Name="txtTitle"
TextWrapping="Wrap"
Text="{x:Bind Title, Mode=OneWay}" />
</StackPanel>
The visual studio designer complains "the property Title was not found".
I appreciate any help to bind my text boxes to the Observable Collection.
the property Title was not found
txtTitle TextBox can't access Book item where in the MyObservableColl collection directly, you need place txtTitle under items control's ItemTemplate.
For example
<ListView ItemsSource="{x:Bind MyObservableColl, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Book">
<StackPanel>
<TextBox Text="{x:Bind Title}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For more info please refer to listview document.
Update
For single item please refer to this xaml
<StackPanel
x:Name="stackPanel"
Grid.Row="2"
Margin="50"
DataContext="{x:Bind MyObservableColl[0], Mode=OneWay}">
<TextBox Text="{Binding Title}"/>
</StackPanel>

ListViewItem access property on viewmodel

I have a list of users on my viewmodel that I pass to the following listView:
<ListView
Background="Azure"
x:Name="ContactList"
ItemsSource="{Binding Path=User}"
SelectedItem="{Binding SelectedUser, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<Border Width="300" Height="Auto" BorderThickness="1">
<StackPanel>
<TextBlock>
<Run Text="{Binding Name}" />
<Run Text="{Binding Age}" />
</TextBlock>
<CheckBox Visibility="{???}">
<TextBlock FlowDirection="LeftToRight"></TextBlock>
</CheckBox>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
As you can see my DataTemplate contains a checkbox. I would like its Visibility to depend on a bool-property I have on my ViewModel. How can I access this property from within the listView?
From looking around here it seems like there are ways to access the ListView-items parent. I think that would do it for me. Can someone point me in the right direction . Thanks
The best way to do this is to include the visibility setting along with your user data. Assuming your view model visibility property is named CheckBoxVisibility, you would have something like this:
<ListView ItemsSource="{Binding}" ...>
<ListView.ItemTemplate>
<DataTemplate>
...
<Run Text="{Binding Path=User.Name}" />
<Run Text="{Binding Path=User.Age}" />
...
<CheckBox Visibility="{Binding Path=CheckBoxVisibility}">
...
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In WPF, you can use a RelativeSource=RelativeAncestor binding; however, this is not available in Window Store/Windows Phone 8+ apps.

How to add Command to ListBox.ItemTemplate

I have a WPF application using MVVM.
This code is from my ResourceDictionary.xaml
<DataTemplate x:Key="LogListTemplate">
<ListBox ItemsSource="{Binding LogList, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource HorizontalListBoxItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Style="{StaticResource ErrorBorders}">
<StackPanel ToolTip="{Binding Details}" Width="250">
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding Details}" TextWrapping="Wrap" />
<Button Command="{Binding AddToTempDtdFileCommand}" CommandParameter="{Binding Details}" Content="Ignore" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
When I click on Button, the command does not execute. Testing confirms this is because my Button lives within a ListBox.
My problem is I can't move my button out of the ListBox for 2 reasons.
1. Asthetics/UI (the button has belong with the information)
2. Binding to the LogList is done from within the ListBox.ItemTemplate
Does any one have any suggestions?
If the command is defined in the ViewModel you can reach it by using RelativeSource. RelativeSource can find an ancestor (which is your View) so you can use its DataContext (your ViewModel).
<Button Command="{Binding DataContext.AddToTempDtdFileCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type YourViewClass}}}" CommandParameter="{Binding Details}" Content="Ignore" />

Using different databinding sources within ListBox and ContextMenus

Here is the XAML:
<ListBox ItemsSource="{Binding Documents}" BorderBrush="{x:Null}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Title}" FontSize="12" FontWeight="Bold" />
<TextBlock Text="{Binding ID}" FontSize="10" FontStyle="Italic" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu ItemsSource="{Binding CategoryList}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Command="{Binding AddDocumentToCategoryContextMenuCommand}" Header="{Binding Category.Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
Ok so the ListBox's ItemSource is bound to the Documents collection in the VM and properly renders the Titles and IDs
The Context Menu's ItemSource is bound to the CategoryList collection in the VM and properly renders the list of categories.
The problem I have is with the Command Binding:
Command="{Binding AddDocumentToCategoryContextMenuCommand}"
Since the ItemSource for the ContextMenu is already set, it tries to get the AddDocumentToCategoryContextMenuCommand from CategoryList. Obviously the command is not there, it is a member of the VM.
I do not want any references to the VMs or Models in the XAML. Everything is constructed using Unity and VM-View is associated in App.xaml:
<Application.Resources>
<DataTemplate DataType="{x:Type vms:FeedViewModel}">
<views:FeedView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vms:DocumentsViewModel}">
<views:DocumentsView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vms:ManagementViewModel}">
<views:ManagementView/>
</DataTemplate>
<DataTemplate DataType="{x:Type dev:DevelopmentViewModel}">
<dev:DevelopmentView />
</DataTemplate>
</Application.Resources>
How can I databind to a member of the VM from within the ContextItem.
Thanks.
UPDATED edit #1 starts Here
Here is the updated xaml (but still not working but some insight gained):
<ListBox ItemsSource="{Binding Documents}" x:Name="Results" BorderBrush="{x:Null}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Title}" FontSize="12" FontWeight="Bold" />
<TextBlock Text="{Binding ID}" FontSize="10" FontStyle="Italic" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu ItemsSource="{Binding CategoryList}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Command="{Binding ElementName=Results, Path=DataContext.AddDocumentToCategoryContextMenuCommand}" Header="{Binding Category.Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
I have this example working for a simple example that does not use a ContextMenu. It appears that the ContextMenu (even though attached to the ListBox) is not part of the user control visual tree. The binding always comes back null / not found. I think the ContextMenu, because it is a floating "window" is constructed in its own tree and therefore cannot find the ListBox call "Results" in order to access the ListBox's DataContext.
Any thoughts on this? Any recommendations on how deal with?
Edit #2 Starts Here
In case you are are wondering, figured out the answer to the binding question:
This binding works:
Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.AddDocumentToCategoryContextMenuCommand}
Hope this helps others with the same question.
One last update for completeness.
In order for the command to know which context menu item was clicked on, I had to change the xaml slightly (silly oversight):
<ListBox.ContextMenu>
<ContextMenu x:Name="Context" ItemsSource="{Binding CategoryList}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.AddDocumentToCategoryContextMenuCommand}"
CommandParameter="{Binding Category.ID}"
Header="{Binding Category.Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
Again, hope this helps others.
Use the ElementName property of the binding to specify that. You'd end up with something like this:
Command="{Binding ElementName=ViewModelObject
Path=AddDocumentToCategoryContextMenuCommand}"

Access property of DataContext in ItemTemplate

My datacontext has two properties: Items which is a collection and DetailsVisiblity which is enum of type Visiblity.
On the page I have a Listbox with ItemsSource="{Binding Entries}". Inside the DataTemplate, I can bind stuff to properties of Items, but how do I get access to DetailsVisiblity which is a property of DataContext?
DataContext has two properties: ObservableCollection<Item> Entries, and Visibility DetailsVisiblity. Item class has two properties: Title and Details.
Here is the view. How do I bind Visiblity of the second TextBlock to DetailsVisiblity property?
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding Details}" Visibility="{Binding ???}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You could name the ListBox and in the Binding you reference it with ElementName, and in Path you use DataContext.DetailsVisibility
<ListBox x:Name="listBox" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" />
<TextBlock Text="{Binding Details}"
Visibility="{Binding ElementName=listBox,
Path=DataContext.DetailsVisibilty}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>