I created a ListBox with ListBoxItems and add an MouseDown event handler to each of the ListBoxItems. The ListBoxItems are shown, but when I click on a ListBoxItem, the Event doesn't get fired.
How i set the MouseUp:
TrackedProcessList.ItemsSource = null;
TrackedProcessList.ItemsSource = this.tracks;
/*... some other code that doesn't matter ... */
ListBoxItem[] items = new ListBoxItem[TrackedProcessList.Items.Count];
for (int i = 0; i < TrackedProcessList.Items.Count; i++)
{
Object obj = TrackedProcessList.Items.GetItemAt(i);
//TrackedProcessList.UpdateLayout();
ListBoxItem item = (ListBoxItem)(TrackedProcessList.ItemContainerGenerator.ContainerFromIndex(i));
if (item != null)
{
item.MouseUp += new MouseButtonEventHandler(ListBoxItem_MouseUp_PostQuestion);
items[i] = item;
}
}
The Method which should be called (but it isn't):
private void ListBoxItem_MouseUp_PostQuestion(object sender, EventArgs e)
{
MessageBox.Show("ListBoxItem_MouseUp_fired");
}
My XAML:
<ListBox x:Name="TrackedProcessList" Height="145" Width="605" ItemsSource="{Binding}" BorderThickness="1,0" IsSynchronizedWithCurrentItem="True">
<DataTemplate>
<TextBlock MouseDown="ListBoxItem_MouseUp_PostQuestion" Text="{Binding Path=programName}" HorizontalAlignment="Stretch" ></TextBlock>
</DataTemplate>
</ListBox>
Do you have any ideas where the failure could be? There is no error. The Event just seems to be not bound to the ListBoxItem.
It is because ListBoxItem already handles both left and right click which means your event handler will not be triggered according to WPF routed event rules. Your either have to assign PreviewMouseDown event or add event handler for handled events:
lbi.AddHandler(ListBoxItem.MouseDownEvent, new MouseButtonEventHandler(MouseEvent), true);
void OnListBox_Mouse_Down(object sender, MouseButtonEventArgs e)
{
e.Handled
}
void OnListBox_Mouse_Up(object sender, MouseButtonEventArgs e)
{
"Do Something";
}
Use the ContainedControl property and set your events :)
kryptonListBox1.ContainedControl.MouseDown += kryptonListBox1_MouseDown_1;
Related
With a regular ComboBox I would use the following code to deactivate the Selection Change.
<ComboBox Name="CbbTest" SelectionChanged="CbbTest_SelectionChanged"></ComboBox>
CbbTest.SelectionChanged -= new SelectionChangedEventHandler(CbbTest_SelectionChanged);
However, when my ComboBox is in a DataTemplate I am not able to access the ComboBox by name, and therefore I am not able to turn off the selection changed.
How can deactivate ComboBox CbbTestTwo like in the previous code, but from a DataTemplate in the following code?
<StackPanel>
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Name="CbbTestTwo" SelectionChanged="CbbTestTwo_SelectionChanged"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
Any help in this matter would be appreciated
If I understand correctly, you seek to be able to manipulate your combobox in the SelectionChanged event. You can get your combobox like this:
private void cbTest_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox comboBox = new ComboBox();
if(sender is ComboBox)
{
comboBox = (ComboBox)sender;
}
}
Can now handle it like that :
private void cbTest_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox comboBox = new ComboBox();
if(sender is ComboBox)
{
comboBox = (ComboBox)sender;
}
//Add the treatments you want
comboBox.Items.Clear();
comboBox.ItemsSource = listTest;
}
You might want to use more MVVM like approach which means subscribing directly on events in the code behind of the view is not the best option. In this case you could use a behavior like this.
public class ComboBoxSelectionChangedBehavior : Behavior<ComboBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectionChanged += OnSelectionChanged;
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// ....
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.SelectionChanged -= OnSelectionChanged;
}
}
And then you can attach this behavior through xaml. Here is a short tutorial on behaviors https://blog.jayway.com/2013/03/20/behaviors-in-wpf-introduction/
Find control inside Listbox.ItemTemplate (WPF C#)
Please refer this link, from the above code snippet, once you will have the combobox instance, you can unsubscribe the event.
Evening all, I've run into an issue with the SelectionChanged (TabControl) event being call before the LostFocus (TextBox) event.
This is a problem since the SelectionChanged is triggered during a tab change, that intern resets the ListView.SelectedIndex (TabControl>TabItem>ListView) to -1.
The textbox uses LostFocus to update/validate it's textbox.text which depend upon the SelectedIndex. The text in the textbox is stored/retrieved from a List<string> and because the index changed, the List happens to go out of bounds.
I've looked around, tired a few things also a "hack-y" approach which didn't really help.
<TabControl SelectionChanged="SelectionChanged_Tab"
<TabItem .../>
<TabItem .../>
</TabControl>
<Grid>
<Label .../>
<TextBox Name="Name" LostFocus="Lost_Focus" .../>
</Grid>
Code:
private void SelectionChanged_Tab(object sender, SelectionChangedEventArgs e)
{
if (e.Source is TabControl)
{
ListView1.SelectedIndex = -1;
ListView2.SelectedIndex = -1;
}
}
private void Lost_Focus(object sender, RoutedEventArgs e)
{
TextBox textbox = sender as TextBox;
int Index = ListView.SelectedIndex;
if (string.IsNullOrEmpty(textbox.Text) || textbox.Text == "0")
{
textbox.Text = "0";
}
switch (textbox.Name)
{
case "Name":
SomeList[Index].AProperty = textbox.Text;
break;
}
}
OK, so after think about the problem from a different perspective, I decided to simple make the TabControl, an Focus-able event and simple make it focus when selection changes:
<TabControl SelectionChanged="SelectionChanged_Tab" Focusable="True"
<TabItem .../>
<TabItem .../>
</TabControl>
Code:
private void SelectionChanged_Tab(object sender, SelectionChangedEventArgs e)
{
if (e.Source is TabControl)
{
ListView2.Focus();
ListView1.SelectedIndex = -1;
ListView2.SelectedIndex = -1;
}
if (ListView2.SelectedIndex == -1)
{
ListView1.Focus();
}
}
I know it's not the most elegant solution (In the process or re-factoring) but this seems to get the job done.
I would like some advice on drag and drop operations of listbox items. Each of my items has a ComboBox, TextBox, CheckBox and Button, as shown below.
I use my drag/drop to reorder these and it is almost working correctly.
The main issue is that a drag operation on an item is occurring when a PreviewMouseLeftButtonDown and PreviewMouseMove event happens on one of the controls noted above.
My question is given the code below what's good way I can prevent this drag occuring when one of the controls is clicked on?
XAML:
<DataTemplate DataType="{x:Type helpers:Filter}">
<Border>
<Border>
<Grid>
<ComboBox />
<TextBox />
<CheckBox />
<Button />
</Grid>
</Border>
</Border>
</DataTemplate>
<ListBox x:Name="FilterList"
ItemsSource="{Binding Filters}"
helpers:DragDropHelper.IsDragSource="true"
helpers:DragDropHelper.IsDropTarget="true" />
C#:
public static readonly DependencyProperty IsDragSourceProperty =
DependencyProperty.RegisterAttached("IsDragSource", typeof(bool), typeof(DragDropHelper), new UIPropertyMetadata(false, IsDragSourceChanged));
private void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.sourceItemsControl = (ItemsControl)sender;
Visual visual = e.OriginalSource as Visual;
this.topWindow = Window.GetWindow(this.sourceItemsControl);
this.initialMousePosition = e.GetPosition(this.topWindow);
this.sourceItemContainer = sourceItemsControl.ContainerFromElement(visual) as FrameworkElement;
if (this.sourceItemContainer != null)
{
this.draggedData = this.sourceItemContainer.DataContext;
}
}
// Drag = mouse down + move by a certain amount
private void DragSource_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (this.draggedData != null)
{
// Only drag when user moved the mouse by a reasonable amount.
if (Utilities.IsMovementBigEnough(this.initialMousePosition, e.GetPosition(this.topWindow)))
{
this.initialMouseOffset = this.initialMousePosition - this.sourceItemContainer.TranslatePoint(new Point(0, 0), this.topWindow);
DataObject data = new DataObject(this.format.Name, this.draggedData);
// Adding events to the window to make sure dragged adorner comes up when mouse is not over a drop target.
bool previousAllowDrop = this.topWindow.AllowDrop;
this.topWindow.AllowDrop = true;
this.topWindow.DragEnter += TopWindow_DragEnter;
this.topWindow.DragOver += TopWindow_DragOver;
this.topWindow.DragLeave += TopWindow_DragLeave;
DragDropEffects effects = DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move);
RemoveDraggedAdorner();
this.topWindow.AllowDrop = previousAllowDrop;
this.topWindow.DragEnter -= TopWindow_DragEnter;
this.topWindow.DragOver -= TopWindow_DragOver;
this.topWindow.DragLeave -= TopWindow_DragLeave;
this.draggedData = null;
}
}
}
I tend to initialise my Drag and Drop properties in a PreviewMouseDown event handler, but it's unwise to perform any other Drag and Drop operations in that handler, because the user might not be dragging... they might just have clicked.
Instead, it's better to handle the PreviewMouseMove event to initiate a Drag and Drop operation. Here is a simplified example:
private void DragSourcePreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
isMouseDown = true;
}
private void DragSourcePreviewMouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown && IsConfirmedDrag(e.GetPosition(sender as ListBox)))
{
isMouseDown = false;
...
DragDrop.DoDragDrop(dragSource, data, DragDropEffects);
}
}
It is in the PreviewMouseMove event handler that you could check which UI element has been clicked on and determine whether you start the Drag and Drop operation or not. Try something like this:
private void DragSourcePreviewMouseMove(object sender, MouseEventArgs e)
{
ListBox dragSourceControl = (ListBox)sender;
HitTestResult result = VisualTreeHelper.HitTest(dragSourceControl,
Mouse.GetPosition(dragSourceControl));
UIElement draggedUIElement = result.VisualHit.GetParentOfType<ListBoxItem>();
bool isViable = AddYourViabilityConditionHere(draggedUIElement);
if (isMouseDown && IsConfirmedDrag(e.GetPosition(sender as ListBox)) && isViable)
{
isMouseDown = false;
...
DragDrop.DoDragDrop(dragSource, data, DragDropEffects);
}
}
I have list of items in LongListMultiSelector - how to handle a selected item?
My LongListMultiSelector xaml:
<tkit:LongListMultiSelector Name="longlist" SelectionChanged="longlist_SelectionChanged">
<tkit:LongListMultiSelector.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" FontSize="32" Tap="TextBlock_Tap"/>
</DataTemplate>
</tkit:LongListMultiSelector.ItemTemplate>
</tkit:LongListMultiSelector>
TextBlock tap event handler code:
private void TextBlock_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
var itemTapped = (sender as FrameworkElement).DataContext as Book;
}
LongListMultiSelector SelectionChanged event handler code:
private void longlist_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
I found part of solution here, however, The problem if at least one item is selected, then textblockTap event doesn't handle - longlist_SelectionChanged event handles everything. How can i fix that?
Once you are using LongListMultiSelector, the SelectionChanged event is fired when item is added or removed. If you want to perform the action regardless item is added/removed, I've managed to do it like this (for a simle string):
private void longlist_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string selectedItem = String.Empty;
if (e.AddedItems.Count > 0) selectedItem = e.AddedItems[0] as string;
else selectedItem = e.RemovedItems[0] as string;
MessageBox.Show(selectedItem); // do your work
}
It should run while items are selected separately by tapping, but this method will have problems when more items are added/removed at the same time - if you need it, then you should handle this also.
Your XAML DataTemplate.
<DataTemplate x:Key="listItemTemplate">
<StackPanel Orientation="Horizontal" Margin="4,4">
<TextBlock Tap="textblockTap" Margin="0,-7,0,0" Text="{Binding Name}" Style="{StaticResource PhoneTextLargeStyle}"/>
</StackPanel>
</DataTemplate>
In your CS page;
private void textblockTap(object sender, EventArgs e)
{
var file = (TextBlock)sender;
var ContentFile = (string)file.Text;
MessageBox.Show(ContentFile);
}
This example will show you the text of the selected item in the MessageBox.
I have a SelectionChanged event in a ListPicker within one of my application Pages that fires multiple times before the page is loaded. This is really inconvenient for me as when an item is selected, a MessageBox is displayed (and other actions will be performed). The MessageBox is displayed twice every time the page is NavigatedTo. How can I fix this?
XAML
<toolkit:ListPicker x:Name="ThemeListPicker" Header="Theme"
ItemTemplate="{StaticResource PickerItemTemplate}"
SelectionChanged="ThemeListPicker_SelectionChanged"/>
XAML.CS
private void ThemeListPicker_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
if(ThemeListPicker.SelectedIndex != -1)
{
var theme = (sender as ListPicker).SelectedItem;
if (index == 0)
{
Settings.LightTheme.Value = true;
MessageBox.Show("light");
}
else
{
Settings.LightTheme.Value = false;
MessageBox.Show("dark");
}
}
}
well, that's how a listpicker behaves, what best you can do is instead of making ThemeListPicker_SelectionChanged make a parent stackpanel inside the datatemplate somewhat like this
<Listpicker.ItemTemplate>
<DataTemplate x:Name="PickerItemTemplate">
<StackPanel tap="stk_Tap">
<TextBlock/>
</StackPanel>
</DataTemplate>
</Listpicker.ItemTemplate>
<Listpicker.FullModeItemTemplate>
<DataTemplate x:Name="PickerFullModeItemTemplate">
<StackPanel tap="stk_Tap">
<TextBlock/>
</StackPanel>
</DataTemplate>
<Listpicker.FullModeItemTemplate>
now use this tap stk_Tap to do your action as, this event would also get called every time the selection changed gets called but, it wont exhibit the buggy behavior like that of selection changed event.
hope this helps.
Attach the SelectionChanged event after the ListPicker is Loaded.
...
InitializeComponent();
YourListPicker.Loaded += YourListPicker_Loaded;
...
private void YourListPicker_Loaded(object sender, RoutedEventArgs e)
{
YourListPicker.SelectionChanged += YourListPicker_SelectionChanged;
}