0

I'm writing some app in WPF using mvvm pattern (so no code-behind). I have an ObservableCollection myCol. Objects are added dynamically into it (say by clicking on some button) The MyClass object contain a WritableBitmap mySource, that I'm using to draw an image.

I want to catch mouse down events on the items of myCol. My problem is that I need to have the item, on which the event was invoked and the position of the event - so two args. I'm using myConverter to pass both of the arguments. And that's my problem - I don't know how to pass the MouseButtonEventArgs to the multi converter.

Any solutions?

code in xaml:

<ItemsControl ItemsSource="{Binding myCol}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Image Source="{Binding mySource}">
                        <b:Interaction.Triggers>
                            <b:EventTrigger EventName="MouseDown">
                                <b:InvokeCommandAction Command="{Binding DataContext.MouseDownCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}">
                                    <b:InvokeCommandAction.CommandParameter>
                                        <MultiBinding Converter="{StaticResource MyConverter}">
                                            <Binding />
                                            <!-- THE LINE BELOW HAS TO BE CHANGED -->
                                            <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}"/>
                                        </MultiBinding>
                                    </b:InvokeCommandAction.CommandParameter>
                                </b:InvokeCommandAction>
                            </b:EventTrigger>
                        </b:Interaction.Triggers>
                    </Image>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

and the Convert fun from myConverter:

 public object Convert(object[] values, Type target_Type, object parameter, CultureInfo culture)
        {
                var myClass = (MyClass)values[0];
                var args = (MouseButtonEventArgs)values[1];  // THAT I WANT

                return new Tuple<MyClass, MouseButtonEventArgs>(myClass, args);
        }
vela18
  • 37
  • 5
  • 1
    Why do we constantly see this "*using mvvm pattern (so no code-behind)*" stuff? That is a big misconception. MVVM does not at all mean that there must not be any code behind. – Clemens Feb 24 '23 at 10:45
  • @Clemens I can very easily achieve what I need in xaml.cs. In your opinion is that ok in my case? – vela18 Feb 24 '23 at 11:00
  • 1
    Yes of course. Code behind is totally ok, especially when a XAML-based solution would be a lot more complicated. Forget what people tell you about "no code behind". That is not what MVVM is about. – Clemens Feb 24 '23 at 11:03
  • 1
    It isn't entirely pointless avoiding or minimising code behind. Code in viewmodels is more unit test friendly. Academic if you're not writing unit tests. – Andy Feb 24 '23 at 15:57
  • @Andy Your comment somehow implies that it is fine to move code-behind code to a view model class. Code-behind is always view related, that's why it is a code-behind file. It's a partial class of a .xaml file. It always contains pure view code, for example a Button.Click handler that invokes view model code. There is nothing to move to a view model class in order to empty the code-behind file of a view. It's healthy to accept that code-behind a.k.a. partial class is not bad at all (and especially not MVVM related). XAML first is also a good paradigm (but for other reasons than MVVM of course). – BionicCode Feb 24 '23 at 19:01
  • @Andy Like "code-behind is bad", too many believe that moving code to the view model (for example dialog handling) is a valid solution in order to keep the code-behind file empty - and *that* is a clear violation of MVVM. So we should be careful with your kind of suggestions or implications. – BionicCode Feb 24 '23 at 19:01
  • 1
    I think we should be careful not to misinterpret and completely misrepresent someone else's statements @bioniccode It really is difficult to impossible to unit test code behind. Meaning that you're unlikely to cover that code in code behind with unit tests. If you want to assume that's a reference to someone wearing army boots then that's your problem. – Andy Feb 24 '23 at 19:21
  • @Andy Sure. You wrote that minimizing code-behind is not pointless. Then relate to view model code is more unit test friendly. This somehow implies that minimizing code-behind by moving to the view model is good because it produces unit test friendly code. Not sure how else your unit test statement makes sense in this context. Or are these two completely unrelated sentences: a discussion about naming conventions: *"C# uses pascal casing for class members. Code in viewmodels is more unit test friendly."*? Then this would be funny how you drop the unit testing info in this unrelated context. – BionicCode Feb 24 '23 at 19:46
  • @Andy However, it doesn't matter. You may meant something different, but your comment could be understand that way. It's *exactly* what many use to do. That was not meant as an offense. Just highlighting that moving code from code-behind to view model classes is a violation of MVVM. The Army boots part is what we would call polemic, right? – BionicCode Feb 24 '23 at 19:56
  • So why can't you use a `ListBox` instead of `ItemsControl`? – XAMlMAX Feb 24 '23 at 23:02
  • @XAMlMAX You can. ListBox is essentially an ItemsControl with extra functionality i.e. item selection, a virtualizing stack panel etc. – Mark Feldman Feb 25 '23 at 04:57
  • @XAMlMAX and would it solve my problem? – vela18 Feb 25 '23 at 16:14
  • `ListBox` would help with `SelectedItem`. As your ItemsSource creates all those templates it also creates all those event to command bindings. I would possibly create a ViewModel to accomodate coords of the image. Oh and I hope the `mySource` is a byte array otherwise this is not MvvM. You would know if you were to test your code. But I worry more about the requirement you showed us here. Click on specific area of an image and then send that into command? Is that like a colour picker of sorts? – XAMlMAX Feb 25 '23 at 22:02
  • @XAMlMAX mySource is a WritableBitmap. – vela18 Feb 26 '23 at 11:26
  • It's not a color picker - I need to pass these values to unmamaged code. that's why I need the mouse position and also the object on which the event occurred. – vela18 Feb 26 '23 at 11:27
  • and for now I solved this problem as follows: ```" and inside the command I'm checking the mouse coords by calling ```Mouse.GetPosition(null)```. Not what I wanted exactly, but it seems that it's not trivial to pass the object and the event args – vela18 Feb 26 '23 at 11:30
  • Hm, I see your predicament. Have you tried using Gestures? On the image? Something like [this](https://stackoverflow.com/a/12668443/2029607) – XAMlMAX Feb 27 '23 at 10:34
  • 1
    @XAMlMAX No, I didn't, but this: https://stackoverflow.com/questions/66465149/pass-extra-argument-to-command-with-invokecommandaction solved my problem. Thx for trying! – vela18 Mar 10 '23 at 01:09

0 Answers0