Maui:通过附加属性将命令绑定到事件

最近重写旧项目,发现maui的社区工具EventToCommand不起作用,没发现问题在哪?也懒得重新安装包,自己模仿Avalonia写一个附加属性执行命令。

using System.Windows.Input;

namespace FileNexus.Behaviours
{
    public static class LoadedBehavious
    {
        public static readonly BindableProperty LoadedCommandProperty = BindableProperty.CreateAttached("LoadedCommand", typeof(ICommand),
            typeof(LoadedBehavious), null, BindingMode.OneWay, propertyChanged: OnLoadedCommandChanged);       

        private static void OnLoadedCommandChanged(BindableObject bindable, object oldValue, object newValue)
        {
            if(bindable is VisualElement element)
            {
                if(newValue is ICommand command)
                {
                    element.Loaded += Handler;
                }
                else
                {
                    element.Loaded -= Handler;
                }
            }
        }

        public static ICommand GetLoadedCommand(BindableObject bindable)
        {
            return (ICommand)bindable.GetValue(LoadedCommandProperty);
        }

        public static void SetLoadedCommand(BindableObject bindable,ICommand command)
        {
            bindable.SetValue(LoadedCommandProperty, command);
        }

        private static void Handler(object? sender, EventArgs e)
        {
            if(sender is VisualElement visualElement)
            {
                ICommand command = (ICommand)visualElement.GetValue(LoadedCommandProperty);
                if (command.CanExecute(null))
                {
                    command.Execute(null);
                }
            }
        }
    }
}

xaml平台

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:b="clr-namespace:FileNexus.Behaviours"
             b:LoadedBehavious.LoadedCommand="{Binding InitCommand}"                      
             x:Class="FileNexus.Views.FileCollectionPage"             
             Title="文件列表" BackgroundColor="Teal" NavigatedTo="ContentPage_NavigatedTo">
    <ContentPage.ToolbarItems>        
        <ToolbarItem Text="删除" Command="{Binding RemoveItemCommand}"/>        
        <ToolbarItem Text="发文" Command="{Binding SendTextCommand}"/>
        <ToolbarItem Text="回退" Command="{Binding GoBackCommand}"/>
    </ContentPage.ToolbarItems>    
    <Grid RowDefinitions="Auto,Auto,Auto,*" Padding="10">
        <ActivityIndicator IsRunning="{Binding IsUploading}" IsVisible="{Binding IsUploading}" Color="Orange" Grid.Row="0"/>
        <Label Text="{Binding CurrentDirectory,StringFormat='当前路径:{0}'}" TextColor="White" FontSize="16" FontAttributes="Bold" Grid.Row="1"/>
        <Label Text="{Binding WebFiles.Count,StringFormat='项目数:{0}'}" TextColor="White" FontSize="16" Grid.Row="2"/>
        <SwipeView Grid.Row="3">
            <SwipeView.LeftItems>
                <SwipeItem Text="上传" BackgroundColor="Orange" Command="{Binding UploadCommand}"/>
                <SwipeItem Text="下载" BackgroundColor="Chocolate" Command="{Binding DownloadCommand}"/>
            </SwipeView.LeftItems>
            <CollectionView ItemsSource="{Binding WebFiles}" SelectionMode="Single" SelectionChangedCommand="{Binding SelectedItemCommand}"
                SelectionChangedCommandParameter="{Binding Source={RelativeSource Self},Path=SelectedItem}" x:Name="collectionView">
                <CollectionView.ItemsLayout>
                    <LinearItemsLayout Orientation="Vertical" ItemSpacing="5"/>
                </CollectionView.ItemsLayout>
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Grid ColumnDefinitions="Auto,*" RowDefinitions="*,*" RowSpacing="2" ColumnSpacing="10">
                            <Image Source="documents.png" Aspect="AspectFill" Grid.Row="0" Grid.Column="0" WidthRequest="48" HeightRequest="48" Grid.RowSpan="2">
                                <Image.Triggers>
                                    <DataTrigger TargetType="Image" Binding="{Binding IsDirectory}" Value="True">
                                        <Setter Property="Source" Value="folder.png"/>
                                    </DataTrigger>
                                </Image.Triggers>
                            </Image>
                            <Label Text="{Binding FileName}" TextColor="White" Grid.Column="1" Grid.Row="0" FontSize="16" FontAttributes="Bold"/>
                            <Label Text="{Binding LastModifiedTime,StringFormat='修改时间:{0:yyyy-MM-dd HH:mm:ss}'}" Grid.Column="1" Grid.Row="1" TextColor="White">
                                <Label.Triggers>
                                    <DataTrigger TargetType="Label" Binding="{Binding IsDirectory}" Value="True">
                                        <Setter Property="Text" Value="{Binding CreationTime,StringFormat='创建时间:{0:yyyy-MM-dd HH:mm:ss}'}"/>
                                    </DataTrigger>
                                </Label.Triggers>
                            </Label>
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </SwipeView>
              
    </Grid>
</ContentPage>

MAUI 附加属性与 Avalonia 的关键差异对比
虽然核心逻辑一致,但 MAUI 和 Avalonia 的附加属性在实现细节上有 3 处关键差异,需注意适配:

对比维度 MAUI Avalonia
基类 基于BindableObject 基于AvaloniaObject
附加属性注册方法 BindableProperty.CreateAttached AvaloniaProperty.RegisterAttached
控件加载事件 VisualElement.Loaded 用Control.LoadedEvent

MAUI 不仅支持创建附加属性,而且实现逻辑与 Avalonia 高度相似 —— 都是通过 “静态属性 + 事件关联 + 数据绑定” 扩展控件功能。只需注意 MAUI 基于BindableObject的语法细节,即可实现与文章中 Avalonia 相同的 “事件绑定命令” 等场景,甚至可复用到 Android、iOS、Windows 等多平台。

posted @ 2025-10-17 21:34  孤独的小苗  阅读(8)  评论(0)    收藏  举报