.Net MAUI 数据绑定未传递到自定义组件

814*_*k31 3 maui

我在数据绑定与自定义组件一起使用时遇到问题。

我创建了一个 IncrementValue 属性,每次单击按钮时该属性都会增加。

绑定到标签时会反映更改。但是,当我将其绑定到自定义组件中的可绑定属性时,它们不起作用。

在示例中,我构建了一个名为的自定义组件Card,它具有两个可绑定属性CardTitleCardIncrement

由于我是 MAUI 甚至 Xamarin 的新手,我是否遗漏了一些东西。

以下代码片段的 Github 链接:https://github.com/814k31/DataBindingExample

卡.xaml.cs

namespace DataBindingExample;

public partial class Card : VerticalStackLayout
{
    public static readonly BindableProperty CardTitleProperty = BindableProperty.Create(nameof(CardTitle), typeof(string), typeof(Card), string.Empty);
    public static readonly BindableProperty CardIncrementProperty = BindableProperty.Create(nameof(CardIncrement), typeof(int), typeof(Card), 0);

    public string CardTitle
    {
        get => (string)GetValue(CardTitleProperty);
        set => SetValue(CardTitleProperty, value);
    }

    public int CardIncrement
    {
        get => (int)GetValue(CardIncrementProperty);
        set => SetValue(CardIncrementProperty, value);
    }

    public Card()
    {
        InitializeComponent();

        BindingContext = this;
    }
}
Run Code Online (Sandbox Code Playgroud)

卡.xaml

<?xml version="1.0" encoding="utf-8" ?>
<VerticalStackLayout
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:databindingexample="clr-namespace:DataBindingExample"
    x:DataType="databindingexample:Card"
    x:Class="DataBindingExample.Card"
    Spacing="25"
    Padding="30,0"
    VerticalOptions="Center"
    BackgroundColor="red"
>
    <Label
        Text="{Binding CardTitle}"
        SemanticProperties.HeadingLevel="Level1"
        FontSize="32"
        HorizontalOptions="Center"
    />
    <Label
        Text="{Binding CardIncrement}"
        SemanticProperties.HeadingLevel="Level1"
        FontSize="32"
        HorizontalOptions="Center"
    />
</VerticalStackLayout>
Run Code Online (Sandbox Code Playgroud)

主页.xml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="DataBindingExample.MainPage"
    xmlns:DataBindingExample="clr-namespace:DataBindingExample"
    xmlns:ViewModels="clr-namespace:DataBindingExample.ViewModels"
    x:DataType="ViewModels:MainPageViewModel"
>
    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center"
        >
            <Label
                Text="{Binding IncrementedValue}"
                SemanticProperties.HeadingLevel="Level2"
                FontSize="18"
                HorizontalOptions="Center"
            />

            <!-- Why doesnt this work? -->
            <DataBindingExample:Card CardIncrement="{Binding IncrementedValue}" />

            <Button
                x:Name="CounterBtn"
                Text="Click Me"
                SemanticProperties.Hint="Counts the number of times you click"
                Command="{Binding IncrementValueCommand}"
                HorizontalOptions="Center"
            />
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>
Run Code Online (Sandbox Code Playgroud)

Too*_*eve 14

制作自定义组件(包括 XAML)时,请勿设置BindingContext = this;.

\n

原因:您希望组件使用与其所在页面相同的 BindingContext。如果您不在自定义组件中设置 BindingContext,这种情况会自动发生。

\n

但是,删除此行会破坏组件的所有 xaml Bindings;您需要向 xaml添加一些内容来解决此问题。

\n

或者换句话说:如何从 XAML 中引用卡的属性?请参阅下一节。

\n
\n

通过 x:Name 访问组件属性

\n

解决方案:为自定义组件(卡)提供一个x:Name,并将其作为这些绑定的“源”:

\n
<VerticalStackLayout\n    ...\n    x:Name="me"     <-- IMPORTANT! Change name as desired.\n    x:Class="DataBindingExample.Card"\n>\n    ...\n    <Label Text="{Binding CardIncrement, Source={x:Reference me}}"\n    ...\n
Run Code Online (Sandbox Code Playgroud)\n

请注意此解决方案的两个部分:

\n
    \n
  • 在组件的 xaml 标头中,定义x:Name="mynamehere".
  • \n
  • 在每个 中Binding,假设该组件是源:\n , Source={x:Reference mynamehere}
  • \n
  • 另一种语法是Sourcebefore Path"{Binding Source={x:Reference me}, CardIncrement}"
  • \n
  • 或者,在这两种语法中,可以标记Path"{Binding Source={x:Reference me}, Path=CardIncrement}"
  • \n
\n
\n
\n

可选(罕见):如果自定义组件具有“ViewModel”:

\n

重要提示:即使您正在使用 MVVM,自定义组件通常也没有视图模型。相反,它的行为是由包含页面使用 BindableProperties 控制的。如相关代码所示。

\n

对于那些将组件的数据和数据操作方法分解为单独的(“视图模型”)类的人来说,此处显示的技术很方便。

\n

要使 BindableProperties 发挥作用,请回忆上面的内容:

\n
\n

不要设置 BindingContext(以便组件可以轻松访问页面的 BindingContext)。

\n
\n

因此,在这种技术中,我们不将 ViewModel 设置为 BindingContext。

\n

如何访问这个ViewModel?

\n

通过将其保存为组件的属性;例如:

\n
public partial class MyComponent : ContentView\n{\n  private MyViewModel VM;\n\n  public void MyComponent()\n  {\n    InitializeComponent();\n\n    VM = new MyViewModel();\n    //DO NOT DO "BindingContext = VM;"\n  }\n\npublic class MyViewModel : ObservableObject\n{\n  [ObservableProperty]\n  SomeType someProperty;   // This is field. Property "SomeProperty" is generated.\n}\n
Run Code Online (Sandbox Code Playgroud)\n

重要提示:需要x:Name在组件上定义。请参阅此答案的前面部分。

\n

然后在 xaml 中,我们使用.符号访问 VM 的属性:

\n
  <Label Text="{Binding VM.SomeProperty, Source={x:Reference me}}"\n
Run Code Online (Sandbox Code Playgroud)\n
\n

另一种方法是Source={RelativeSource Self}

\n
  <SomeElement SomeAttribute="{Binding MyProperty, Source={RelativeSource Self}}" />\n  <-- OPTIONAL -->\n  <SomeElement SomeAttribute="{Binding VM.SomeProperty, Source={RelativeSource Self}}" />\n
Run Code Online (Sandbox Code Playgroud)\n

我个人不使用这种语法,因为有人阅读时可能不确定“Self”指的是什么。是“SomeElement”(包含“Binding”表达式的元素)吗?它是周围的“DataTemplate”(如果有)吗?它是 XAML 文件的根吗?我\xe2\x80\x99m不会回答这个问题;使用 x:Name 代替。

\n