I have a Listbox filled with Buttons. When the buttons is clicked then a new Page shows. But i wanna have the selected index of the listbox when i click on the button. But the listboxitem is never selected. Is there a way to get the index where the button lies by clicking the button. Thanks for help.
Example code
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<Button Click="ViewDetail_Click" Content="{Binding Path=Area}"></Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The data context of the button will contain the source data item corresponding to the list item. You've not shown what your ItemsSource is for the list, so I can't show exactly what code you'd need. But something like this:
ObservableCollection<MyDataItem> items = new ObservableCollection<MyDataItem>();
...
myList.ItemsSource = items;
...
private void ViewDetail_Click(object sender, RoutedEventArgs e)
{
Button b = (Button) sender;
MyDataItem detailItem = (MyDataItem) b.DataContext;
int itemIndex = items.IndexOf(detailItem);
}
Of course, if the reason you're asking for the index in the first place is because you want to get hold of the corresponding data item, you don't actually need the index at all - the item's already right there in the data context.
By the way, I wouldn't use a ListBox here. The main thing ListBox brings to the party is selection, but by putting buttons in as the items, you're defeating that - as you've already discovered, the button is handling the mouse input before the list box has a chance to, meaning that you can't actually select the items. At which point, why have a ListBox? A base ItemsControl probably makes more sense. (Wrapped in a ScrollViewer if you need scrolling.)
Related
I have an ItemsControl displaying a list via binding. The list is of a ViewModel type which is then referenced in a DataTemplate to display a button. The button has it's UID bound to a GUID from the the view model. When a new view model is added to the bound list, I need to get hold of the button that will be added, as the buttons need to be able to be dragged/dropped by the user. At the moment the closest I can get is finding the ContentPresenter that displays the button, but the content of that ContentPresenter is of type view model.
Is there a way to find the button that has been added? Or should I not used a DataTemplate and create the buttons my self in order to access them?
I have used the VisualTree helper to get the content presenter, but have not managed to find the button.
You could handle the Loaded event for the Button:
<DataTemplate>
<Button Loaded="OnButtonLoaded" ... />
private void OnButtonLoaded(object sender, RoutedEventArgs e)
{
Button button = (Button)sender;
//...
}
You won't be able to get a reference to it using the VisualTreeHelper until it has actually been added to the visual tree and loaded anyway.
I seem to have conflicting requirements. I have a DataGrid that has a checkbox as the first column. The users want the checkbox to be selectable with a single click, not a double click. I was able to make that happen by using a DataGridTemplateColumn and a checkbox like this:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The user also a control that allows them to specify a row (there can be hundreds of rows). If they specify a row that isn't in view I want it to scroll into view. I compromised and added an event handler in the code behind for the DataGrid_SelectionChanged event. Originally I was just using the ScrollIntoView command but offscreen rows would get highlighted but the grid did not scroll them into view. I was then able to add a Focus command and the row scrolled into view. So now the event handler looks like this:
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataGrid dg = (DataGrid)sender;
if (dg.SelectedItem == null) return;
dg.ScrollIntoView(dg.SelectedItem);
dg.SelectedItem.Focus();
}
Now I'm back to the original problem, the row scrolls into view but to check the checkbox on any other row (that you don't move into via the jump to row control) you have to click twice. Anybody know what is causing the rows moved to manually to require double clicks?
Well I got it to work with the following code which was inspired by some tangentially related posts on getting the focus into cells. I have no clue as to why ScrollIntoView doesn't work, working or why performing the last three lines was the one way I could get the row to scroll into view without disabling the checkbox.
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataGrid dg = (DataGrid)sender;
if (dg.SelectedItem == null) return;
dg.ScrollIntoView(dg.SelectedItem);
DataGridRow dg_row = (DataGridRow)dg.ItemContainerGenerator.ContainerFromItem(dg.SelectedItem);
if (dg_row == null) return;
dg_row.Focus();
}
I have a ListBox that is used as a navigation menu. When an item is selected, it has a state that is highlighted. I have now implemented a message box when navigating away from a page if there are unsaved changes. The problem is, the visual state of the ListBoxItem is changed to selected upon click. I need to be able to change set the state to selected from code, instead of on click.
Is there a way to override the click event so that it doesn't cause the ListBoxItem to go to the selected state? I could then do VisualStateManager.GoToState(item, "Selected", true).
If not, is there a way to create a custom visual state for the ListBoxItem?
You should interrupt routing of MouseLeftButtonDown event from your item container and set selected item from view model. For instance:
XAML
<ListBox x:Name="lb">
<ListBoxItem>
<TextBlock MouseLeftButtonDown="TextBlock_OnMouseLeftButtonDown" Text="Test"/>
</ListBoxItem>
</ListBox>
Event Handler
private void TextBlock_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//interrups item selection
e.Handled = true;
//here you can show "Do you want navigate from?" dialog
// and if user accepts then show selected item in menu using SelectedItem or SelectedIndex
lb.SelectedIndex = 0;
}
I have a WPF Window with a datagrid dgSample. it has been bound to a list lstSample like this:
dgSample.itemssource=lstSample;
this datagrid also has a radio button column wherein i select one row by clicking on the radio button, and then, i can move to the next page after i click on the next button. On the next page, there is again the same datagrid, with the same radiobutton column. What I want is, that when i reach this page, i want the radio button that was selected in the previous page to be selected here as well.
I have tried binding the radiobutton column with an IsSelected Property by doing:
IsChecked="{Binding Path IsSelected, Mode=TwoWay}"
but this is not working.
What can I do to make it work?
P.S.: I prefer code-behind solution than the xaml one.
Please help !
Your model needs to implement INotifyPropertyChanged and call
PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"))
to get it to update in another view.
NB: If you set
public event PropertyChangedEventHandler PropertyChanged = delegate { };
you won't have to check for null.
I had an ItemsControl, which you could use page up/down buttons to scroll expectedly. I switched it with a ListBox, to apply (thru triggers) a new DataTemplate when an item is selected.
Everything works fine, until using pageup or pagedown buttons. Instead of scrolling one page, it scrolls till the end or the beginning.
My previous attemps:
Not changing the item height when DataTemplate changes
Removed IsSelected=True trigger completely
All SelectionMode values
Do I miss something trivial?
private void RaiseKeyDownUpEventsOnEntitiesBox(Key key)
{
KeyEventArgs keyEventArgs = new KeyEventArgs(
InputManager.Current.PrimaryKeyboardDevice,
Keyboard.PrimaryDevice.ActiveSource,
System.Environment.ProcessorCount, key);
keyEventArgs.RoutedEvent = UIElement.KeyDownEvent;
entitiesBox.RaiseEvent(keyEventArgs);
keyEventArgs.RoutedEvent = UIElement.KeyUpEvent;
entitiesBox.RaiseEvent(keyEventArgs);
}
Page Down
RaiseKeyDownUpEventsOnEntitiesBox(Key.Next);
Page Up
RaiseKeyDownUpEventsOnEntitiesBox(Key.Prior);
Indeed, I missed something trivial. I forgot to remove the ScrollViewer outside the ItemsControl. I guess, this creates a confusion, since ListBox has its own ScrollViewer.
This raised another question. Previous ScrollViewer were automaticcally scrolled down from code behind. Now, that I can't reach the ListBox's ScrollViewer, I can't call its LineDown method. Here is my workaround:
// Responses is the ItemsSource
Responses.Add(e);
// xResponses is the ListBox
var item = xResponses.ItemContainerGenerator.ContainerFromIndex(0);
ScrollBar.LineDownCommand.Execute(null, item as IInputElement);
In the beginning, item might evaluate to null, however this does not create a problem. After adding a few items, luckily before we need to scroll, a container is returned successfully. Note that index is not important here, all we need is an IInputElement inside the ScrollViewer.