Style target behaviors MAUI

658 Views Asked by At

I want to create styled editor for my current page. I use it few times so i decide to wrote style for this element and wondering how to use Behaviors inside style. If i do this like regular way, everything is working fine

<Editor Style="{StaticResource TestEditor}"/>
<Editor.Behaviors>
<toolkit:EventToCommandBehavior 
                        EventName="Unfocused"
                        Command="{Binding Source={x:Reference TestEditorPage}, Path=BindingContext.UnfocusedCommand}"
                       CommandParameter="{Binding .}">
                        
                    </toolkit:EventToCommandBehavior>

</Editor.Behaviors>
</Editor>

So how to do the same but in my style if it is possible:

 <Style x:Key="TestEditor"
           TargetType="Editor">

        <Setter Property="AutoSize" Value="TextChanges"/>
        <Setter Property="Grid.Column" Value="1"/>
        <Setter Property="Placeholder" Value="Enter question answer"/>
        <Setter Property="Text" Value="{Binding Source={RelativeSource AncestorType={x:Type models:TestAnswerResponce}}, Path=Answer}"/>

        <Setter Property="Behaviors">

            <!-- Behavior -->
            
        </Setter>           
        
    </Style>
1

There are 1 best solutions below

9
Liqun Shen-MSFT On BEST ANSWER

However, creating a style that sets the Behaviors property of a control is not possible because the property is read-only. The solution is to add an attached property to the behavior class that controls adding and removing the behavior.

As a workaround, you could set the value of attach property to EventToCommandBehavior. Try the following code:

First, create a behaviour class in which adds an attached property.

public class MyEditorStyleBehavior : Behavior<Editor>
{
    public static readonly BindableProperty AttachBehaviorProperty =
            BindableProperty.CreateAttached("AttachBehavior", typeof(object), typeof(MyEditorStyleBehavior), null,propertyChanged: OnAttachBehaviorChanged);

    public static object GetAttachBehavior(BindableObject view)
    {
        return (object)view.GetValue(AttachBehaviorProperty);
    }

    public static void SetAttachBehavior(BindableObject view, object value)
    {
        view.SetValue(AttachBehaviorProperty, value);
    }

    static void OnAttachBehaviorChanged(BindableObject view, object oldValue, object newValue)
    {
        Editor editor = view as Editor;
        if (editor == null)
        {
            return;
        }

        EventToCommandBehavior attachBehavior = newValue as EventToCommandBehavior;
        editor.Behaviors.Add(attachBehavior);
    }
}

And in xaml, consume the behaviour.

This is my xaml:

<ContentPage.Resources>

<Style x:Key="TestEditor" TargetType="Editor">

   <Setter Property="AutoSize" Value="TextChanges"/>

   <Setter Property="Placeholder" Value="Enter question answer"/>
   <Setter Property="Text" Value="{Binding MyEditorText}"/>

    <Setter Property="local:MyEditorStyleBehavior.AttachBehavior">
        <Setter.Value>
            <toolkit:EventToCommandBehavior  EventName="Unfocused" 
               Command="{Binding Source={x:Reference TestEditorPage}, Path=BindingContext.UnfocusedCommand}"
               />
        </Setter.Value>
    </Setter>
</ContentPage.Resources>

<ScrollView>
    <VerticalStackLayout
        Spacing="25"
        Padding="30,0"
        VerticalOptions="Center">

        <Editor x:Name="myeditor" Style="{StaticResource TestEditor}"/>

        <Editor x:Name="myeditor1" Style="{StaticResource TestEditor}"/>

    </VerticalStackLayout>
</ScrollView>

In code behind .cs file, don't forget to set the bindingContext for the page.

public MainPage()
{
    InitializeComponent();
    this.BindingContext = new MainPageViewModel();
}

In ViewModel, I define the UnfocusedCommand and MyEditorText property. And each time editor lose focus (tap the entry below it), the command will fire.

public string MyEditorText { get; set; }

public Command UnfocusedCommand
{
    get
    {
        return new Command(() =>
        {
            Console.WriteLine("12345");
        });
    }
}

public MainPageViewModel()
{
    MyEditorText = "MyEditorText";
}

Hope it works.