【问题标题】:Bind view to viewmodel and show as dialog page in Xamarin.Forms?将视图绑定到视图模型并在 Xamarin.Forms 中显示为对话框页面?
【发布时间】:2019-01-06 18:11:56
【问题描述】:

我正在为 Windows、Android 和 iOS 开发跨平台库。

我有一个界面方法,用于显示基于某些 ViewModel(带有用于绑定的数据和命令)和相应视图的复杂对话框消息。

有一个 Windows 实现:

// view and viewModel is valid at this point
public void Show<TViewModel>(TView view, TViewModel viewModel) where TViewModel : class
{
    var window = (Window)view;
    window.DataContext = viewModel;
    window.ShowDialog();
}

我可以在 Xamarin.Forms 中做同样的事情吗?

我发现了类似的东西:

var activity = Intent(this, typeof(DataPage));
activity.BindingContext = viewModel
this.StartActivity(m_activity);

但这适用于 Xamarin.Android,这不是我需要的。

【问题讨论】:

    标签: c# mvvm xamarin.forms binding


    【解决方案1】:

    您需要使用的是来自Xamarin.Forms 程序集的INavigation 接口。所有视图/页面都通过 Navigation 属性提供它,并且您希望使用当前显示的。

    一旦你有了它,你就可以调用PushModalAsync,这需要Page的类型,但如果你想显示它,我希望你创建一个。

    绑定

    至于Bindings,您最终需要将您的视图模型分配给您的视图BindingContext 我的视图有一个类似于下面的基类:

    public abstract class ViewBase : ContentPage
    {
        protected ViewModelBase viewModel;
    
        internal ViewModelBase ViewModel
        {
            get
            {
                return this.viewModel;
            }
            set
            {
                if (this.viewModel != value)
                {
                    this.viewModel = value;
    
                    // Make sure we bind the view model to the UI.
                    this.BindingContext = value;
                }
            }
        }
    }
    

    进一步的想法

    这可能远远超出这个问题的要求,但是我已经按照您的要求将Pages 的显示包装到以下实现中:

    internal async Task<U> ShowAsync<T, U>(IDictionary<string, object> arguments = null, bool animated = true) where T : IDialogView where U : IDialogResult
    {
        var completionSource = new TaskCompletionSource<U>();
    
        try
        {
            var page = (IDialogView)Activator.CreateInstance<T>();
    
            // Hook up event handlers so when either the Complete/Error is fired then we dismiss and pass the result back to the caller.
            page.ResultChanged += (sender, e) =>
            {
                // Hide the modal view.
                this.DismissAsync();
    
                // Do we need to perform a safety check when converting?
                completionSource.SetResult((U)e.Value);
            };
    
            // Pass in any arguments to the view.
            page.SetArguments(arguments);
    
            // Display the view and wait.
            await this.navigation.PushModalAsync((Page)page, animated);
    
            // Return the result of the view.
            return await completionSource.Task;
        }
        catch (Exception ex)
        {
            LogService.Error($"Unable to ShowAsync for view: {typeof(T).Name}", ex);
            completionSource.SetException(ex);
        }
    
        return default(U);
    }
    
    internal interface IDialogView
    {
        event EventHandler<EventArgs<IDialogResult>> ResultChanged;
    
        void SetArguments(IDictionary<string, object> arguments);
    }
    
    internal interface IDialogResult
    {
    
    }
    

    虽然这看起来确实使初始设置复杂化,但这意味着您可以简单地调用:

    var result = await ShowAsync<MyView, MyViewResult>();
    

    最大的好处是它允许您显示新页面并等待它需要执行的任何操作并利用该操作的结果。请注意,您不需要处理对话框显示的结果,然后可以用简单的布尔值替换 U 逻辑。

    【讨论】:

    • 我已经更新了我的答案,以简要举例说明如何为 ViewModel 设置绑定
    • Adventures in Xamarin Forms 站点有一个非常好的视图模型优先导航示例,它也适用于对话框等,我自己在很多项目中都使用过它。主页似乎部分关闭 atm,因此您可能需要向作者发送电子邮件或查看回程机器。
    猜你喜欢
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    • 2019-06-09
    • 2013-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多