相关文章推荐
鬼畜的枕头  ·  Visual Studio 2017 ...·  8 月前    · 
买醉的蟠桃  ·  jquery ...·  1 年前    · 
私奔的青椒  ·  How to Enable All ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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

I have a Custom ListBox witch tries to handle the Click event :

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:

    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.

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?

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.

I wish we had something like e.handled = true in a mechanism that could be used in the given scenario.

You could perhaps switch to event handling instead of command binding and then use e.Handled to block its propagation if that is acceptable. Alternatively, you can (assuming the ellipse command is routed first) raise a flag in LaunchFromXamlRun() and in LaunchRun() if it is raised, do nothing and reset the flag. – o_weisman Apr 21, 2019 at 9:35 Thought about event scenario and also about a Boolean flag, but as I was away from this type of development for a while didn't know exactly how can achieve the desired result, in another hand wanted to hear advice on it with hope to find the best way. if you provide both of your approaches as working scenarios would be appreciated and will mark it as the answer. Thanks. – Kasrak Apr 21, 2019 at 9:42 About the 2nd approach how can we handle the flag? where should it be stored that we be sure with every unique call it be false, and after the first hit we change it to true? If that be in our ViewModel as our DataContext's property can we be sure about this behavior? – Kasrak Apr 21, 2019 at 9:45 TBH I haven't used Prism, so can't be sure, but doesn't the ellipse inherit its data context from the list box? – o_weisman Apr 21, 2019 at 9:51 Guess true, all the project should be using same DataContext :ContentViewModel. Prism shouldn't change so much things here, heard and read earlier that its DelegateCommand is similar to RelayCommand of another MVVM framework and it implements ICommand - may be helps - – Kasrak Apr 21, 2019 at 10:16

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>

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
            return ellipseCommand
            ?? (ellipseCommand = new RelayCommand(
                 Console.WriteLine("CIRCLE clicked");
    private RelayCommand<Person> itemClickCommand;
    public RelayCommand<Person> ItemClickCommand
            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.

Sorry for the delay, was too busy these days, will back to the topic tomorrow. But 2 things to mention: – Kasrak Apr 22, 2019 at 17:51 1. I forgot to mention earlier there is osmething that may answer one of your doubts and questions, as it is a custom listbox, I handled the left click of the mouse within the control definition, if needed let me know to post that code also. – Kasrak Apr 22, 2019 at 17:52 2. Should we change the ListItem into buttons? Is it recommendation or just an idea? If possible I like to keep the original given controls if not there is no problem for these changes. – Kasrak Apr 22, 2019 at 17:55 +1 and Thanks again, as I want to give a detailed and proper response this delay seems to be reasonable, so pardon me. – Kasrak Apr 22, 2019 at 17:56 As I mentioned, left click is associated with the row selection mechanism of a listbox. The markup I posted works. At least within my understanding of your aims. You might be able to find an alternative but of course you'll have to change something from your original. Good luck with that. – Andy Apr 22, 2019 at 18:11

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.