wpflistboxlistboxitem

WPF How to select need 'DoubleClick' control like button


In some situation. I need to select DoubleClick control like button. And it fill the ListBoxItem. I couldn't set IsHitTestVisible = "false" cause I need to DoubleClick it.

Code like:

<ListBox>
    <Button Width="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=ActualWidth}" />
</ListBox>

What the best way to handle it? better in MVVM.
PS: Select item by clicking item.

I have tried to set 'e.Handled = false;' in click event, let it go to the selector. But it didn't work.


Solution

  • I found a way that could let item be selected and do somethings in 'Double Click' .

    1.

    First, the item need set 'IsHitTestVisible="False"' .

    Second, we write a 'MouseDoubleClick' in 'Listbox' and item. And we find the item in 'ListboxMouseDoubleClick' to trigger item 'MouseDoubleClick'.

    In xaml

    <ListBox  MouseDoubleClick="ListboxDoubleClick">
        <TextBlock Text="Try Select Need Double Click item"/>
        <Button Background="Red" MouseDoubleClick="BtnInListBoxDoubleClick" IsHitTestVisible="False" Width="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=ActualWidth}" Height="20" />
    </ListBox>
    

    MouseDoubleClick:

            private void BtnInListBoxDoubleClick(object sender, MouseButtonEventArgs e)
            {
                MessageBox.Show("This is BtnInListBoxDoubleClick!");
            }
    
            private void ListboxDoubleClick(object sender, MouseButtonEventArgs e)
            {
                DependencyObject originalSource = e.OriginalSource as DependencyObject;
    
                var btn = FindControlHelper.FindChild<Button>(originalSource) as Button;
    
                if (btn == null)
                    return;
    
                var mouseEventArgs = new MouseButtonEventArgs
                     (Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left)
                {
                    RoutedEvent = Button.MouseDoubleClickEvent,
                    Source = btn
                };
                btn.RaiseEvent(mouseEventArgs);
            }
    

    FindChild function:

    public static T? FindChild<T>(DependencyObject dependencyObject, string? name = null)
        where T : FrameworkElement
    {
        DependencyObject? child = null;
        T? grandChild = null;
    
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
        {
            child = VisualTreeHelper.GetChild(dependencyObject, i);
    
            if (child is T && (((T)child).Name == name | string.IsNullOrEmpty(name)))
            {
                return (T)child;
            }
            else
            {
                grandChild = FindChild<T>(child, name);
                if (grandChild != null)
                    return grandChild;
            }
        }
    
        return null;
    }
    

    So the point is set your item 'IsHitTestVisible="False"' so that item could be selected, then find the item in 'ListBox' 's 'DoubleClickEvent'.

    2 .

    And by the way , if you could find the item that mean you could find the item's 'DataContext'. So you don't need to operate directly control in View.

    like:

               var listboxitem = FindControlHelper.FindParent<ListBoxItem>(originalSource) as ListBoxItem;
    
               if (listboxitem == null)
                   return;
               var datacontext = listboxitem.DataContext as Student;
    

    FindParent function:

            public static T? FindParent<T>(DependencyObject dependencyObject, string? name = null)
                where T : FrameworkElement
            {
                var parent = VisualTreeHelper.GetParent(dependencyObject);
    
                while (parent != null)
                {
                    if (parent is T && (((T)parent).Name == name | string.IsNullOrEmpty(name)))
                    {
                        return (T)parent;
                    }
                    parent = VisualTreeHelper.GetParent(parent);
                }
                return null;
            }