如何将视图模型绑定到Xamarin中XAML中的视图?

如何将视图模型绑定到Xamarin中XAML中的视图?,xamarin,mvvm,binding,Xamarin,Mvvm,Binding,我有一个非常基本的观点 <ContentPage x:Class="ThetaRex.InvestmentManager.Merlin.Views.ScenarioSelectionPage" Title="{Binding Title}" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns="http://xamarin.com/schema

我有一个非常基本的观点

<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/>
来自WPF和UWP中的纯MVVM环境,我希望将视图绑定到XAML中的viewmodel,而不是使用代码隐藏中的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中从头开始创建视图模型,但它不使用视图中代码隐藏所使用的实例,因此这不是一个选项。

如果我了解您需要什么,解决方案是构建一个ViewModelLocator,如下所示:

  • ViewModelLocalizator类
  • 公共静态类ViewModelLocalizator
    {
    公共静态只读BindableProperty AutoWireViewModelProperty=
    CreateAttached(“AutoWireViewModel”,typeof(bool),typeof(ViewModelLocalizator),default(bool),propertyChanged:OnAutoWireViewModelChanged);
    公共静态bool GetAutoWireViewModel(BindableObject bindable)
    {
    return(bool)bindable.GetValue(AutoWireViewModelProperty);
    }
    公共静态void SetAutoWireViewModel(BindableObject bindable,bool值)
    {
    bindable.SetValue(AutoWireViewModelProperty,值);
    }
    /// 
    ///验证视图名称并将其与同名视图模型关联。将“视图”后缀替换为“视图模型”
    /// 
    AutoWireViewModelChanged上的私有静态无效(BindableObject bindable、object oldValue、object newValue)
    {
    如果(!(可绑定为元素视图))
    {
    返回;
    }
    var viewType=view.GetType();
    var viewModelName=viewType.FullName.Replace(“.Views.”,“.ViewModels.”)。Replace(“Page”,“ViewModel”);
    var viewModelType=Type.GetType(viewModelName);
    如果(viewModelType==null){return;}
    var vmInstance=Activator.CreateInstance(viewModelType);
    if(vmInstance!=null)
    {
    view.BindingContext=vmInstance;
    }
    }
    }
    
  • 在视图中使用它
  • 
    
    可能与@sermet重复-它不是重复的。见附注。该解决方案创建了视图无法访问的全新ViewModel。视图要求它必须能够调用其视图模型上的方法。例如,在上面的示例中初始化时执行LoadItemsCommand.var vm=BindingContext作为ScenarioSelectionViewModel;vm.LoadItemsCommand.Execute(null);
    <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">
    
    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;
            }
        }
    }
    
    <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/>