Xamarin - 绑定命令到User Control内对象的属性

时间:2017-01-19 23:18:54

标签: c# xaml xamarin xamarin.forms

我几天前就开始学习XAML了,我遇到了解决这个问题的麻烦。

在Xamarin Forms中,我想创建一个包含标签和按钮的用户控件,并能够将命令绑定到XAML中的usercontrol来自使用我的用户控件的另一个页面。

我目前正在例外:

  

Xamarin.Forms.Xaml.XamlParseException:'位置8:24。无法分配属性“Test1”:属性不存在,或者不可分配,或者值和属性之间的类型不匹配'

这是我目前试图开始工作的一个愚蠢的版本。

我的自定义控件XAML

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="App3.Controls.Control1">
    <StackLayout>
        <Button Command="{Binding Test1}" Text="Test"/>
    </StackLayout>
</ContentView>

使用我的自定义控件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"
             xmlns:local="clr-namespace:App3"
             xmlns:controls="clr-namespace:App3.Controls"
             x:Class="App3.MainPage">

    <controls:Control1 Test1="{Binding Test2}" />
</ContentPage>

我的自定义控制代码隐藏

using System.Windows.Input;
using Xamarin.Forms;

namespace App3.Controls
{
    public partial class Control1 : ContentView
    {

        private static readonly BindableProperty controlProperty = BindableProperty.Create("Test1", typeof(ICommand), typeof(Control1), null);

        public Control1()
        {
            InitializeComponent();
        }

        public ICommand Test1
        {
            get
            {
                return (ICommand)GetValue(controlProperty);
            }
            set
            {
                SetValue(controlProperty, value);
            }
        }

    }
}

使用自定义控件

查看页面模型
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Xamarin.Forms;

namespace App3
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        public MainPageViewModel()
        {
            this.Test2 = new Command(test);
        }

        public void test()
        {
            Application.Current.MainPage.DisplayAlert("it works", "it works", "it works");
        }

        public ICommand Test2
        {
            get; set;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

2 个答案:

答案 0 :(得分:14)

如果您希望从Xaml检测到可绑定的BindableProperty,可以遵循一些命名约定:

  

创建标识符字段时,请在注册时将该字段命名为属性名称,再加上后缀属性。此字段是依赖项属性的标识符,稍后将用作您将在包装器中进行的SetValue和GetValue调用的输入,通过您自己的代码,通过任何外部代码访问对该属性的任何其他代码访问。您可以通过属性系统以及可能由XAML处理器允许。

  

将DependencyProperty标识符定义为所有者类型的公共静态只读字段。

(这是DependencyProperty的文档,但在这种情况下它很适用于BindableProperties。请参阅https://msdn.microsoft.com/en-us/library/ms753358(v=vs.110).aspx

您可以通过替换

来修复代码
private static readonly BindableProperty controlProperty = BindableProperty.Create("Test1", typeof(ICommand), typeof(Control1), null);

public ICommand Test1
{
    get { return (ICommand)GetValue(controlProperty); }
    set { SetValue(controlProperty, value); }
}

通过

public static readonly BindableProperty Test1Property = BindableProperty.Create("Test1", typeof(ICommand), typeof(Control1), null);


public ICommand Test1
{
    get { return (ICommand)GetValue(Test1Property); }
    set { SetValue(Test1Property, value); }
}

这应该可以防止属性检测问题。

要使您的完整内容正常工作,Button命令绑定应将其源设置为控件本身,并且您应将MainPageViewModel设置为BindingContext MainPage

答案 1 :(得分:3)

非常感谢你们两位,我和Krzysztof一起离线谈过,经过所有这些改变之后,还有一件事要让它发挥作用。

现在当您单击自定义控件(Control1)中的按钮时,将不会调用binded命令,保存在绑定中的命令为null,但即使您通知视图从bindablecontext获取新命令,它也无法正常工作,因为它将找不到合适的属性,因为我们没有指定bindablecontext,因此框架将在其他地方(在父对象中)搜索我们的属性。不要尝试将自定义控件的bindablecontext设置为此,它将阻止对此控件的绑定能力(您将无法正确绑定到这些依赖项属性)。

在这种情况下,解决它的最简单方法是在xaml中设置适当的绑定源。 设置内容视图的名称,并在绑定所有绑定时指定绑定源(这里只有一个)。

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"   
x:Class="App3.Controls.Control1"
x:Name="MySpecifiedName">
    <StackLayout>
        <Button Command="{Binding Test1, Source={x:Reference MySpecifiedName}}" Text="Test"/>
    </StackLayout>
</ContentView>

我浪费了几个小时来挖掘如何修复它,所以我写这里是为了拯救面临这些问题的其他开发人员,时间。