Avalonia: привязка свойства команды к UserControl - PullRequest
0 голосов
/ 30 апреля 2020

Итак, я создал пользовательский элемент управления кнопками, назовем его MyButton, используя Avalonia. MyButton представляет собой набор из нескольких элементов управления, включая Avalonia.Controls.Button, который выглядит следующим образом (MyButton.xaml):

<Border xmlns="https://github.com/avaloniaui"
        .....
        x:Class="myProject.myControls.MyButton">
  <Button x:Name="button"
          Background="Transparent"
          ....
          BorderThickness="0">
    <Panel >
      .....
    </Panel>
  </Button>
</Border>

(Да, мой пользовательский элемент управления наследуется от Avalonia.Controls.Border вместо Avalonia.Controls.UserControl)

Мой план состоит в том, чтобы передать свойство Command кнопок (свойство с атрибутом x:Name="button") дальше и сделать его доступным через MyButton.

Поэтому, когда я хочу использовать MyButton в MainWindow.xaml я мог бы сделать следующее:

<Window ... >
   <Design.DataContext>
        <vm:MainWindowViewModel/>
   </Design.DataContext>
   <myControls:MyButton Command="{Binding MyButton_Click}"/>
</Window>

, где модель вида MainWindowViewModel.cs выглядит так:

public partial class MainWindowViewModel : ViewModelBase
{
    public void MyButton_Click()
    {
         // do stuff...
    }
}

Способ, которым я пытался сделать это в MyButton.xaml.cs можно следующим образом:

public class MyButton : Border
{
    private readonly Button button;

    public MyButton()
    {
        InitializeComponent();
        button = this.FindControl<Button>("button");
    }

    private void InitializeComponent()
    {
        AvaloniaXamlLoader.Load(this);
    }

    public static readonly StyledProperty<ICommand> CommandProperty =
        AvaloniaProperty.Register<MyButton, ICommand>(nameof(Command));


    public ICommand Command
    {
        get { return GetValue(CommandProperty); }
        set
        { // this setter is never executed as can be seen when running with debugger attached
            if (button != null) 
            {
                button.Command = value;
                SetValue(CommandProperty, value);
            }
            else
            {
                Debug.WriteLine("MyButton error: unable to set Command: control not initialized!");
            }
        }
    }
}

Однако при запуске приложения и нажатии кнопки целевой метод MyButton_Click никогда не выполняется. При подключении отладчика кажется, что установщик MyButton.Command также никогда не выполняется, что, по-моему, будет связано с неправильной привязкой? (На консоли отладки нет ошибок привязки или чего-либо, связанного с этим) *

После нескольких часов проб и ошибок я нашел обходной путь, используя Reflection и пользовательский обработчик событий OnClick() для элемента button. Это работает, но довольно уродливо и требует целевого метода c, так что мой вопрос:

Как правильно связать команду на UserControl с методом, содержащимся в ViewModel главного окна ?

Также: Может ли мой подход, основанный на рефлексии, быть также жизнеспособным? (Я предполагаю, что привязки Авалонии также как-то основаны на рефлексии?)

1 Ответ

1 голос
/ 30 апреля 2020

Не используйте геттеры и сеттеры для стилизованных свойств, они не будут вызываться при вызове свойств с помощью привязок, стилей или анимации (то же самое для WPF, UWP и Xamarin.Forms). Вместо этого вам нужно либо связать команду вложенной кнопки через <Button Command="{Binding $parent[myControls:MyButton]}" /> (предпочтительно), либо подписаться на уведомление об изменении свойства из конструктора stati c, как исходный Button делает .

Подробнее о свойствах зависимостей (которые работают в основном так же, как StyledProperty в Avalonia): https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-properties-overview

...