There are similar questions, but as I will explain, their answers do not seem to work for me.
I have a Listbox with an ItemsSource feeding it data...
<ListBox Name="lbPatternResults" SelectionMode="Multiple">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Get current values" Click="GetCurrentValuesForID"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
The ItemsSource property is set elsewhere to an IEnumerable.
When clicking the menuitem, the sender is the MenuItem, and its parent is the ContextMenu. Usually, to get the ListBoxItem, people are told to use the context menu's PlacementTarget, but in my case it's not a ListBoxItem... it's the ListBox. How do I get from here? I just want the index or the value of the row in the list...
EDIT: It's not the SelectedIndex of the ListBox (There can be one selected index, and one other that you get the menu from).
This works fine for me:
<ListBox>
<ListBox.Resources>
<ContextMenu x:Key="MyContextmenu">
<MenuItem Click="MenuItem_OnClick"
Header="Test" />
</ContextMenu>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu"
Value="{DynamicResource MyContextmenu}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBoxItem Content="A" />
<ListBoxItem Content="B" />
<ListBoxItem Content="C" />
<ListBoxItem Content="D" />
<ListBoxItem Content="E" />
</ListBox>
and code-behind:
private void MenuItem_OnClick(object sender, RoutedEventArgs e) {
var menuItem = (sender as MenuItem);
if (menuItem == null)
return;
var parentMenu = menuItem.Parent as ContextMenu;
if (parentMenu == null)
return;
var lbItem = parentMenu.PlacementTarget as ListBoxItem;
if (lbItem != null)
MessageBox.Show((string)lbItem.Content);
}
Related
I am working in Visual Studio 2013 in WPF (C#) and I have the following code to create an expander from my xml. It is currently working perfectly right now but I want to include an expand all and collapse all buttons. I have looked all over and can't seem to find a solution.
Here is where the expander is created. I know I just have to iterate through a list of items and change the Property="IsExpanded" to Value="True" to create an expand all.
<DataTemplate x:Key="dtListTemplate" >
<StackPanel>
<Expander LostFocus="CollapseExpander" ExpandDirection="Down" Width="Auto">
<Expander.Style>
<Style TargetType="Expander">
<Setter Property="IsExpanded" Value="False" />
<Setter Property="Header" Value="{Binding XPath=#Name}" />
<Setter Property="FontWeight" Value="Bold"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpanded,RelativeSource={RelativeSource Self}}" Value="True">
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<ListBox Name="itemsList"
ItemsSource="{Binding XPath=UpgradeAction}"
ItemTemplate="{StaticResource dtListItemTemplate}"
SelectionChanged="listItems_SelectionChanged"
Style="{StaticResource styleListBoxUpgradeAction}"
ItemContainerStyle="{StaticResource styleListBoxItemUpgradeAction}">
</ListBox>
</Expander>
</StackPanel>
</DataTemplate>
Here's the code that calls the DataTemplate which has information from an Xml.
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Border Grid.Column="0" Grid.Row="0" Width="790" Height="40" Padding="5" Background="#4E87D4">
<Label VerticalAlignment="Center" FontSize="16" FontWeight="Bold" Foreground="White">Test</Label>
</Border>
<Button Name="ExpandBttn" Width="100" Height="40" FontSize="16" FontWeight="Bold" Content="Expand All" DataContext="{Binding}" Click="Expand_Button_Click"/>
<Button Name="ColapseBttn" Width="100" Height="40" FontSize="16" FontWeight="Bold" Content="Colapse All" DataContext="{Binding}" Click="Collapse_Button_Click"/>
</StackPanel>
<ListView Name="listItems" Grid.Column="0" Grid.Row="1" Background="Wheat"
ItemsSource="{Binding Source={StaticResource xmldpUpgradeActions}, XPath=ActionGroup}"
ItemTemplate="{StaticResource dtListTemplateRichards}"
SelectionChanged="listItems_SelectionChanged">
</ListView>
</StackPanel>
Here's what I tried in the .cs file for the expand all portion.
private void Expand_Button_Click(object sender, RoutedEventArgs e)
{
foreach(var item in listItems.Items)
{
var listBoxItem = listItems.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
var itemExpander = (Expander)GetExpander(listBoxItem);
if (itemExpander != null)
itemExpander.IsExpanded = true;
}
}
private static DependencyObject GetExpander(DependencyObject container)
{
if (container is Expander) return container;
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(container); i++)
{
var child = VisualTreeHelper.GetChild(container, i);
var result = GetExpander(child);
if (result != null)
{
return result;
}
}
return null;
}
Any help is greatly appreciated!
Is xmldpUpgradeActions a CollectionViewSource?
Whatever class is in the collection, it should implement INotifyPropertyChanged.
Give it an IsExpanded property that raises PropertyChanged in its setter when its value changes, and bind that to Expander.IsExpanded in the template:
<Expander
IsExpanded="{Binding IsExpanded}"
LostFocus="CollapseExpander"
ExpandDirection="Down"
Width="Auto">
Write a command that loops through all the items in the collection and sets item.IsExpanded = false; on each one.
I have a problem regarding the state of a menuitem in ContextMenu. I have a ObversableCollection of Cars. The cars are visualized in a ListBox, for each ListBox Item I want a ContextMenu. In that ContextMenu there is an option ReserveCar.
They problem I'm having is that the CanExecute of the Car is only executed once when I right click any car. They CanExecute will not be called anymore after that when I right click an other Car.
This causes that when I rightclick a Car which can be Reserved, the MenuItem is active, but when I then rightclick another which I should not be able to reserve the MenuItem remains active (because CanExecute is not called again).
<ListBox
ItemsSource="{Binding Cars}"
SelectedItem="{Binding SelectedCar}">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Reserve Car"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}"
Command="{Binding ReserveCarCommand}">
<MenuItem.Icon>
<Image Source="{StaticResource ReserveCarIcon}" Width="24" Height="24"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
My ViewModel:
private RelayCommand<Car> _reserveCarCommand;
public ICommand ReserveCarCommand
{
get { return _reserveCarCommand ?? (_reserveCarCommand = new RelayCommanReserveCar, CanReserveCar)); }
}
public bool CanReserveCar(Car car)
{
return !car.IsReserved && ReservationsAreOpen;
}
public void ReserveCar(Car car)
{
car.IsReserved = true;
}
Also when I manually refresh the Command when doing something, the CanExecute is called with a null as parameter, so thats not working either.
if (_reserveCarCommand != null) _reserveCarCommand .RaiseCanExecuteChanged();
Try binding the context menu on ListBoxItem instead of ListBox. As binding of context menu for ListBox happen only at the fist right click so CanExectute will not fire after first right click.
<ListBox Name="simpleListBox"
ItemsSource="{Binding Cars}"
SelectedItem="{Binding SelectedCar}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
...
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I use the Following Code for Bind the values in Multiple select Listbox with Check box in silverlight
<ListBox x:Name="ValListBox" Margin="188,212,136,100" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}" Content="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I need to get the selected item text using c#?
By Using the Following Method We can get the Selected Item in multiselect Listbox.
Changes in xaml: We need to add Click Function.
<ListBox x:Name="ValListBox" Margin="188,212,136,100" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Click="CheckBox_Click" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}" Content="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In Code Behind We can get like,
List<string> selecteditems = new List<string>();
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
var cb = sender as CheckBox;
if (cb.IsChecked == true)
{
var item = cb.DataContext;
selecteditems.Add(item.ToString());
}
else
{
var item = cb.DataContext;
selecteditems.Remove(item.ToString());
}
}
In selecteditems List we can get the all selected items from Multiple Listbox
I have three check boxes Namely, Document Submission,Document Pickup and Others. I made this three check Boxes Mutually Exclusive to each other as Below
<Grid Height="303" Width="500">
<ListBox Name="ListBox1" Margin="49,67,86,164">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Resources>
<SolidColorBrush
x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="White"/>
</Style.Resources>
</Style>
</ListBox.Resources>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Background="White" IsItemsHost="True"
Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox FontWeight="Bold" FontSize="13" IsThreeState="True" IsChecked="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBoxItem}}}" Content="{Binding}" BorderThickness="1" AllowDrop="False" Focusable="True" Background="White" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
List Box is Bind on Window loaded as Follows
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<string> lst = new List<string>();
lst.Add("Documnet Pickup");
lst.Add("Document Submission");
lst.Add("Others");
ListBox1.ItemsSource = lst;
}
How can i make one check box is checked on window loaded. Is this a best approach?.
Since you're binding checkbox IsChecked property to listbox item IsSelected property here :
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBoxItem}}}"
You can simply set listbox selected index to index of an item, for example, the first item :
List<string> lst = new List<string>();
lst.Add("Documnet Pickup");
lst.Add("Document Submission");
lst.Add("Others");
ListBox1.ItemsSource = lst;
ListBox1.SelectedIndex = 0;
then the respective item will automatically has checkbox checked.
Try adding the last line to your function. It makes the first checkbox checked.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<string> lst = new List<string>();
lst.Add("Documnet Pickup");
lst.Add("Document Submission");
lst.Add("Others");
ListBox1.ItemsSource = lst;
ListBox1.Items[0].Selected = true;
}
I have multiple Listviews each binded with their own itemsource. But i only have 1 Selected Item.
So for example i have 5 listboxes (Monday, Tuesday, ...) each of them with their own itemssource (MondayList, TuesdayList, ...). Each of these Listviews SelectedItem property is binded to The Property 'CurrentToDo'.
The problem is that if i select one in the Monday and then select one in Tuesday they are both selected.
So only one item should be able to be selected throughout all the listviews, please help.
<UserControl.Resources>
<Style x:Key="ListViewItemStyleToDo" TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
<GridView x:Key="ViewBase1" x:Shared="False" >
<GridViewColumn Header="" Width="30">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Subject" Width="auto" DisplayMemberBinding="{Binding Subject}" />
</GridView>
</UserControl.Resources>
<ListView Grid.Row="1" ItemsSource="{Binding MondayList}" SelectedItem="{Binding CurrentToDo, Mode=TwoWay}" SelectionMode="Single" ItemContainerStyle="{DynamicResource ListViewItemStyleToDo}" View="{DynamicResource ViewBase1}" />
<ListView Grid.Row="3" ItemsSource="{Binding TuesdayList}" SelectedItem="{Binding CurrentToDo,Mode=TwoWay}" SelectionMode="Single" ItemContainerStyle="{DynamicResource ListViewItemStyleToDo}" View="{DynamicResource ViewBase1}" />
Property:
private ToDoMod _currentToDo;
public ToDoMod CurrentToDo
{
get { return _currentToDo; }
set
{
_currentToDo= value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("CurrentToDo"));
}
}
Here is the answer:
Just bind to SelectedValue instead of SelectedItem.
You'd need to add 5 more properties: MondayCurrentToDo, TuesdayCurrentToDo...
Bind each list view's SelectedItem to the respective property.
In setter of each property, update CurrentToDo and remove selection of other lists - so it will look like this:
private ToDoMod _mondayCurrentToDo;
public ToDoMod MondayCurrentToDo
{
get { return _mondayCurrentToDo; }
set
{
_mondayCurrentToDo= value;
CurrentToDo = _mondayCurrentToDo;
_tuesdayCurrentToDo = null;
//TODO: add null setters for all other _<dayOfWeek>CurrentToDo members
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("MondayCurrentToDo"));
PropertyChanged(this, new PropertyChangedEventArgs("TuesdayCurrentToDo"));
//TODO: add notificaitons for all other <DayOfWeek>CurrentToDo properties
}
}
}
Of course, refactor this into methods, etc...