microsoft / xaml-standard

XAML Standard : a set of principles that drive XAML dialect alignment
Other
804 stars 50 forks source link

All events in markup to also support an ICommand #140

Open mrlacey opened 7 years ago

mrlacey commented 7 years ago

Given a button:

   <Button x:Name="MyButton"
       Content="My Button"
       Click="MyButton_Click"
       Command="{Binding MyButtonCommand}" />

Why should I need separate properties for Click and Command? In this instance, they are both triggered by the same thing and so it feels like a duplication. It also adds more overhead for any other events I want to bind to a command, through the use of extensions to map the event to a command or the use of a gesture recognizer, etc.

In current platform markups that support binding to ICommands, they typically pick a single event and map that to a Command property. But why keep doing this? Why not allow any event to trigger a command on any/all controls?

So, for Click="MyButton_Click" the click event would call a method in code behind called MyButton_Click with the standard event signature (sender, eventArgs). and for Click="{Binding MyButtonCommand}" the click event would trigger the command called MyButtonCommand in the current DataContext.

For multiple events on a control all bound to commands, this would lead to much simpler markup. Consider this compared to current equivalents:

   <TextBox x:Name="EnteredUserName"
        Text="{Binding Path=Name, Mode=TwoWay}"
        PlaceholderText="Enter your name"
        GotFocus="{Binding GotFocusCommand}"
        TextChanged="{Binding NameChangedCommand}"
        KeyDown="{Binding KeyDownCommand}"
        LostFocus="{Binding LostFocusCommand}" />

This would make it easier to use commands with any event or multiple events on the same control. It would remove inconsistency over what triggers the Command property. It would still support backward compatibility and the ability to use code-behind if that's what someone really wanted.

Command properties could still be set as part of each binding and so we could remove the need to have CommandProperty properties directly on each control too.

Without deep knowledge of implementation codebases, this doesn't feel like it would require a massive change to XAML parsing to make possible. The code-behind equivalent of setting this either way might be more tricky.

I understand the historical reasons that have led us to have both Click and Command but this is a chance to make things simpler going forward, and without breaking backward compatibility.

insinfo commented 7 years ago

I did not understand exactly what you want, if I understand you'd like to delete the Click property and keep only the Commande property, if you can do a syntax demo before and after

If possible visit my posts to help in defining the model and syntax of these controls Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link, Visit this link,

Duranom commented 7 years ago

@mrlacey This is a nice thing for a designer and cleans up the Xaml as the core events are most times set to commands, for others you have to use the Xaml behaviors for now, it makes sense as an event with designing/designer are always in concept of Event Observe Command/React. (Something triggers, the object is the observed and you command execution).

However I think the code-behind implementation will be the biggest here, like how would this be allowed with compiled bindings#19 - Future milestone or a clean proper implementation in code-behind? Aside from that, should all type of event be supported or should it be possible to certain special events only? Like a command does not really sense like on event as ManipulationCompleted. Should the event arguments be supplied to the Command or nothing, and if it should be supplied what to do when there is an event that has more than one parameter (Seeing as they are delegates)

tibitoth commented 7 years ago

So it's like the UWP's x:Bind event to method binding. On that case I have a problem that in the ViewModel you need to have a dependency to the UI specific EventArgs if you want to get some data from the event. (eg. ItemClickedEventArgs.ClickedItems). Sadly with this dependency the ViewModel cannot be cross platform.

So what do you think how could you transform the event arguments to a cross platform command parametet?

mrlacey commented 7 years ago

@insinfo I'm not talking about getting rid of the Click event, I'm saying that for a Button it's basically a duplicate of the Command property and that this property is a special handler for the Click event as it makes it easy to wire it to an ICommand. As it's often needed to wire more events to ICommands and to remove the duplication, why not just allow events to be passed commands. This snippet Click="{Binding MyButtonCommand}" also from above shows, shows what I'm asking to be made possible. Also, all your links are unhelpful. They go to issues of varying subjects, with different levels of detail and relevance. Congrats on your enthusiasm and raising lots of issues but that list is basically just spam.

@Duranom & @totht91 Yes, while some events (and Manipulation related ones are a good example) are rarely used in a ViewModel (and therefore make sense as ICommands), it's easier to be absolute in a definition and say all events should support this rather than define a list of appropriate events for all controls. Just because it may be incredibly rare for an event to be bound to an ICommand doesn't mean it shouldn't be possible.

By maintaining support for traditional events and code-behind then access to the sender and platform specific event args is still possible if desired/needed. These could also be included as [part of] the CommandParameter if needed.

I would suggest not automatically wiring up the CommandParameter to receive the EventArgs. Let the CommandParameter be set as part of the binding so that it can be whatever the developer wants and to enable cross-platform support. This would be the same as the Command parameter currently in UWP. It doesn't get eventArgs by default.

I don't see a potential issue with compiled bindings and Event Binding. When adding them in future they would be a compliment to this. There's nothing in UWP event binding which is platform specific apart from the ability to x:Bind to an event handler name and I'm not advocating for that. And yes, that would throw up some cross platform issues.

insinfo commented 7 years ago

@mrlacey Thanks, and please excuse me for this, then I noticed that this looks like Span. I think I got a little too excited about my ideas.😄

SariDev commented 7 years ago

I like the idea of being able to bind any Event to a command.

Today I'm using interaction triggers in WPF when a Control doesn't offer a command binding. e.g. To be able to react on the SelectionChanged Event of the WPF TreeView in the VM.

The MVVM Light Framework uses it's own EventToCommand implementation to be able to pass EventArgs to the command. <i:Interaction.Triggers> <i:EventTrigger EventName="Loaded"> <cmd:EventToCommand Command="{Binding Mode=OneWay, Path=LoadedCommand}" PassEventArgsToCommand="True" /> </i:EventTrigger> </i:Interaction.Triggers>

More info about it here: http://blog.galasoft.ch/posts/2009/11/bug-correction-in-messenger-and-new-feature-in-eventtocommand-mvvm-light-toolkit-v3-alpha/

An simpler way (shorter syntax and no need for 3rd Party libraries) to bind any Event to a command + passing the EventArgs would be really nice from my point of view

birbilis commented 7 years ago

also related I think: (from https://mcnextpost.com/2015/11/10/uwpxaml-compiled-binding-what-is-it/)

{x:Bind} is also capable to bind event handlers to events.

With classic binding, this was only possible by using ICommand to bind ViewModel’s methods to a Button click. If you wanted to bind to an event with no corresponding built-in Command property, you had to use a behavior and Interactions library from Blend SDK, usually you had to use EventToCommand behavior from MVVM libraries like MVVMLight.

One important thing to note also is that while classic binding uses the property DataContext as a root source for evaluating binded paths, Compiled Binding on the other hand directly references the root control in which it is used. For example, when using compiled binding in a page like MainPage, {x:Bind HelloWorld} will reference MainPage.HelloWorld. A field, a property or a method named HelloWorld must exist on MainPage and must be public. This also works when using compiled binding in a UserControl

birbilis commented 7 years ago

@insinfo please edit your older posts to remove unneeded cross-references between items in the repo. Keep only references to other issues directly related to an issue if possible

birbilis commented 7 years ago

@SariDev btw, the link http://blog.galasoft.ch/posts/2009/11/bug-correction-in-messenger-and-new-feature-in-eventtocommand-mvvm-light-toolkit-v3-alpha/ above is broken (if you move the mouse over it at your post it should other url than the one in the text)