如何在资源字典中的 DataTemplate 中绑定命令?

How bind a command in DataTemplate in Resource Dictionary?

我正在尝试制作一个更好的解决方案架构,为此我将许多代码部分分离到不同的文件中。因为我的应用程序使用了很多数据模板,所以我将它们推送到不同的 ResourceDictionary.xaml 文件中。

问题:

我有一个视图 Agenda.xaml,带有 viewModel AgendaViewModel。此视图有一个 ListView,它调用外部 ResourceDictionary 文件中的数据模板。但是如果我想在 dataTemplate 中放置一个绑定命令,该命令永远不会执行,因为(我猜)我的 DataTemplate 所在的资源字典没有引用 ViewModel。

我能做什么?

我已经尝试过一些奇怪的绑定代码,比如

<TapGestureRecognizer Command="{Binding BindingContext.OpenActiviteCommand, Source={x:Reference agendaPage}}" CommandParameter="{Binding .}"/>

其中 "agendaPage" 是 Agenda.xaml 的 x:Name。

我在 Google 上找到的所有内容都是关于 WPF 和绑定 属性 在 Xamarin Forms(RelativeSource、ElementName 等...)上不可用

我知道我可以将 dataTemplate 放在我的 Agenda.xaml 视图中,但我真的想将它保存在外部文件中。我想避免查看 1500 行的文件....

这是我的 Agenda.xaml 视图

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Corim.Portable.CorimTouch.ViewForms.Agenda.AgendaViewDetail"
             xmlns:converters="clr-namespace:Corim.Portable.CorimTouch.Converters"
             Title="Agenda"
             x:Name="agendaPage">
    <ContentPage.Content>
        <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"  BackgroundColor="{StaticResource LightGrayCorim}">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <!-- Liste itv,pointage,activite -->
            <ListView 
                x:Name="listAgenda"
                Grid.Row="1"
                SeparatorVisibility="None"
                HasUnevenRows="True"
                SelectionMode="None"
                CachingStrategy="RecycleElement"
                ItemsSource="{Binding AgendaList}"
                ItemTemplate="{StaticResource agendaTemplateSelector}"
                BackgroundColor="{StaticResource LightGrayCorim}">
            </ListView>
        </Grid>
    </ContentPage.Content>
</ContentPage>

这是 AgendaTemplates.xaml

中 Datatemplate 的一部分
<DataTemplate x:Key="agenda-adresse-intervention">
        <ViewCell>
            <Frame Margin="10,5,10,0" HasShadow="False" Padding="0" CornerRadius="10" IsClippedToBounds="True">
                <controls:CustomTappedStackLayout
                    BackgroundColor="White"
                    TappedBackgroundColor="{StaticResource RollOver}"
                    HorizontalOptions="FillAndExpand"
                    Orientation="Horizontal"
                    Padding="10">
                    <StackLayout.GestureRecognizers>
                        <TapGestureRecognizer Command="{Binding Path=BindingContext.OpenParcCommand, Source={x:Reference agendaPage}}" CommandParameter="{Binding .}" NumberOfTapsRequired="1"/>
                    </StackLayout.GestureRecognizers>
                    <Image
                        Source="localisation_adresse"
                        WidthRequest="30"
                        HeightRequest="30"
                        Aspect="AspectFit"
                        HorizontalOptions="Start"
                        Margin="10"
                        VerticalOptions="StartAndExpand"/>

                    <StackLayout
                        HorizontalOptions="FillAndExpand"
                        Orientation="Vertical">
                        <Label
                        Text="{Binding Client}"
                        IsVisible="{Binding Client, Converter={StaticResource StringEmptyBooleanConverter}}"
                        FontFamily="{StaticResource SemiBoldFont}"
                        FontSize="{StaticResource MediumTextSize}"
                        TextColor="Black"/>

                        <Label
                        Text="{Binding Title}"
                        IsVisible="{Binding Title, Converter={StaticResource StringEmptyBooleanConverter}}"
                        FontFamily="{StaticResource RegularFont}"
                        FontSize="{StaticResource DefaultTextSize}"
                        TextColor="Gray"/>
                    </StackLayout>
                </controls:CustomTappedStackLayout>
            </Frame>
        </ViewCell>
    </DataTemplate>

But if I want put a Binding Command in the dataTemplate, the command is never executed because (I guess) the resource Dictionary where is my DataTemplate not reference ViewModel.

你猜错了:做你正在做的事情完全没问题,应该透明地工作。绑定在运行时解析,您的数据模板对将要绑定的对象一无所知。

1st:放弃BindingContext.OpenActiviteCommand废话:)只需绑定到OpenActiviteCommand,唯一的问题是:

第二:你的 OpenActiviteCommand 在哪里?

AgendaTemplates 的数据上下文是您 AgendaList 中的项目。 如果 AgendaList 的类型是 ObservableCollection<AgendaViewModel>,而你的 AgendaViewModelOpenParcCommand 那么它应该没问题:

public class AgendaViewModel
{
    public AgendaViewModel(ICommand openParcCommand)
    {
        OpenParcCommand = openParcCommand;
    }

    public ICommand OpenParcCommand { get; }
}

在你的 AgendaPageViewModel:

public class AgendaPageViewModel
{
    public ObservableCollection<AgendaViewModel> AgendaList { get; }
}

感谢@Roubachof

解决方案是用 AgendaDataViewModel 的 ListView 替换我的 InterventionModel ListView。

AgendaViewModel 是一个新的 class,它包含我需要的所有命令和一个 InterventionModel。

这是 AgendaDataViewModel :

public class AgendaDataViewModel : HybridContentViewModel
    {
        private InterventionModel _model;

        public InterventionModel Model
        {
            get => _model;
            set { _model = value; }
        }
        public ICommand OpenActiviteCommand { get; private set; }

        public AgendaDataViewModel()
        {
            this.OpenActiviteCommand = new Command<InterventionModel>(this.OpenActivite);
        }

        /// <summary>
        /// Ouvre le formulaire d'édition de l'activité
        /// </summary>
        /// <param name="model"></param>
        private void OpenActivite(InterventionModel model)
        {
            //TODO amener sur le formulaire d'activité
        }
    }

我的AgendaTemplate.xaml


 <!--Template pour l'affichage du parc-->
    <DataTemplate x:Key="agenda-adresse-intervention">
        <ViewCell>
            <Frame Margin="10,5,10,0" HasShadow="False" Padding="0" CornerRadius="10" IsClippedToBounds="True">
                <controls:CustomTappedStackLayout
                    BackgroundColor="White"
                    TappedBackgroundColor="{StaticResource RollOver}"
                    HorizontalOptions="FillAndExpand"
                    Orientation="Horizontal"
                    Padding="10">
                    <StackLayout.GestureRecognizers>
                        <TapGestureRecognizer Command="{Binding OpenParcCommand}" CommandParameter="{Binding Model}" NumberOfTapsRequired="1"/>
                    </StackLayout.GestureRecognizers>
                    <Image
                        Source="localisation_adresse"
                        WidthRequest="30"
                        HeightRequest="30"
                        Aspect="AspectFit"
                        HorizontalOptions="Start"
                        Margin="10"
                        VerticalOptions="StartAndExpand"/>

                    <StackLayout
                        HorizontalOptions="FillAndExpand"
                        Orientation="Vertical">
                        <Label
                        Text="{Binding Model.Client}"
                        IsVisible="{Binding Model.Client, Converter={StaticResource StringEmptyBooleanConverter}}"
                        FontFamily="{StaticResource SemiBoldFont}"
                        FontSize="{StaticResource MediumTextSize}"
                        TextColor="Black"/>

                        <Label
                        Text="{Binding Model.Title}"
                        IsVisible="{Binding Model.Title, Converter={StaticResource StringEmptyBooleanConverter}}"
                        FontFamily="{StaticResource RegularFont}"
                        FontSize="{StaticResource DefaultTextSize}"
                        TextColor="Gray"/>
                    </StackLayout>
                </controls:CustomTappedStackLayout>
            </Frame>
        </ViewCell>
    </DataTemplate>

如您所见,值绑定是通过这一行实现的:

{Binding Model.Client}

其中 Client 是 Binded 属性 的名称。要绑定命令,您不需要模型,只需像这样绑定即可:

Command={Binding CommandName}

希望对以后的人有所帮助!