So, I am designing a Universal Windows app which uses a ListView with data bound to it which i create programatically. The XAML for my page:
<ListView x:Name="lvEpisodeListSource" Margin="10,170,10,10" ItemsSource="{Binding Source={StaticResource EpisodeListSource}}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Episode">
<ListViewItem Background="CadetBlue" IsDoubleTapEnabled="False" IsHoldingEnabled="False" Tapped="ListViewItem_Tapped" IsRightTapEnabled="False" HorizontalAlignment="Stretch">
<TextBlock Name="AlbumBlock" Foreground="Black" FontWeight="Normal" FontSize="15" Margin="5,0,0,0"
Text="{x:Bind Name}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</ListViewItem>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
The data binds correctly and that all works fine. I am trying to then save the most recently clicked ListViewItem to LocalApplicationData. Currently, I am trying to do this by setting the Local App Data in the tapped event for the Items.
private void ListViewItem_Tapped(object sender, TappedRoutedEventArgs e)
{
myData data = ((ListViewItem)sender).DataContext as myData;
var clickedNumber = lvDataListSource.Items.IndexOf(((ListViewItem)sender));
}
This is currently not working and the clickedNumber always returns -1 no matter which I click. Is there a way to get the index of the item which called the tapped event or is there a better way to do want I want to accomplish?
Thanks!
Getting index or data corresponding to whole ListView (Parent Context) Instead of ListViewItem (Child Context) is always better.
Change your XAML to below.
<ListView x:Name="lvEpisodeListSource" Margin="10,170,10,10" ItemsSource="{Binding Source={StaticResource EpisodeListSource}}" SelectionChanged="ListView_SelectionChanged>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Episode">
<TextBlock Name="AlbumBlock" Foreground="Black" FontWeight="Normal" FontSize="15" Margin="5,0,0,0"
Text="{x:Bind Name}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
and your Selection Changed event would be
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView view = (ListView)sender;
//Get Index of Selected Item
var index = view.SelectedIndex;
//Get Selected Item
var selectedItem = view.SelectedItem;
}
I would suggest always to refer parent resource and try to drill down to child unless you have a child click event which gives direct resource to get the parent.
Related
I have a ComboBoxItem with a child button and I would like to prevent the ComboBox from dropping up (collapsing) when that button is clicked. Apparently it seems that the button is bubbling up the click event to the ComboBoxItem, causing the drop down to collapse.
<ComboBox DropDownOpened="OnWindowsDropDownOpened">
<ComboBox.ItemTemplateSelector>
<s:ComboBoxItemTemplateSelector>
<s:ComboBoxItemTemplateSelector.SelectedTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}" />
</DataTemplate>
</s:ComboBoxItemTemplateSelector.SelectedTemplate>
<s:ComboBoxItemTemplateSelector.DropDownTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Button Command="{Binding DataContext.HighlightWindow, ElementName=Windows}" CommandParameter="{Binding}" MouseDown="Button_MouseDown" Click="Button_Click">
<md:PackIcon Kind="Target" />
</Button>
<TextBlock Text="{Binding Description}" />
</StackPanel>
</DataTemplate>
</s:ComboBoxItemTemplateSelector.DropDownTemplate>
</s:ComboBoxItemTemplateSelector>
</ComboBox.ItemTemplateSelector>
<ComboBox.ItemContainerStyle>
<Style BasedOn="{StaticResource MaterialDesignComboBoxItemStyle}" TargetType="ComboBoxItem">
<Setter Property="IsEnabled" Value="{Binding Valid}" />
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Text="{Binding Title}" />
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
As we can see, I tried both MouseDown and Click, handling the event, as follows:
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
e.Handled = true;
}
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
How do I do that? Also, is it possible to use MVVM code only (XAML-based code, no C#)?
Here's a screenshot of the ComboBox open
One you have not tested yet PreviewMouseLeftButtonDown and do it by the ComboBox. Or you can take another Preview* event.
private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = sender is Button;
}
<ComboBox DropDownOpened="OnWindowsDropDownOpened" PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown">
In WPF, elements are selected based on their behavior, not their visual appearance.
The behavior of the ComboBox (including) is to collapse when an item is selected.
If you do not need this, but need an explicit, separate action from the user to collapse the list, then use another element or a combination of them.
In my opinion, the Expander with a nested ListBox will be the most convenient for your task.
<ListView x:Name="listview" ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.ZoomMode="Enabled"
ItemsSource="{Binding YourCollection}" DoubleTapped="listview_DoubleTapped" Tapped="listview_Tapped" SelectionChanged="listview_SelectionChanged"
GotFocus ="StackPanel_GotFocus" IsItemClickEnabled="True" ItemClick="ListView_ItemClick"
Margin="162,539,-103,11" Style="{StaticResource ListViewStyle1}" ScrollViewer.VerticalScrollBarVisibility="Disabled" Grid.RowSpan="2">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Height="130" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate >
<DataTemplate>
<StackPanel Orientation="Vertical" Height="130" Width="192" >
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" Height="108" Width="192" HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding Name}" TextAlignment="Center" Height="22" Width="192" Foreground="White" FontFamily="Assets/GothamLight.ttf#GothamLight"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Need to set the focus or selection to first item of the listview items. The listview contains an array of items, where the focus needs to be targeting first item during start and then retain the last chosen item.
There are multiple options here depending on your coding style. It looks like you're using code behind from our event handlers and binding to a view model class with YourCollection property, so I'll give you both examples. :)
Using code-behind
Update your XAML file to handle the Loaded event and name your ListView:
<Page Loaded="Page_Loaded">
...
<ListView Name="MyListView" ItemsSource="{Binding YourCollection}">
...
</ListView>
Then add the following code your Page_Loaded handler:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
if (MyListView.Items.Count > 0)
MyListView.SelectedIndex = 0;
}
Using view model
Provide a SelectedItem property in your view model (wherever you are defining YourCollection):
private YourItem_selectedItem = null;
public Dumb SelectedItem
{
get { return _selectedItem; }
set { SetProperty<YourItem>(ref _selectedItem, value); }
}
Then bind your ListView to the selected item, as you did with your ItemsSource:
<ListView Name="MyListView" ItemsSource="{Binding YourCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
Finally, just set your SelectedItem after you've loaded your collection items.
This method also has the benefit of replacing your SelectionChanged and ItemClick events. You won't need them because the control changes SelectedItem by default in those situations.
I found a further solution that does not require the Page_Loaded handler nor the property SelectedItem in the ViewModel.
<ListView Name="yourCollectionListView"
ItemsSource="{Binding YourCollection}"
SelectedItem="{Binding RelativeSource={RelativeSource Self}, Path=ItemSource[0]}"/>
Of course you should ensure the list has at least one item. With VisualState.StateTriggers you can hide the ListView if it is empty.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding YourCollection.Count, Converter={StaticResource EqualToParam}, ConverterParameter={StaticResource Zero}}"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="yourCollectionListView.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Define the zero value in the page's resources:
<x:Int32 x:Key="Zero">0</x:Int32>
EDIT
It is even possible to achieve this by binding the following to the SelectedItem property:
SelectedItem="{Binding Path=[0]}"
I have this gridview which works fine, but everytime I select an item I got this blue line around the item, how to remove it ?
<GridView Margin="5,15,0,0" x:Name="List" ItemsSource="{Binding}" SelectionChanged="List_SelectionChanged">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Margin="11">
<StackPanel BorderBrush="Black" Orientation="Vertical">
<Image Width="150" Height="150" Source="{Binding Way}" />
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid MaximumRowsOrColumns="2" Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
The following fixed it for me:
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewItem">
<ListViewItemPresenter
SelectedBackground="Transparent"
SelectedPointerOverBackground="Transparent"
PressedBackground="Transparent"
SelectedPressedBackground="Transparent"
/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GridView.ItemContainerStyle>
To remove the selection blue border of GridView, we can modify the template of GridView. To modify the template of GridViewItem, we can select the GridView in "Document Outline" and right click, then select "Edit Additional Templates"→ "Edit Generated Item Container (ItemContainerStyle)" → "Edit a Copy...".
In the Style, there is a ListViewItemPresenter in it.
When developing for Windows 10, use ListViewItemPresenter instead of GridViewItemPresenter in your item container style, both for ListView and for GridView.
For more info, see ListViewItemPresenter.
The color of blue line around the item is defined by SelectedBackground="{ThemeResource SystemControlHighlightAccentBrush}". We can set the SelectedBackground="Transparent", then there is no blue line around the item.
This is how I do it. Although it's not difficult to change the style, this requires about 99% less xaml (and a bit more code) to accomplish. You will have to remove the SelectionChanged event, specify the data type for your DataTemplate and add a Tapped event to each item.
<GridView SelectionMode="None" ItemsSource="{Binding}"
<GridView.ItemTemplate>
<DataTemplate x:DataType="YourType">
<Grid Tapped="Grid_Tapped_For_Every_Item">
...
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
...
</GridView>
in code file:
private void Grid_Tapped_For_Every_Item(object sender, TappedRoutedEventArgs e){
var g = (Grid) sender;
var myClass = (YourType)g.DataContext;
//Do whatever you were going to do in the SelectionChanged event
}
I need to capture the event when user click on empty jumplists, but I've tried the tap event , or put the datatemplate of jumplist in a button and tried click event, but neither of them worked. It's seem like I can't interact with empty section. The Longlistselector only provides 2 method : JumplistOpening and JumplistClosed. So how can I click on the gray jumplist ?
<phone:LongListSelector x:Name="llsMainSong"
IsGroupingEnabled="True" HideEmptyGroups="True"
JumpListStyle="{StaticResource JumpListStyle}"
GroupHeaderTemplate="{StaticResource GroupHeaderTemplate}"
ItemsSource="{Binding GroupedMainSongList}">
.........
</phone:LongListSelector>
<Style x:Key="JumpListStyle" TargetType="phone:LongListSelector">
<Setter Property="GridCellSize" Value="230,113"/>
<Setter Property="LayoutMode" Value="Grid" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Button Background="LightGray" Height="113" Margin="6" Click="Button_Click">
<TextBlock Text="{Binding Title}" FontSize="28" Padding="6" VerticalAlignment="Center"
Style="{StaticResource HelveBoldWhite}"/>
</Button>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
private void Button_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("click");
// ^ only jumplist which bind to group has data fired the event.
}
I have this xaml. And I need to uncheck all other checkboxes where one is checked. I other words to allow to check only one. I add TreeViewItems on a runtime.
<TreeView Name="treeView_max" >
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<CheckBox Name="chk" Margin="2" Tag="{Binding}" Checked="checkBox_Checked">
</CheckBox>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
</TreeView>
Adding TreeViewItems at runtime:
foreach (Genesyslab.Desktop.Modules.Core.Model.BusinessAttributes.IDispositionCodeValue item in listOfDispositionCodeValueItemsControl.Items)
{
TreeViewItem newChild2 = new TreeViewItem();
newChild2.Header = item.DisplayName.Remove(0,item.DisplayName.IndexOf("-") + 1);
treeView_max.Items.Add(newChild2);..........`
and
private void checkBox_Checked(object sender, RoutedEventArgs e)
{
try
{
//uncheck all checkboxes except selected one
}
catch (Exception es)
{
MessageBox.Show(es.ToString());
}
}
You can use RadioButton controls that belong to the same group instead, which will get you the behavior of only one option being able to be selected at a time.
Then edit the control template to display CheckBox controls in place of those RadioButton's, and bind the IsChecked property of each CheckBox to its parent RadioButton. Now when you "check" a CheckBox, all other CheckBox controls will become unchecked.
<TreeView Name="treeView_max" >
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<RadioButton Name="chk" Margin="2" Tag="{Binding}" GroupName="SomeGroup">
<RadioButton.Template>
<ControlTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=RadioButton}}" />
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
</TreeView>
Be careful about where you use this. Users are used to seeing RadioButton's when they're only able to select one option, and CheckBox's where they can select multiple options.