how to bind input key to itemscontrol in wpf - wpf

I have an items control which has items on a canvas, when I press delete I want to delete an item from the canvas:
<ItemsControl.InputBindings>
<KeyBinding Command="{Binding DeleteItemCommand}" Key="Delete"/>
</ItemsControl.InputBindings>
However, the method in DeleteItemCommand is never called.
How can I achieve this?

The ItemsControl (or possibly something within) needs to be Focusable to receive keyboard input.

Related

Combobox Text property not changing in user control

I have a list box that has a list of user controls. Each user control has 5 combo boxes. I want to be able to read the selected text of each combo box in each user control from the main application. However, when I change the selection in the combo box, the text property of the combo box in the user control doesn't change when I read it in the main application.
Code-behind:
radQueryParamList.Items.Add(new TCardQueryParameters());
Xaml (This is just a data template for how to display a TCardQueryParameters object):
<DataTemplate x:Key="TCardViewQueryParamDataTemplate">
<tcardqueryparam:TCardQueryParameters x:Name="TCardViewerParamUC" />
</DataTemplate>
<telerik:RadListBox Grid.Column="1" ItemTemplate="{StaticResource TCardViewQueryParamDataTemplate}" Name="radQueryParamList" VerticalAlignment="Top" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3">
Where I loop over the list of user controls
string test = radTESTGACC.Text;//TEST combo box, Text property changes
//radQueryParamList is a listbox of user controls where TCardQueryParameters is the UC
foreach(TCardQueryParameters param in radQueryParamList.Items)
{
//Each UC has a radGACC combo box in it, and I am reading what the user
//selected for each user control here in the main app, but the text property
//never changes
String gacc = param.radGACC.Text; //Text property DOESN'T CHANGE
}
I thought that each instance of the user control would keep its own state and I would just be able to read what the user selected for that combo box, but that doesn't seem to be the case.
You have not bound the SelectedItem, SelectedValue, or SelectedIndex property of your internal ComboBox to anything so it maintains its selection.
An ItemTemplate is like a cookie cutter. It contains the definition of the object, but not the object itself. Properties specific to the object's state are lost unless they are bound to something on the DataContext behind the template.
This is important to note for two aspects.
First off, to improve performance WPF usually unloads items which are not visible, which often results in items being re-created from their template anytime they are reloaded. An example would be when you minimize an application to the taskbar, then maximize it again. This is usually better on performance and memory usage, however it does mean you have to be sure you store the state of items that were created with a Template somewhere.
And second, by default ListBoxes use something called virtualization. A simple way of explaining this would be this:
Suppose you have a ListBox of 100,000 items. In your ListBox, only 10 items can be visible at a time. WPF will render roughly 14 items (the 10 visible ones, and then a few extra for a scroll buffer so you don't see anything unusual while scrolling). When you scroll to new items, WPF just re-uses the existing items that are already rendered, and just replaces the DataContext behind those items.
As you can guess, it is far better on performance to render 14 UI items instead of 100k items.
So to answer your question, you will probably want to bind either SelectedItem, SelectedValue, or SelectedIndex of your TCardQueryParameters UserControl to a property on the DataContext (which in your case appears to be another different UserControl).
It should probably be noted that what you are essentially doing is creating a list of UserControls, assigning them to the ListBox, and then telling the ListBox that it should draw each UserControl with another separate UserControl. So although you are changing the SelectedItem in the template UserControl, that change is not being reflected to your ListBox.Items copy of the UserControl.
I'm guessing you probably don't want that, so would recommend removing your ItemTemplate completely.
Or better yet, create a new class object containing all the data for your UserControl, and adding that to your ListBox.Items. Then tell the ListBox to draw that item using a TCardQueryParameters UserControl as the ItemTemplate, like you have now.

Loading more items when scrollbar scrolled to the end in ListView(WPF)

I want to implement a function that using a ListView to load items, but the number of items are very large, so I want when the user scroll the scrollbar to the end of the ListView, it auto load more items. I have found a solution to detect if the scroll is scrolled to the end here: Detect when WPF listview scrollbar is at the bottom? But in MVVM, I didn't find a solution to pass EventArgs. Is there any other solutions?
My Xaml looks like this:
<ScrollViewer>
<ListView>
...
</ListView>
</ScrollViewer>
Thanks!
You could have your View execute an ICommand Property on your ViewModel and take advantage of the CommandParameter parameter of the Execute method. However, I would warn that passing the state of your View to the ViewModel so that the ViewModel can determine which items to load is not an appropriate MVVM pattern. Generally, the ViewModel needs to drive the show, even if that includes offloading some UI state information from the View to the ViewModel so that it can natively deduce what to load.
If you use MVVMLight in your WPF project, just set PassEventArgsToCommand true.
eg:
xmlns:ni="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:mv="http://www.galasoft.ch/mvvmlight"
<ni:Interaction.Triggers>
<ni:EventTrigger EventName="SelectionChanged">
<mv:EventToCommand Command="{Binding YourCommand}" PassEventArgsToCommand="True" />
</ni:EventTrigger>

WPF bind a control visibility to the focused property of another control

I have a combobox that displays a list of items, and I want to place a button next to it which triggers a command to see the details of the selected item. So far, so good. Now I want the button to be visible only if the combobox has focus (or is in "edit" mode, but not only when the popup is open).
I thought I could bind the visibility of the button to some focus property of the combobox, something like this:
<Button Content="Details" Visibility="{Binding ElementName=elementListComboBox,
Path=IsFocused, Converter={StaticResource Bool2VisibilityConverter}}"/>
But I found no way to know if the control I want is focused or not. I looked at the FocusManager.FocusedElement, but I don't know how to get the focused control I want inside the binding. Is there a way to achieve this in XAML?
Ok, the way to get this working as I wanted is this:
<Button Command="{Binding SomeCommand}"
Content="Details"
Focusable="False"
Visibility="{Binding ElementName=elementListComboBox,
Path=IsKeyboardFocusWithin,
Converter={StaticResource Bool2VisibilityConverter}}"/>
Two key factors here: bind the button's visibility to IsKeyboardFocusWithin property of the combobox, and set the button's Focusable property to false, else it will get collapsed when you want to click on it.
Hope this is useful.

Up/down key bindings not recognized

I have a textbox and a listbox. The listbox shows search suggestions for the textbox.
I want to highlight the first listbox item when user presses down arrow when the textbox is focused.
Similarly, the textbox should be focused back when the user is as the first element on the listbox and presses the up arrow.
I am using the following code for KeyBindings:
<KeyBinding Key="Down" Command="{x:Static local:SearchView.ApplicationShortCutsCommand}" CommandParameter="{x:Static common:SearchViewCommands.MoveToSuggestions}" />
<KeyBinding Key="Up" Command="{x:Static local:SearchView.ApplicationShortCutsCommand}" CommandParameter="{x:Static common:SearchViewCommands.MoveToQuery}" />
Other keys such as Esc and Enter work fine, although this one doesn't work at all (the associated event isn't fired).
Any suggestions?
The events associated with ListBox up and down have priority.
I ended up using shift up/down instead because there are so many event consumers that use the up and down events.

WPF - databinding label on listbox ismouseover

I'm still new to WPF, and I'm trying to do something that's beyond my knowledge at the moment.
I have a listbox databinded to the source collection, and a label. I'd like to bind the label's Content value to the listbox's item over which is mouse hovered.
Say I have DataTemplate binded to the class MenuItem:
<DataTemplate DataType="{x:Type local:MenuItem}" x:Key="MenuListTemplate">
Which has member Text. I want my Label to display Text from element which is mouse overed in list. I have the IsMouseOver trigger for my textbox, but have no idea how to bind Label.Content to it.
Any tips?
I don't think that binding can achieve your goal with ease. I think it's easier to do with routed events.
Subscribe to the MouseMove event at the ListBox level. Check if the source of the event is a ListBoxItem, and if it is use this item to update the label.

Resources