XAML 在外部标记中使用RelativeSource的正确方法是什么?

liwlm1x9  于 2022-12-07  发布在  其他
关注(0)|答案(2)|浏览(130)

我想避免在下面重复Source={RelativeSource AncestorType={x:Type vm:MainViewModel}}

<SwipeView ...   xmlns:vm="clr-namespace:Todo.ViewModel">
    <SwipeView.LeftItems>
        <SwipeItems>
            <SwipeItem Text="Delete" 
                Command="{Binding DeleteCommand,Source={RelativeSource AncestorType={x:Type vm:MainViewModel}}}" />
        </SwipeItems>
    </SwipeView.LeftItems>
    <Grid Padding="0,5">
        <Frame >
            <Frame.GestureRecognizers>
                <TapGestureRecognizer
                Command="{Binding TapCommand,Source={RelativeSource AncestorType={x:Type vm:MainViewModel}}}"/>
            </Frame.GestureRecognizers>
        </Frame>
    </Grid>
</SwipeView>

我做了以下操作,但它没有按预期工作。

<SwipeView ... xmlns:vm="clr-namespace:Todo.ViewModel"
    BindingContext="{Binding Source={RelativeSource AncestorType={x:Type vm:MainViewModel}}}"
        >
    <SwipeView.LeftItems>
        <SwipeItems>
            <SwipeItem Text="Delete"  Command="{Binding DeleteCommand}" />
        </SwipeItems>
    </SwipeView.LeftItems>
    <Grid Padding="0,5">
        <Frame >
            <Frame.GestureRecognizers>
                <TapGestureRecognizer  Command="{Binding TapCommand}" />
            </Frame.GestureRecognizers>
        </Frame>
    </Grid>
</SwipeView>

存储库

使用下面的repo来避免得到不一致的结果(我们之间),并确保我们在同一范围内进行讨论。
https://github.com/pstricks-fans/Todo
以下是相关部分:

我的浏览视图:

第一次

主页:

第一个

主视图型号:

public partial class MainViewModel : ObservableObject
{
    [RelayCommand]
    void Delete(string s){}

    [RelayCommand]
    async Task Tap(string s){}
}
dgenwo3n

dgenwo3n1#

在您的示例中,SwipeView正在ItemTemplate内部使用。您不得更改其BindingContext;必须是相关项目。
因此,你最初的目标是不可能的;我们可以简化“Source”表达式,但不能消除它。
我知道的最简单的是:

Command="{Binding VM.DeleteCommand, Source={x:Reference thePage}}"

说明:在“thePage”上,找到包含属性“DeleteCommand”的属性“VM”。对MainPage进行以下更改。
第一次

wrrgggsh

wrrgggsh2#

首先,在官方文档中绑定到祖先的格式类似于{Binding Source={RelativeSource AncestorType={x:Type local:PeopleViewModel}}, Path=DeleteEmployeeCommand}
然后,您可以尝试在构造方法中设置SwipeView的绑定上下文,而不是使用绑定方式。
我已经做了一个样本测试,绑定工作良好:
此时将显示MySwipeView.cs:

public partial class MySwipeView : SwipeView
    {
      public ICommand TestCommand { get; private set; }
      public MySwipeView()
      {
            InitializeComponent();
            TestCommand = new Command<string>(Test);
            //BindingContext = this;
            BindingContext = new MyViewModel();
      }
      void Test(string print)
      {
            Debug.WriteLine("============"+print);
      }

    }

我的浏览视图.xaml:

<SwipeView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiAppTest.MySwipeView"
             >
    <SwipeView.LeftItems>
        <SwipeItems>
            <SwipeItem
                Text="Delete"
                Command="{Binding DeleteCommand}"
                CommandParameter="xxxxxxxxx"/>
        </SwipeItems>
    </SwipeView.LeftItems>
    <Grid Padding="0,5">
        <Frame >
            <Frame.GestureRecognizers>
                <TapGestureRecognizer
                Command="{Binding TapCommand}"
                CommandParameter="xxxxxxxx"/>
            </Frame.GestureRecognizers>
            <Label Text="xxxxxxxx" FontSize="24"/>
        </Frame>
    </Grid>
</SwipeView>

主页面.xaml:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MauiApp21"
             x:Class="MauiApp21.MainPage">

    <HorizontalStackLayout>
        <local:MySwipeView/>
    </HorizontalStackLayout>

</ContentPage>

将显示MyViewModel.cs:

public partial class MyViewModel : ObservableObject
    {
        [RelayCommand]
        void Delete(string value) { Debug.WriteLine("===========Delete"); }
        [RelayCommand]
        void Tap(string value) { Debug.WriteLine("===============Tap"); }
    }

无论BindingContextthis还是MyViewModel,该命令都将成功运行。

相关问题