简体   繁体   English

在 ListBoxItem DataTemplate 内的嵌套控件中处理相同的单击事件 - WPF

[英]Handling the same click event in a nested control inside ListBoxItem DataTemplate - WPF

When we have a custom listbox with a defined event-handling for the left-click of the mouse, and also an additional shape inside the ListBoxItem data template which needs to do some action when it is clicked how can we handle these当我们有一个自定义列表框,定义了鼠标左键单击的事件处理,还有 ListBoxItem 数据模板中的一个附加形状,当它被点击时需要做一些动作,我们如何处理这些

I have a Custom ListBox witch tries to handle the Click event :我有一个自定义列表框女巫试图处理 Click 事件:

In the ContentView:在内容视图中:

                <ABC:AListBox
                    ClickCommand="{Binding LaunchCommand}"
                    ...>
                </ABC:AListBox>

In it's datatemplate we have this:在它的数据模板中,我们有这个:

        <DataTemplate x:Key="ThisListTemplate">
            <StackPanel ...>
                <Border Grid.Column="1" VerticalAlignment="Center">
                    <TextBlock
                        FontSize="15"
                        Foreground="White"
                        Text="{Binding Path=ItemTitle}" />      
                </Border>
                <Canvas Height ="12" Width ="12" >
                  <Ellipse Name = "TheEllipse" Stroke="Black" Height ="12"                                  
                           Width ="12" Cursor="Hand" Canvas.Left="185" Canvas.Top="12">                          
                  </Ellipse>
                    <Ellipse.InputBindings>
                        <MouseBinding Gesture="LeftClick"
                                      Command="{Binding DataContext.LaunchFromXamlCommand , RelativeSource={RelativeSource AncestorType=ABC:AListBox}}"
                                      CommandParameter="{Binding}" />
                    </Ellipse.InputBindings>                      
                </Canvas> 
            </StackPanel>                   
        </DataTemplate>

And in the MVVM as our data context we have:在 MVVM 作为我们的数据上下文中,我们有:

    public ICommand LaunchCommand { get; private set; }
    public DelegateCommand<object> LaunchFromXamlCommand { get; private set; }

    // Initialization on load:

    this.LaunchCommand = new DelegateCommand(this.LaunchRun);
    this.LaunchFromXamlCommand = new DelegateCommand<object>(this.LaunchFromXamlRun);


    //---------     
    private void LaunchFromXamlRun(object param)
    {
            TheListItem app = (TheListItem)param;   
    ...
    }   

    private void LaunchRun()
    { ... }

Here I used 2 different commands LaunchCommand as an ICommand in addition with LaunchFromXamlCommand which is called via the template.在这里,除了通过模板调用的 LaunchFromXamlCommand 之外,我还使用了 2 个不同的命令 LaunchCommand 作为 ICommand。

The LaunchFromXamlRun will get triggered fine and as expected. LaunchFromXamlRun将按预期正常触发。 But also as it can be guessed there will be 2 raised events and 2 commands getting triggered which I want to omit one and ignore the general ListBox event handler when that shape is get hit.但也可以猜到,将会有 2 个引发的事件和 2 个被触发的命令,我想省略一个,并在该形状被击中时忽略一般的 ListBox 事件处理程序。

What can be the best solution for doing this?这样做的最佳解决方案是什么?

FYI: (Maybe not so important just for a note) The App is using earlier versions of Prism (don't think that matters here) and has a modular code, everything is separated in different assemblies and the code is using MVVM pattern.仅供参考:(也许不那么重要只是为了说明)该应用程序使用的是早期版本的 Prism(不要认为这在这里很重要)并且具有模块化代码,所有内容都在不同的程序集中分开,并且代码使用 MVVM 模式。

I wish we had something like e.handled = true in a mechanism that could be used in the given scenario.我希望我们在一个可以在给定场景中使用的机制中有类似e.handled = true东西。

Your problem is exacerbated by having that click handler in your listbox.在您的列表框中使用该点击处理程序会加剧您的问题。 I don't know how you're doing that but that cannot just be click.我不知道你是怎么做到的,但这不能只是点击。 It's probably previewmousedown.它可能是 previewmousedown。 Because, of course, a listbox "eats" mousedown as part of selecting an item.因为,当然,列表框“吃掉”鼠标作为选择项目的一部分。

One way round this involves not using that listbox previewmousedown.解决此问题的一种方法是不使用该列表框 previewmousedown。 Here I put my row content inside a button and bind the button's command.在这里,我将我的行内容放在一个按钮中并绑定按钮的命令。 It doesn't look like a button of course.当然,它看起来不像一个按钮。

I make the circle into a button and give it a transparent fill so you can click on all of it.我把圆圈做成一个按钮,并给它一个透明的填充,这样你就可以点击所有的东西。

    <ListBox ItemsSource="{Binding People}">
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Button  Command="{Binding DataContext.ItemClickCommand, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
                         CommandParameter="{Binding}"
                         >
                    <Button.Template>
                        <ControlTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding LastName}"/>
                                <Button Command="{Binding DataContext.EllipseCommand, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
                                >
                                    <Button.Template>
                                        <ControlTemplate>
                                            <Ellipse Name = "TheEllipse" Stroke="Black" 
                                         Fill="Transparent"
                                         Height ="12"                                  
                                         Width="12" Cursor="Hand">
                                            </Ellipse>
                                        </ControlTemplate>
                                    </Button.Template>
                                </Button>

                            </StackPanel>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

My viewmodel uses relaycommands but (obviously) any implementation of ICommand would do.我的视图模型使用中继命令,但(显然)ICommand 的任何实现都可以。 I had People from the last question I did some work on.我有上一个问题的人,我做了一些工作。

public class MainWindowViewModel : BaseViewModel
{
    private RelayCommand ellipseCommand;
    public RelayCommand EllipseCommand
    {
        get
        {
            return ellipseCommand
            ?? (ellipseCommand = new RelayCommand(
              () =>
             {
                 Console.WriteLine("CIRCLE clicked");
             }
             ));
        }
    }
    private RelayCommand<Person> itemClickCommand;
    public RelayCommand<Person> ItemClickCommand
    {
        get
        {
            return itemClickCommand
            ?? (itemClickCommand = new RelayCommand<Person>(
              (person) =>
              {
                  Console.WriteLine($"You clicked {person.LastName}");
                  person.IsSelected = true;
              }
             ));
        }
    }
    private ObservableCollection<Person> people = new ObservableCollection<Person>();

    public ObservableCollection<Person> People
    {
        get { return people; }
        set { people = value; }
    }

    public ListCollectionView LCV { get; set; }
    public MainWindowViewModel()
    {
        People.Add(new Person { FirstName = "Chesney", LastName = "Brown" });
        People.Add(new Person { FirstName = "Gary", LastName = "Windass" });
        People.Add(new Person { FirstName = "Liz", LastName = "McDonald" });
        People.Add(new Person { FirstName = "Carla", LastName = "Connor" });
    }
}

When you click that outer button it will grab the click.当你点击那个外部按钮时,它会抓住点击。 Which is why I set IsSelected in the command so the item you click becomes selected via binding.这就是为什么我在命令中设置 IsSelected 以便您单击的项目通过绑定被选中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM