自定义控件的 Xamarin 数据绑定值计算为 Xamarin.Forms.Binding

Posted

技术标签:

【中文标题】自定义控件的 Xamarin 数据绑定值计算为 Xamarin.Forms.Binding【英文标题】:Xamarin databinding value for custom control evaluates as Xamarin.Forms.Binding 【发布时间】:2016-01-20 03:18:09 【问题描述】:

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

场景如下:

我的视图模型:

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”属性的类型不匹配。为了尝试解决此问题,我将属性类型更改为“对象”,此时 ShellViewModel.ViewModel 中的设置器收到 Xamarin.Forms.Binding 的实例。

谁能发现我做错了什么,这就解释了为什么我得到一个 Binding 实例而不是 ShellViewChildModel?奇怪的是,对于我的 xaml 中的其他控件,我的内容显示得很好。

欢迎任何想法。到目前为止,我的想法已经用尽,文档没有指出我的代码有任何明显的缺陷:/

【问题讨论】:

在获取你的ActiveViewModel 时试试这个; return (ShellViewChildModel)GetValue(ViewModelProperty); 并且在集合中也只需使用您的 ViewModelProperty,不需要私有支持字段。 @GeraldVersluis 不幸的是,这会导致同样的错误。此外,由于习惯了 WPF,我开始尽可能避免使用 DependencyObject,在这种情况下,我猜想避免使用 BindableObject 也是有意义的。无论如何 - 更改为 BindableObject + 按照建议实施并没有解决这个问题 【参考方案1】:

我讨厌魔法。似乎“更容易”的编程变得更“神奇”的事情发生。更多次然后不是它最终把我搞砸了。对不起,答案之前在这里做简短的评论。

改变

 private static readonly BindableProperty ViewModelProperty

 public static readonly BindableProperty ViewModelProperty

为什么?

赋值

ShellChildPresenter ViewModel="Binding Path=ActiveViewModel"

由 Xaml 解析器解释。首先,它创建一个由“Binding Path=ActiveViewModel”描述的绑定元素。其次,它将“属性”一词附加到末尾,并在 Binding Context 中扫描对象,寻找.....属性以神奇地将其全部连接到。

由于您的........属性是私有的,解析器看不到它。所以它继续前进并按照您告诉它的方式执行 ViewModel=Binding 而不是您想要的 ViewModelProperty=Binding。

就像我说的我讨厌魔法。

【讨论】:

老实说,我同意你的咆哮...如果有警告就可以了。但是它绑定到 clr 属性,而当无法发现“依赖属性”时默默地失败只是......该死的。为什么?!我一直在寻找像18h这样的解决方案...... grrrrrr。然后再次对这样的错误感到不安有助于记住它。谢谢!

以上是关于自定义控件的 Xamarin 数据绑定值计算为 Xamarin.Forms.Binding的主要内容,如果未能解决你的问题,请参考以下文章

在父项中设置绑定时,Xamarin.Forms 绑定到自定义控件不起作用

ReactiveUI 中的 Xamarin.Forms 控件是不是需要自定义绑定?

Xamarin Forms 命令在自定义控件中始终为空

Xamarin 自定义控件

Xamarin XAML语言教程控件模板的模板绑定

WPF 自定义控件将文本框文本重置为默认值