我遇到了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中的其他控件已经让我的内容显示得很好。
欢迎任何想法。我开始没有想法和文档,并没有指出到目前为止我的代码有任何明显的缺陷:/
答案 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。
就像我说我讨厌魔法一样。