AvaloniaUI / Avalonia.Xaml.Behaviors

Port of Windows UWP Xaml Behaviors for Avalonia Xaml.
MIT License
372 stars 42 forks source link

Add IfElseBehavior #166

Open izaksuilov opened 1 month ago

izaksuilov commented 1 month ago

I suggest adding new IfElseBehavior.

Why do we need this? For examlpe, I have a "State" property (which is enum, for example), depending on which I want to perform different actions.

Now I need to write it like this:

 <i:Interaction.Behaviors>
    <!--Unknown-->
    <ia:DataTriggerBehavior Binding = "{Binding State}" Value="{x:Static uisdk:UILineState.Unknown}">
        // do smth
    </ia:DataTriggerBehavior>

    <!--Ready-->
    <ia:DataTriggerBehavior Binding = "{Binding State}" Value="{x:Static uisdk:UILineState.Ready}">
        // do smth
    </ia:DataTriggerBehavior>

    <!--Passing-->
    <ia:DataTriggerBehavior Binding = "{Binding State}" Value="{x:Static uisdk:UILineState.Passing}">
        // do smth
    </ia:DataTriggerBehavior>

    <!--Passed-->
    <ia:DataTriggerBehavior Binding = "{Binding State}" Value="{x:Static uisdk:UILineState.Passed}">
        // do smth
    </ia:DataTriggerBehavior>

    <!--Stopped-->
    <ia:DataTriggerBehavior Binding = "{Binding State}" Value="{x:Static uisdk:UILineState.Stopped}">
        // do smth
    </ia:DataTriggerBehavior>

    <!--Aborted-->
    <ia:DataTriggerBehavior Binding = "{Binding State}" Value="{x:Static uisdk:UILineState.Aborted}">
        // do smth
    </ia:DataTriggerBehavior>
 </i:Interaction.Behaviors>

What's the problem? The problem is:

  1. We create a binding for each DataTriggerBehavior (that is a lot if you have many bindings in usercontrols). So every time Binding changes, each DataTriggerBehavior's compare method executes and spends a lot of resources
  2. This behavior is not like if-else statement, so the logic is different.

What I suggest I suggest adding new IfElseBehavior.

  1. You can bind the property you want to observe ONE time, so it saves the resources
  2. You can write if-else-like statements for your xaml logic
  3. This actions can be nested within each other
  4. You can put usual IAction inside If-Else action

Example of usage

Usual if-elseif-esle

<bh:Interaction.Behaviors>
  <bh:IfElseBehavior Binding="{Binding LineViewModel.State}">
    <!--Ready-->
    <bh:IfAction Value="{x:Static uisdk:UILineState.Ready}">
      // do smth
    </bh:IfAction>

    <!--Passing-->
    <bh:ElseIfAction Value="{x:Static uisdk:UILineState.Passing}">
      // do smth
    </bh:ElseIfAction>

    <!--Passed-->
    <bh:ElseIfAction Value="{x:Static uisdk:UILineState.Passed}">
      // do smth
    </bh:ElseIfAction>

    <!--Stopped-->
    <bh:ElseIfAction Value="{x:Static uisdk:UILineState.Stopped}">
      // do smth
    </bh:ElseIfAction>

    <!--Aborted-->
    <bh:ElseIfAction Value="{x:Static uisdk:UILineState.Aborted}">
      // do smth
    </bh:ElseIfAction>

    <!--Unknown-->
    <bh:ElseIfAction Value="{x:Static uisdk:UILineState.Unknown}">
      // do smth
    </bh:ElseIfAction>

    <bh:ElseAction>
      // do smth
    </bh:ElseIfAction>
  </bh:IfElseBehavior>
</bh:Interaction.Behaviors>

Nested if-else actions:

<bh:Interaction.Behaviors>
  <bh:IfElseBehavior>
    <!--Has runtime error-->
    <bh:IfAction Binding="{Binding HasErrorRuntime}" Value="{x:True}">
      // do smth
    </bh:IfAction>

    <!--Has configuration error-->
    <bh:ElseIfAction Binding="{Binding HasErrorConfig}" Value="{x:True}">
      // do smth
    </bh:ElseIfAction>

    <!--If there are no errors, then check the status -->
    <bh:ElseAction Binding="{Binding State}">
      <!--Waiting-->
      <bh:IfAction Value="{x:Static uisdkenum:UIProcedureState.Waiting}">
        // do smth
      </bh:IfAction>

      <!--Running-->
      <bh:ElseIfAction Value="{x:Static uisdkenum:UIProcedureState.Running}">

        <!--Running and pause-->
        <bh:IfAction Binding="{Binding IsPaused}" Value="{x:True}">
          // do smth
        </bh:IfAction>

        <!--Running and breakpoint-->
        <bh:ElseIfAction Binding="{Binding IsAtBreakpoint}" Value="{x:True}">
          // do smth
        </bh:ElseIfAction>

        <!--Running no pause and no breakpoint-->
        <bh:ElseAction>
          // do smth
        </bh:ElseAction>
      </bh:ElseIfAction>

      <!--Done-->
      <bh:ElseIfAction Value="{x:Static uisdkenum:UIProcedureState.Done}">
        // do smth
      </bh:ElseIfAction>

      <!--Stopped-->
      <bh:ElseIfAction Value="{x:Static uisdkenum:UIProcedureState.Stopped}">
        // do smth
      </bh:ElseIfAction>

      <!--Aborted-->
      <bh:ElseIfAction Value="{x:Static uisdkenum:UIProcedureState.Aborted}">
        // do smth
      </bh:ElseIfAction>

    </bh:ElseAction>
  </bh:IfElseBehavior>
</bh:Interaction.Behaviors>
izaksuilov commented 1 month ago

I have suggested this behavior in this PR