XAML 通过Avalonia上的TemplateBinding分配按钮Click事件

j0pj023g  于 2022-12-07  发布在  其他
关注(0)|答案(1)|浏览(678)

我有一个TemplatedControl SoftwareReleaseControl,它显示一些文本和一个按钮。我需要此按钮从创建SoftwareReleaseControl控件时指定的属性OnInstallClick继承其Click事件。
问题是:我无法使其工作。它没有绑定到模板的属性。我尝试将源代码从Avalonia的button (ClickEvent)复制到控件的Code-Behind。它显示为EventHandler,但没有传递到按钮,并且还给出Unable to find suitable setter or adder [...]错误。
SoftwareReleaseControl.xaml:

<Styles xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="using:Updater.Controls">
    <Design.PreviewWith>
        <StackPanel Spacing="5">
            <Panel Classes="Spacing"/>
            <my:SoftwareReleaseControl Title="..." Version="..." Description="..." Installed="..."/>
            <my:SoftwareReleaseControl Title="..." Version="..." Description="..." Installed="..."/>
        </StackPanel>

    </Design.PreviewWith>

    <Style Selector="TextBlock">
        <Setter Property="Foreground" Value="{DynamicResource text}"/>
        <Setter Property="FontFamily" Value="Lato"/>
    </Style>
    [...]
    <Style Selector="my|SoftwareReleaseControl">
        [...]
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Panel Background="{TemplateBinding Background}"
                           HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
                           VerticalAlignment="{TemplateBinding VerticalAlignment}"
                           Height="{TemplateBinding Height}"
                           MinWidth="{TemplateBinding MinWidth}" Width="{TemplateBinding Width}">
                        <Grid Margin="{TemplateBinding Padding}"
                              HorizontalAlignment="Stretch"
                              VerticalAlignment="Stretch"
                              RowDefinitions="46, *, 40">
                            [...]

                            <StackPanel Grid.Row="2" Orientation="Horizontal">
            ======= HERE ===>>  <Button x:Name="PART_footer_installButton"
                                        Content="Instalar"
            ======= PROBLEM ===>>       Click="{TemplateBinding OnInstallClick}">
                                    <Button.Styles>
                                        <Style Selector="Button#PART_footer_installButton">
                                            <Setter Property="VerticalAlignment" Value="Bottom"/>
                                            <Setter Property="HorizontalAlignment" Value="Left"/>
                                            <Setter Property="Foreground" Value="{DynamicResource text}"/>
                                            <Setter Property="FontSize" Value="16"/>
                                            <Setter Property="Tag" Value="{TemplateBinding Tag}"/>
                                        </Style>
                                        <Style Selector="Button#PART_footer_installButton:pointerover /template/ ContentPresenter#PART_ContentPresenter">
                                            <Setter Property="TextBlock.Foreground" Value="{DynamicResource text}"/>
                                        </Style>
                                    </Button.Styles>
                                </Button>
                            </StackPanel>
                        </Grid>
                    </Panel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Styles>

xaml.cs(代码隐藏):

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using System;

namespace Updater.Controls
{
    public partial class SoftwareReleaseControl : TemplatedControl
    {
        public SoftwareReleaseControl()
        {
            
        }
        public static readonly RoutedEvent<RoutedEventArgs> OnInstallClickEvent = RoutedEvent.Register<Button, RoutedEventArgs>(nameof(OnInstallClick), RoutingStrategies.Bubble);
        public event EventHandler<RoutedEventArgs> OnInstallClick
        {
            add => AddHandler(OnInstallClickEvent, value);
            remove => RemoveHandler(OnInstallClickEvent, value);
        }
        [...]
    }
}

MainWindow.xaml(我尝试在其中显示控件):

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:Updater.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:my="using:Updater.Controls"
        mc:Ignorable="d" Width="800" Height="520"
        x:Class="Updater.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Title="Updater">

    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
          Background="{DynamicResource window.background}"
          RowDefinitions="40, *" ColumnDefinitions="*">
        [...]
        <ScrollViewer Grid.Row="1">
            <StackPanel Spacing="5" x:Name="stk_releases">
                <Panel Classes="Spacing"/>
==== HERE ===>> <my:SoftwareReleaseControl Title="..." Version="..." Description="..." Installed="..." OnInstallClick="{Binding btn_OnClick}"/>
                <my:SoftwareReleaseControl Title="..." Version="..." Description="..." Installed="..." OnInstallClick="{Binding btn_OnClick}"/>
            </StackPanel>
        </ScrollViewer>
    </Grid>

</Window>

我是否需要在MainWindow的代码隐藏或ViewModel中实现btn_OnClick并不重要。
目前的程式码会给我错误:

    • 主窗口.xaml* 上的Unable to find suitable setter or adder for property OnInstallClick of type Updater:Updater.Controls.SoftwareReleaseControl for argument Avalonia.Markup:Avalonia.Data.Binding, available setter parameter lists are: System.EventHandler[[Avalonia.Interactivity.RoutedEventArgs, Avalonia.Interactivity]],在OnInstallClick="{Binding btn_OnClick}"上的OnInstallClick="{Binding btn_OnClick}"
  • Unable to find suitable setter or adder for property Click of type Avalonia.Controls:Avalonia.Controls.Button for argument Avalonia.Base:Avalonia.Data.IBinding, available setter parameter lists are: System.EventHandler 1个<Avalonia.Interactivity.RoutedEventArgs>on *SoftwareReleaseControl.xaml*,位于Click="{TemplateBinding OnInstallClick}"上。

是的,我确实在App. xaml上指定了 StyleInclude

**为什么 * 单击 * 而不是 * 命令 *:**我需要 sender 对象,这样我就可以获得按钮的Tag属性。窗口上会有很多这样的控件,我需要找出被单击的控件。

tl;dr:如何在模板化控件上指定事件处理程序,使控件中的按钮可以继承该处理程序作为其 Click(而不是Command)。我需要在哪里实现该处理程序?ViewModel还是CodeBehind?

tcbh2hod

tcbh2hod1#

我放弃了使用 Click,而是找到了一种将按钮本身发送到命令的方法。
SoftwareReleaseControl.xaml:

[...]
<Button x:Name="PART_footer_installButton"
    Command="{Binding _OnInstallClick}"
    CommandParameter="{Binding RelativeSource={RelativeSource Self}}">
    <Button.Styles>
        <Style Selector="Button#PART_footer_installButton">
            <Setter Property="VerticalAlignment" Value="Bottom"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="Foreground" Value="{DynamicResource text}"/>
            <Setter Property="FontSize" Value="16"/>
            <Setter Property="Tag" Value="{TemplateBinding Tag}"/>
        </Style>
        <Style Selector="Button#PART_footer_installButton:pointerover /template/ ContentPresenter#PART_ContentPresenter">
            <Setter Property="TextBlock.Foreground" Value="{DynamicResource text}"/>
        </Style>
    </Button.Styles>
</Button>
[...]

SoftwareReleaseControl.xaml.cs:

namespace Updater.Controls
{
    public partial class SoftwareReleaseControl : TemplatedControl
    {
        public SoftwareReleaseControl()
        {
            DataContext = this;
        }
        public event EventHandler InstallClick;
        private void _OnInstallClick(object? sender)
        {
            EventHandler handler = InstallClick;
            handler?.Invoke(sender, EventArgs.Empty);
        }
        [...]
    }
}

MainWindow.xaml.cs:

namespace Updater.Views
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel(this);

            for (int i = 0; i < 6; i++)
            {
                var t = new SoftwareReleaseControl();
                t.Description = (string)App.Current.Resources["lorem.50"];
                t.Installed = i % 2 == 0;
                t.Tag = i;
                t.InstallClick += T_InstallClick;
                stk_releases.Children.Add(t);
            }
        }

        private void T_InstallClick(object? sender, EventArgs e)
        {
            Debug.WriteLine("123");
            if (sender is Button btn)
            {
                Debug.WriteLine(btn.Tag);
            }
        }
    }
}

相关问题