在ListBoxItem DataTemplate内部的嵌套控件中处理相同的click事件-WPF [英] Handling the same click event in a nested control inside ListBoxItem DataTemplate - WPF
问题描述
当我们有一个带有为鼠标左键定义的事件处理的自定义列表框,并且ListBoxItem数据模板内还有一个附加形状时,单击它时需要采取一些措施,我们如何处理这些
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
我有一个自定义ListBox女巫试图处理Click事件:
I have a Custom ListBox witch tries to handle the Click event :
在ContentView中:
<ABC:AListBox
ClickCommand="{Binding LaunchCommand}"
...>
</ABC:AListBox>
在数据模板中,我们有以下内容:
<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>
在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()
{ ... }
在这里,除了通过模板调用的LaunchFromXamlCommand之外,我还使用了2个不同的命令LaunchCommand作为ICommand。
Here I used 2 different commands LaunchCommand as an ICommand in addition with LaunchFromXamlCommand which is called via the template.
LaunchFromXamlRun
将被正常触发。
但是也可以猜到会有2个引发事件和2个命令被触发,我想忽略其中一个,而在击中该形状时忽略常规ListBox事件处理程序。
The LaunchFromXamlRun
will get triggered fine and as expected.
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.
什么是最好的解决方案?
What can be the best solution for doing this?
仅供参考: (也许不那么重要 该应用程序使用的是Prism的早期版本(此处不重要),并且具有模块化代码,所有内容均以不同的程序集分隔,并且代码使用MVVM模式。
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.
我希望我们在一种可用于给定场景的机制中拥有类似 e.handled = true
的东西。
I wish we had something like e.handled = true
in a mechanism that could be used in the given scenario.
推荐答案
通过在列表框中使用该单击处理程序,您的问题会更加严重。我不知道您的操作方式,但是不能仅仅单击一下。可能是previewmousedown。因为,当然,在选择项目时,列表框会吃掉鼠标。
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. Because, of course, a listbox "eats" mousedown as part of selecting an item.
一种解决方法是不使用该列表框预览鼠标。在这里,我将行内容放在按钮内,并绑定按钮的命令。
One way round this involves not using that listbox 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>
我的视图模型使用中继命令,但是(显然)任何ICommand实现都可以。我有上一个问题的人,我做了一些工作。
My viewmodel uses relaycommands but (obviously) any implementation of ICommand would do. 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" });
}
}
当您单击该外部按钮时,它将抓住该单击。这就是为什么我在命令中设置IsSelected以便您单击的项目通过绑定而被选中的原因。
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.
这篇关于在ListBoxItem DataTemplate内部的嵌套控件中处理相同的click事件-WPF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!