JordanMarr / ReactiveElmish.Avalonia

Static Avalonia views for Elmish programs
Other
92 stars 8 forks source link

DOC request - how to wire up DoubleTapped for a listbox #4

Closed daz10000 closed 1 year ago

daz10000 commented 1 year ago

Sorry - scoured docs and doc strings and the Elmish.WPF examples but couldn't make this work. I will update the sample to include a working example if you don't mind pointing out what I'm doing wrong here.

The listbox has the DoubleTapped attribute. I just can't work out which binding style to use on the elmish side

<ListBox Items="{Binding Items}" SelectionMode="Single" 
                    DoubleTapped="{Binding DoubleTapped}"
                    SelectedIndex="{Binding SelectedIndex}">
            </ListBox.Styles>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border Background="gray" CornerRadius="4" Padding="5,0,5,0" BorderBrush="red" Margin="0">
                        <StackPanel Orientation="Horizontal" >
                            <TextBlock Width = "200" VerticalAlignment="Center" Text="{Binding Name}" />
                            <TextBlock Padding="5" Text="{Binding Count}"/>
                        </StackPanel>
                    </Border>
                </DataTemplate> 
            </ListBox.ItemTemplate>
        </ListBox>

Just mapping it onto a message fails

"DoubleTapped" |> Binding.cmd (fun m-> DoubleTapped) ' with error message. I'm obviously not using the right type of binding here, but I have tried most of them at this point :(

  GslGalleryView.axaml(19, 21): [AVLN:0004] Unable to find suitable setter or adder for property DoubleTapped of type Avalonia.Base:Avalonia.Input.InputElement for argument Avalonia.Markup:Avalonia.Data.Binding, available setter parameter lists are:
System.EventHandler`1<Avalonia.Input.TappedEventArgs> Line 19, position 21.

Separately, if you have interest, I wanted to contribute working examples of each control as I get them running with Elmish.Avalonia - probably jsut extending the sample I just submitted. It could evolve into a gallery of examples and would be a good reference, as each new control is a small learning curve at the moment and working code is sometimes the best doc.

JordanMarr commented 1 year ago

That's because DoubleTapped is a routed event whereas something like Button Command is a property that can be bound. You definitely can't bind events the same way as properties.

JordanMarr commented 1 year ago

You will have to either have to handle it as an event in the code behind or you might be able to use a library like this to shim the event to make it bindable MVVM style: https://github.com/AvaloniaUI/Avalonia.Xaml.Behaviors

(Adding control samples is a great idea, btw.)

JordanMarr commented 1 year ago

It looks like you can also use this library as well to bind an event: https://github.com/Serg046/EventBinder

Note that for Avalonia, you need to open the xmlns “EventBinder.Avalonia”

daz10000 commented 1 year ago

Thanks for the research and suggestions. Still on the steep end of the learning curve. For the code behind, and eventbinder solutions, I was struggling with how to get back into the elmish event loop. After picking some very bleeding edge, previewy libs for eventbinder, I can get it to wire up but it fails because it's still trying to call a method on my class. I really want to just inject an event ultimately into the elmish queue. I might be missing something simple here.

The behavior route on the other hand worked beautifully and (for me) is fairly intuitive, and keeps the logic inside the xaml which is nice

I just had to drop this into the ListBox itself

<i:Interaction.Behaviors>
                <EventTriggerBehavior EventName="DoubleTapped" SourceObject="{Binding ElementName=listbox}">
                    <Interactions:InvokeCommandAction Command="{Binding DoubleTapped}"/>
                </EventTriggerBehavior>
            </i:Interaction.Behaviors>

A couple of things into the header

xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
             xmlns:Interactions="using:Avalonia.Xaml.Interactions.Core"

and add <PackageReference Include="Avalonia.Xaml.Behaviors" Version="$(AvaloniaVersion)" / to the project and voila!

As promised, I'm going to try to add some examples to the sample project and send them over. It's kind of my notes of working bits of code. I don't know about you, but I find the most productive space is having things that work I can just copy. Best form of documentation, and happy to pay that back

image

JordanMarr commented 1 year ago

The Interaction.Behaviors is the route I would take as well. Very nice to be able to stay within the view.

daz10000 commented 1 year ago

This all works - again thanks for the help - and as a way to say thanks, I sent a PR with a working demo