首页 > 解决方案 > 如何在 Xamarin 中将视图模型绑定到 XAML 中的视图?

问题描述

我有一个非常基本的观点。

<ContentPage x:Class="ThetaRex.InvestmentManager.Merlin.Views.ScenarioSelectionPage"
             Title="{Binding Title}"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns="http://xamarin.com/schemas/2014/forms">
    <StackLayout>
        <ListView ItemsSource="{Binding Items}"/>
    </StackLayout>
<ContentPage/>

后面的代码也很简单:

namespace ThetaRex.InvestmentManager.Merlin.Views
{
    using System.ComponentModel;
    using ThetaRex.InvestmentManager.Merlin.ViewModels;
    using Xamarin.Forms;

    public partial class ScenarioSelectionPage : ContentPage
    {
        public ScenarioSelectionPage()
        {
            InitializeComponent();
            this.BindingContext = this.ViewModel = new ScenarioSelectionViewModel();
        }

        public ScenarioSelectionViewModel ViewModel { get; set; }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            ViewModel.LoadItemsCommand.Execute(null);
        }
    }
}

来自 WPF 和 UWP 中的纯 MVVM 环境,我想将视图绑定到 XAML 中的视图模型,而不是在后面的代码中使用this.Binding = ViewModel。我试过了:

<ContentPage x:Class="ThetaRex.InvestmentManager.Merlin.Views.ScenarioSelectionPage"
             xmlns:controls="clr-namespace:ThetaRex.InvestmentManager.Merlin.Controls"
             BindingContext="{Binding ViewModel}"
             Title="{Binding Title}"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns="http://xamarin.com/schemas/2014/forms">

但它没有用。如何从 XAML 绑定到 ViewModel?

注意: 我知道我可以在 XAML 中从头开始创建视图模型,但它不使用与视图后面的代码相同的实例,所以这不是一个选项。

标签: xamarinmvvmbinding

解决方案


如果我明白你想要什么,解决方案是像这样构建一个 ViewModelLocator:

  1. ViewModelLocalizator 类
public static class ViewModelLocalizator
{
    public static readonly BindableProperty AutoWireViewModelProperty =
           BindableProperty.CreateAttached("AutoWireViewModel", typeof(bool), typeof(ViewModelLocalizator), default(bool), propertyChanged: OnAutoWireViewModelChanged);

    public static bool GetAutoWireViewModel(BindableObject bindable)
    {
        return (bool)bindable.GetValue(AutoWireViewModelProperty);
    }

    public static void SetAutoWireViewModel(BindableObject bindable, bool value)
    {
        bindable.SetValue(AutoWireViewModelProperty, value);
    }

    /// <summary>
    /// VERIFY THE VIEW NAME AND ASSOCIATE IT WITH THE VIEW MODEL OF THE SAME NAME. REPLACING THE 'View' suffix WITH THE 'ViewModel'
    /// </summary>
    private static void OnAutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (!(bindable is Element view))
        {
            return;
        }

        var viewType = view.GetType();

        var viewModelName = viewType.FullName.Replace(".Views.", ".ViewModels.").Replace("Page", "ViewModel");
        var viewModelType = Type.GetType(viewModelName);

        if (viewModelType == null) { return; }

        var vmInstance = Activator.CreateInstance(viewModelType);

        if (vmInstance != null)
        {
            view.BindingContext = vmInstance;
        }
    }
}
  1. 在您的视图上使用它
<ContentPage x:Class="YourProject.Views.YourTestPage"
             Title="{Binding Title}"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:viewModelBase="clr-namespace:YourProject.ViewModels;assembly=YouProject"
             viewModelBase:ViewModelLocalizator.AutoWireViewModel="true"
>
    <StackLayout>
        <ListView ItemsSource="{Binding Items}"/>
    </StackLayout>
<ContentPage/>

推荐阅读