关于xamarin.forms:Xamarin Forms自定义控件数据绑定问题

Xamarin Forms custom control data binding issue

我有一个简单的自定义控件,但无法让公开的可绑定 Command 属性正常工作。

设置如下:MainPage.xaml 承载 CustomControl.xaml(下方的米色区域)。 CustomControl 包含一个标签和一个按钮。 MainPage 包含 CustomControl、Entry、Label 和一个 Button。所有控件都绑定到 MainPageViewModel 中的 CustomControlText 属性。因此,随着该属性的更改,所有控件都应更新。

它主要工作...

请看下面的演示视频。我单击 MainPage 上的按钮,所有控件都会更新,包括自定义控件。当我更改条目值时,所有字段都会更新。但是,单击"从 CustomControl 增加"没有任何作用。它应该调用 MainViewModel.

中的 SubmitCommand2

enter

MainPage.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:App7"
             x:Class="App7.MainPage">

    <StackLayout>
        <BoxView HeightRequest="100" />

        <local:CustomControl
            Margin="50"
            WidthRequest="300"
            TextData="{Binding CustomControlText}"
            Command="{Binding SubmitCommand2}"
        />

        <Entry Text="{Binding CustomControlText}" />

        <Label Text="{Binding CustomControlText}" />

        <Button Text="Increment from Main Page" Command="{Binding SubmitCommand}" />

    </StackLayout>

</ContentPage>

MainPage.xaml.cs

1
2
3
4
5
6
7
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }
}

MainPageModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class MainPageModel : FreshBasePageModel
{
    public MainPageModel() { }

    public string CustomControlText { get; set; }

    private int _index = 0;

    public Command SubmitCommand
    {
        get
        {
            return new Command(() =>
            {
                _index++;
                CustomControlText = $"Hello World {_index}";
            });
        }
    }

    public Command SubmitCommand2
    {
        get
        {
            return new Command(() =>
            {
                _index++;
                _index++;
                CustomControlText = $"Hello World {_index}";
            });
        }
    }

    public override void Init(object initData)
    {
        CustomControlText ="Hello World";

        base.Init(initData);
    }
}

CustomControl.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App7.CustomControl"
             BackgroundColor="Beige"
             x:Name="this">
    <ContentView.Content>
        <StackLayout>
            <Entry x:Name="entryControl"
                Placeholder="Enter Text"
                Text="{Binding Source={x:Reference this}, Path=TextData}"
            />
            <Button Text="Increment From CustomControl"
                Command="{Binding Source={x:Reference this}, Path=Command}"
            />
        </StackLayout>
    </ContentView.Content>
</ContentView>

CustomControl.xaml.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomControl : ContentView
{
    public CustomControl()
    {
        TextData ="";

        InitializeComponent();
    }

    public static readonly BindableProperty TextDataProperty = BindableProperty.Create(
                                               propertyName:"TextData",
                                               returnType: typeof(string),
                                               declaringType: typeof(CustomControl),
                                               defaultBindingMode: BindingMode.TwoWay,
                                               defaultValue:"");

    public string TextData
    {
        get { return base.GetValue(TextDataProperty).ToString(); }
        set { base.SetValue(TextDataProperty, value); }
    }

    public static readonly BindableProperty CommandProperty = BindableProperty.Create(
                                               propertyName:"Command",
                                               returnType: typeof(Command),
                                               declaringType: typeof(CustomControl),
                                               defaultBindingMode: BindingMode.OneWay);

    public Command Command { get; set; }
}

CustomControlCommand属性也应该用base.GetValuebase.SetValue实现,和TextData一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public partial class CustomControl : ContentView
{
    ...

    public static readonly BindableProperty CommandProperty =  
        BindableProperty.Create(
            propertyName: nameof(Command),
            returnType: typeof(ICommand),
            declaringType: typeof(CustomControl),
            defaultBindingMode: BindingMode.OneWay,
            defaultValue: default(ICommand));

    public ICommand Command
    {
        get => (ICommand) GetValue(CommandProperty);
        set => SetValue(CommandProperty, value);
    }
}