自定义控件的Xamarin数据绑定值评估为Xamarin.Forms.Binding

时间:2015-10-21 08:06:35

标签: xaml xamarin xamarin.forms

我遇到了Xamarin.Forms的问题,因为使用它的人知道它与WPF非常相似。不幸的是,我遇到了一个我从未体验过WPF的问题。

场景如下:

My Viewmodel:

public class ShellViewModel : ViewModelBase
{
    public ShellViewModel()
    {
        ActiveViewModel = new ProjectActionOverviewViewModel();
    }

    private ShellViewChildModel _activeViewModel;

    public ShellViewChildModel ActiveViewModel
    {
        get { return _activeViewModel; }
        set
        {
            Debug.WriteLine("Updating ActiveViewModel.");
            SetValue(ref _activeViewModel, value);
            Task.Run(() => value.ActivateAsync());
            Debug.WriteLine("Updated ActiveViewModel.");
        }
    }

的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:viewModels="clr-namespace:MyNamespace.XamarinForms.ViewModels;assembly=MyNamespace.XamarinForms"
             xmlns:views="clr-namespace:MyNamespace.XamarinForms.Views;assembly=MyNamespace.XamarinForms"
             xmlns:resources="clr-namespace:MyNamespace.XamarinForms.Resources;assembly=MyNamespace.XamarinForms"
             xmlns:custom="clr-namespace:MyNamespace.XamarinForms.Views.Custom;assembly=MyNamespace.XamarinForms"
             x:Class="MyNamespace.XamarinForms.Views.Pages.ShellView">
    <ContentPage.BindingContext>
        <viewModels:ShellViewModel></viewModels:ShellViewModel>
    </ContentPage.BindingContext>
    <Grid BackgroundColor="{x:Static resources:Colors.DefaultBackground}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" BackgroundColor="{x:Static resources:Colors.CiRed}" Padding="14" IsVisible="{Binding ActiveViewModel.IsHeaderVisible}">
            <Label TextColor="{x:Static resources:Colors.BrightForeground}" FontSize="20" Text="{Binding ActiveViewModel.HeaderText}"/>
        </Grid>
        <Grid Grid.Row="1" BackgroundColor="{x:Static resources:Colors.DefaultBackground}">
            <custom:ShellChildPresenter ViewModel="{Binding Path=ActiveViewModel}"></custom:ShellChildPresenter>
        </Grid>
        <Grid IsVisible="{Binding ActiveViewModel.IsBusy}" Grid.Row="0" Grid.RowSpan="2" BackgroundColor="{x:Static resources:Colors.DarkBackground}" Opacity="0.5">
            <ActivityIndicator IsRunning="{Binding ActiveViewModel.IsBusy}" VerticalOptions="Center" HorizontalOptions="Center"></ActivityIndicator>
        </Grid>
    </Grid>
</ContentPage>

我的自定义控件:

public class ShellChildPresenter : ContentView
{
    public ShellChildPresenter()
    {
    }

    private static readonly BindableProperty ViewModelProperty = BindableProperty.Create<ShellChildPresenter, ShellViewChildModel>(
        presenter => presenter.ViewModel, 
        defaultValue: null,
        defaultBindingMode: BindingMode.OneWay,
        propertyChanged: ViewModelPropertyChanged);

    private static void ViewModelPropertyChanged(BindableObject bindable, ShellViewChildModel oldValue, ShellViewChildModel newValue)
    {
        if (newValue != null)
        {
            var current = bindable as ShellChildPresenter;
            if (current == null)
                return;

            var view = newValue.CreateContentView();
            view.BindingContext = newValue;
            current.Content = view;
        }
    }

    public ShellViewChildModel ViewModel
    {
        get { return (ShellViewChildModel)GetValue(ViewModelProperty); }
        set { SetValue(ViewModelProperty, value); }
    }
}

首先,这会引发异常,宣布“ViewModel”属性的类型不匹配。为了尝试修复此问题,我将属性类型更改为“object”,此时ShellViewModel.ViewModel中的setter收到了Xamarin.Forms.Binding的实例。

任何人都可以发现我做错了什么,这解释了为什么我得到的是Binding实例而不是ShellViewChildModel?奇怪的是,我的xaml中的其他控件已经让我的内容显示得很好。

欢迎任何想法。我开始没有想法和文档,并没有指出到目前为止我的代码有任何明显的缺陷:/

1 个答案:

答案 0 :(得分:1)

我讨厌魔法。似乎“更容易”的编程变得越来越“魔术”。更多次,然后不是它最终搞砸了我。对不起,在答复之前对此进行了简短的评论。

更改

 private static readonly BindableProperty ViewModelProperty

 public static readonly BindableProperty ViewModelProperty

为什么?

分配

ShellChildPresenter ViewModel =“{Binding Path = ActiveViewModel}”

由Xaml Parser解释。首先,它创建一个绑定元素,如“{Binding Path = ActiveViewModel}”所述。其次,它将单词Property附加到最后,并在Binding Context中搜索对象,查找.....属性以神奇地连接它。

因为你的........属性是私有的,解析器无法看到它。所以它继续前进,并按照你所说的去做ViewModel = Binding而不是你想要的ViewModelProperty = Binding。

就像我说我讨厌魔法一样。