I have a problem. I have a list view in my xaml:
<ListView
Margin="0 10 0 0"
DockPanel.Dock="Top"
ItemsSource="{Binding Items}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
BorderThickness="0"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<local:ItemView/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My item view looks like this (which is in UserControl tag):
<buttons:MyButton
cal:Message.Attach="DoSomething">
<buttons:MyButton.Visual>
<DockPanel
HorizontalAlignment="Left">
<local:Image
DockPanel.Dock="Left"
CountryCode="{Binding Source}"/>
<TextBlock
DockPanel.Dock="Left"
VerticalAlignment="Center"
Padding="15 0 0 0"
FontFamily="{StaticResource MediumFont}"
FontSize="16"
Foreground="{StaticResource DarkText}"
Text="{Binding TextValue}" />
</DockPanel>
</buttons:MyButton.Visual>
</buttons:MyButton>
Now the problem is that when i click on the list item, my selectedItem is not set. It always null unless I click on the very edge of the list item, then it sets the selected value, but i have to click again in the middle of the item to call the action I want.
My question is: How can I make my list view item on click (on the whole item plot) set the selected item and call the action I want?
P.S. I am using Caliburn Micro if this helps...
If you don't mind using code behind or a view model, you could do something like this:
<ListView.ItemTemplate>
<DataTemplate>
<Button BorderBrush="Transparent" Background="Transparent" Focusable="False">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding DataContext.ClickCommand, ElementName=ListViewName}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<!-- YOUR TEMPLATE HERE -->
<Button.Template>
</DataTemplate>
</ListView.ItemTemplate>
This is a view/control related thing. You could handle the Click event for the Button and explicitly set the IsSelected property of the parent ListViewItem container like this:
private void OnClick(object sender, RoutedEventArgs e)
{
var listViewItem = FindParent<ListViewItem>(sender as DependencyObject);
if (listViewItem != null)
listViewItem.IsSelected;
}
private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
{
var parent = VisualTreeHelper.GetParent(dependencyObject);
if (parent == null) return null;
var parentT = parent as T;
return parentT ?? FindParent<T>(parent);
}
XAML:
<ListView.ItemTemplate>
<DataTemplate>
<local:ItemView ButtonBase.Click="OnClick"/>
</DataTemplate>
</ListView.ItemTemplate>
Or you could set the SelectedItem property of the ListView to the DataContext of the element:
private void OnClick(object sender, RoutedEventArgs e)
{
FrameworkElement fe = sender as FrameworkElement;
if (fe != null)
listView.SelectedItem = fe.DataContext;
}
XAML:
<ListView x:Name="listView" ... />
I know this is an old question, but what I think you were looking for is something like this
<ListView ItemsSource="{Binding ListViewItemTemplates}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button x:Name="StartPage">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:Action.Target>
<cal:ActionMessage MethodName="StartPage">
<cal:Parameter Value="{Binding}" />
</cal:ActionMessage>
</cal:Action.Target>
</i:EventTrigger>
</i:Interaction.Triggers>
<Button.Template>
<ControlTemplate>
<StackPanel Width="210" Orientation="Horizontal">
<Image Source="{Binding Path=Source}"
Stretch="None" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView/>
Then you can easily bind this with the following
private ObservableCollection<ListViewItemTemplate> listViewItemTemplates;
public ObservableCollection<ListViewItemTemplate> ListViewItemTemplates
{
get => listViewItemTemplates;
set
{
listViewItemTemplates = value;
this.OnPropertyChanged("ListViewItemTemplates");
}
}
Where ListviewItemTemplate is a class consisting of two strings Name and Source
Related
I am creating custom phone book which reads phone book contacts and displays inside my application. So I am creating a long list selector and a listbox inside it.
My listbox will contain phone contact name and list of phone number with the check box under the particular name. I wrote an event trigger inside my listbox to make track of the checkbox is clicked or not.
PROBLEM : Event is not firing in the view model. I suspect since the listbox is present inside another list(long list selector), event is not firing.
Here is xaml code:
<phone:LongListSelector Grid.Row="3" LayoutMode="List" ItemsSource="{Binding PhoneBookDataSource}" IsGroupingEnabled="True" HideEmptyGroups="True">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding PhoneContactName}" FontWeight="SemiBold" FontSize="36" Foreground="Green"></TextBlock>
<ListBox ItemsSource="{Binding LstPhoneContactNumber,Mode=TwoWay}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding PhoneNumberCheckedStateChangeCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="480">
<TextBlock Text="{Binding PhoneNumberItem}" FontSize="25" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="Gray"></TextBlock>
<CheckBox Foreground="Black" Background="Black" VerticalAlignment="Center" HorizontalAlignment="Right" IsChecked="{Binding IsPhoneNumberItemChecked,Mode=TwoWay}"></CheckBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
<phone:LongListSelector.GroupHeaderTemplate>
<DataTemplate>
<Border Background="Transparent" Padding="5">
<Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Width="62"
Height="62" Margin="0,0,18,0" HorizontalAlignment="Left">
<TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6"
FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Border>
</Border>
</DataTemplate>
</phone:LongListSelector.GroupHeaderTemplate>
<phone:LongListSelector.JumpListStyle>
<Style TargetType="phone:LongListSelector">
<Setter Property="GridCellSize" Value="113,113"/>
<Setter Property="LayoutMode" Value="Grid" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Width="113" Height="113" Margin="6" >
<TextBlock Text="{Binding Key}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="48" Padding="6"
Foreground="{Binding Converter={StaticResource ForegroundConverter}}" VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</phone:LongListSelector.JumpListStyle>
</phone:LongListSelector>
Here is my view model:
public DelegateCommand PhoneNumberCheckedStateChangeCommand { get; set; }
public DelegateCommand SendSMSCommand { get; set; }
public CustomPhoneBookViewModel(INavigationService nav, IDataService data, IAESEnDecrypt encrypt, IGeoLocationService geoLocation, IMessageBus msgBus, ISmartDispatcher smartDispatcher)
: base(nav, data, encrypt, geoLocation, msgBus, smartDispatcher)
{
IsProgressBarBusy = true;
PhoneContactsList = new ObservableCollection<PhoneBookEntity>();
PhoneBookDataSource = new ObservableCollection<LLSAlphaKeyGroup<PhoneBookEntity>>();
InitializeDelegateCommands();
GetDeviceResolution();
ReadPhoneBook();
}
private void OnPhoneNumberItemCheckedStateChangedCommand()
{
try
{
foreach (var parentItem in PhoneBookDataSource)
{
foreach (var childItem in parentItem)
{
foreach (var item in childItem.LstPhoneContactNumber)
{
if (item.IsPhoneNumberItemChecked)
IsSendSMSButtonEnabled = true;
return;
}
}
IsSendSMSButtonEnabled = false;
}
}
catch { }
finally
{
SendSMSCommand.RaiseCanExecuteChanged();
}
}
Any suggestions is appreciated!!
The easiest way of making the nested ListBox interaction bind to the global ViewModel (instead of to its own, nested DataContext) is to assign a unique name to the outmost LongListSelector:
<phone:LongListSelector x:Name="OuterList" Grid.Row="3" LayoutMode="List" ItemsSource="{Binding PhoneBookDataSource}" IsGroupingEnabled="True" HideEmptyGroups="True">
and explicitly bind the Command to this element's DataContext (which is the global ViewModel):
<i:InvokeCommandAction Command="{Binding ElementName=OuterList, Path=DataContext.PhoneNumberCheckedStateChangeCommand}" />
i am trying to add contacts in list as my code is,
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,10">
<TextBlock x:Name="ContactResultsLabel" Text="results are loading..." Style="{StaticResource PhoneTextLargeStyle}" TextWrapping="Wrap"></TextBlock>
<ListBox x:Name="ContactResultsData" ItemsSource="{Binding listOfContacts}" Height="293" Margin="24,0,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="contactChk" IsChecked="false" Foreground="Black" Background="Black" BorderBrush="White"></CheckBox>
<TextBlock x:Name="ContactResultsName" Text="{Binding Name}" FontSize="50"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
not able to get contacts under list box i am using this method on button click,
private void GetSelectedCheckObjItem()
{
try
{
for (int i = 0; i < ContactResultsData.Items.Count; i++)
{
// Get a all list items from listbox
ListBoxItem ListBoxItemObj = (ListBoxItem)ContactResultsData.ItemContainerGenerator.ContainerFromItem(ContactResultsData.Items[i]);
// find a ContentPresenter of that list item.. [Call FindVisualChild Method]
ContentPresenter ContentPresenterObj = FindVisualChild<ContentPresenter>(ListBoxItemObj);
// call FindName on the DataTemplate of that ContentPresenter
DataTemplate DataTemplateObj = ContentPresenterObj.ContentTemplate;
CheckBox Chk = (CheckBox)DataTemplateObj.FindName("contactChk", ContentPresenterObj);
// get a selected checkbox items.
if (Chk.IsChecked == true)
{
MessageBox.Show(Chk.Content.ToString().Trim());
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
I got this method from google it looks fine but issue is that i am not getting "Findname" in this line,
CheckBox Chk = (CheckBox)DataTemplateObj.FindName("contactChk", ContentPresenterObj);
i also tried this one,
<ListBox x:Name="ContactResultsData" SelectionMode="Multiple" ItemsSource="{Binding listOfContacts}" Height="293" Margin="24,0,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="contactChk"
IsChecked={Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}},
Path=IsSelected}"
Foreground="Black" Background="Black" BorderBrush="White">
</CheckBox>
<TextBlock x:Name="ContactResultsName" Text="{Binding Name}" FontSize="50"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
On using this i am not getting these properties,
Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}
and properties i am getting are,
Self and TemplatedParent
Is there any alternative for adding contact in list. Well i am alerting on checkbox click,
private void contactChk_Checked(object sender, RoutedEventArgs e)
{
CheckBox chk2 = (CheckBox)sender;
MessageBox.Show("" + chk2.IsChecked);
count++;
}
perhaps i can add contact in list from this method
Hopes for your suggestion
Thanks
using Microsoft.Phone.UserData;
//Use this name space
FOllow the below //improvise a little bit
Contacts cons = new Contacts();
foreach(var c in con)
{
a.cnts.Add(new Contactss()
{
name=c.name,
number=c.phone
});
}
lstbxk.ItemsSource = a.cnts;
I need help to get Selected list view item details, when context menu assigned to list view items is clicked.
<ListView.Resources>
<ContextMenu x:Key="GvRowMenu" ItemsSource="{Binding ContextMenuItems}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding IconPath}"></Image>
<TextBlock Text="{Binding Name}"></TextBlock>
<MenuItem
Click="MenuItem_Click"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=DataContext.RunCommand}" />
This is a click event code
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
//what needs to de here?
}
I wrote this piece of code in my view model, but it doesnt trigger on execute method
RunCommand = new DelegateCommand<object>(OnRunCommand, CanRunCommand);
private void OnRunCommand(object obj)
{
// use the object here...
}
private bool CanRunCommand(object obj)
{
return true;
}
Let me know, how can I handle this situation. Any examples related to same will be appreciated.
Thanks
you are mixing you methods... you can run an event or you can use a command, but not so much both together.
what you want is to bind the command:
<MenuItem Command="{Binding DataContext.RunCommand}" />
there are many wonderfull sources of info out there... here is one.
Thanks..!
Well, below piece of code worked for me.
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem menuItem = (MenuItem)e.Source;
ContextMenu contextMenu = menuItem.CommandParameter as ContextMenu;
ListViewItem item = (ListViewItem)contextMenu.PlacementTarget;
var x = ((myViewModel)(item.Content)).myModel;
//'x' gives all required data of list view item
}
This is my XAML
<ListView.Resources>
<ContextMenu x:Key="GvRowMenu" ItemsSource="{Binding ContextMenuItems}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImagePath}"/>
<TextBlock Text="{Binding Name}"/>
<MenuItem Click="MenuItem_Click"
CommandParameter="{Binding
RelativeSource={RelativeSource
AncestorType={x:Type ContextMenu}}}"/>
</StackPanel>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListView.Resources>
I have 2 listboxes in my app that use
<Window.Resources>
<ItemsPanelTemplate x:Key="WrapPanelTemplate">
<WrapPanel Width="290"/>
</ItemsPanelTemplate>
<DataTemplate x:Key="ButtonItemTemplate">
<Button Content="{Binding Path=Name}" Width="120" Margin="3,2,3,2" />
</DataTemplate>
</Window.Resources>
Everything looks great but when I try to click on them they do not select a new item. I have SelectedItem bound to a property on my view-model but whenever I select a new item the set method does not happen. I have a regular listbox that is hooked up in the same way and does work. Here is the implementation of the custom listbox:
<ListBox Height="284" HorizontalAlignment="Left" x:Name="faveProgramsButtons"
ItemsSource="{Binding Path=FavoriteAppList}"
SelectedItem="{Binding Path=FavoriteAppList_SelectedApp}" VerticalAlignment="Top"
Width="281" ItemsPanel="{StaticResource WrapPanelTemplate}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemTemplate="{StaticResource ButtonItemTemplate}">
</ListBox>
Thanks!
The problem is that the Button is swallowing the mouse click so the ListBoxItem in the ListBox never receives it, hence it is never selected. If you want to be able to select the items when you click the Button you can try using a ToggleButton instead and bind IsChecked to IsSelected
<DataTemplate x:Key="ButtonItemTemplate">
<ToggleButton Content="{Binding Path=Name}" Width="120" Margin="3,2,3,2"
IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}},
Path=IsSelected,
Mode=TwoWay}"/>
</DataTemplate>
You could also achieve this with a little code behind or an attached behavior.
ButtonItemTemplate
<DataTemplate x:Key="ButtonItemTemplate">
<Button Content="{Binding Path=Name}" Width="120" Margin="3,2,3,2"
Click="TemplateButton_Click"/>
</DataTemplate>
Code Behind
private void TemplateButton_Click(object sender, RoutedEventArgs e)
{
Button clickedButton = sender as Button;
ListBoxItem listBoxItem = GetVisualParent<ListBoxItem>(clickedButton);
if (listBoxItem != null)
{
listBoxItem.IsSelected = true;
}
}
public static T GetVisualParent<T>(object childObject) where T : Visual
{
DependencyObject child = childObject as DependencyObject;
// iteratively traverse the visual tree
while ((child != null) && !(child is T))
{
child = VisualTreeHelper.GetParent(child);
}
return child as T;
}
I have the listBox and a ObservableCollection. The listBox.ItemSource (listNotify.ItemSource) is set to that ObservableCollection (errosList).
The problem that i have is that i don`t know how to remove the correct element from errorsList when the user click on the button with content x from listBox. For the item of the listBox i use a ItemTemplate, inside a stackPanel and in stackPanel i have a button.
Bellow is the XAML code:
<ListBox x:Name="listNotify">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="35">
<Image Height="16" Source="/Template;component/Resources/error.png" Stretch="Fill" VerticalAlignment="Top" Width="16"/>
<StackPanel Orientation="Vertical">
<HyperlinkButton Content="{Binding ErrorHeader}" HorizontalAlignment="Left" Height="16" Width="125"/>
<TextBlock Text="{Binding ErrorMessage}" HorizontalAlignment="Left" Width="405" d:LayoutOverrides="VerticalAlignment" />
</StackPanel>
<Button Content="x" Width="20" Height="20" Click="removeError_Click"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The code is from a silverlight 4 project.
Thanks.
private void removeError_Click(object sender, RoutedEventArgs e) {
FrameworkElement fe = sender as FrameworkElement;
if (null != fe) {
_observableCollection.Remove((YourType)fe.DataContext);
}
}
Should do what your looking for. Replace YourType with the type you declared in the ObservableCollectiion.
Don't you have an ID-like property in your Items of the errorsList-Collection? Then you could use the Tag-Property of the Button to archieve this:
<Button Content="x" Width="20" Height="20" Tag="{Binding ID}" Click="Button_Click" />
and in the click-event of the button:
string id = ((Button) sender).Tag.ToString();
var itemToRemove = errorsList.Where(x => x.ID == id).First();
errorsList.Remove(itemToRemove);
Hope that helps