MvvmCross ViewTypeResolver无法解析Tag(片段或自定义类型)
-
12-12-2019 - |
题
实际情况是,我添加到 MvxViewTypeResolver
类“Fragment”-Case,所以它看起来像这样:
#region Copyright
// <copyright file="MvxViewTypeResolver.cs" company="Cirrious">
// (c) Copyright Cirrious. http://www.cirrious.com
// This source is subject to the Microsoft Public License (Ms-PL)
// Please see license.txt on http://opensource.org/licenses/ms-pl.html
// All other rights reserved.
// </copyright>
//
// Project Lead - Stuart Lodge, Cirrious. http://www.cirrious.com
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.Views;
using Cirrious.MvvmCross.Binding.Android.Interfaces.Binders;
namespace Cirrious.MvvmCross.Binding.Android.Binders
{
public class MvxViewTypeResolver : IMvxViewTypeResolver
{
private Dictionary<string, Type> _cache = new Dictionary<string, Type>();
public IDictionary<string, string> ViewNamespaceAbbreviations { get; set; }
#region IMvxViewTypeResolver Members
public virtual Type Resolve(string tagName)
{
Type toReturn;
if (_cache.TryGetValue(tagName, out toReturn))
return toReturn;
var unabbreviatedTagName = UnabbreviateTagName(tagName);
var longLowerCaseName = GetLookupName(unabbreviatedTagName);
var viewType = typeof(View);
#warning AppDomain.CurrentDomain.GetAssemblies is only the loaded assemblies - so we might miss controls if not already loaded
var query = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
where viewType.IsAssignableFrom(type)
where (type.FullName ?? "-").ToLowerInvariant() == longLowerCaseName
select type;
toReturn = query.FirstOrDefault();
_cache[tagName] = toReturn;
return toReturn;
}
private string UnabbreviateTagName(string tagName)
{
var filteredTagName = tagName;
if (ViewNamespaceAbbreviations != null)
{
var split = tagName.Split(new char[] {'.'}, 2, StringSplitOptions.RemoveEmptyEntries);
if (split.Length == 2)
{
var abbreviate = split[0];
string fullName;
if (ViewNamespaceAbbreviations.TryGetValue(abbreviate, out fullName))
{
filteredTagName = fullName + "." + split[1];
}
}
}
return filteredTagName;
}
#endregion
protected string GetLookupName(string tagName)
{
var nameBuilder = new StringBuilder();
switch (tagName)
{
case "View":
case "ViewGroup":
nameBuilder.Append("android.view.");
break;
case "fragment":
nameBuilder.Append("android.app.");
break;
default:
if (!IsFullyQualified(tagName))
nameBuilder.Append("android.widget.");
break;
}
nameBuilder.Append(tagName);
return nameBuilder.ToString().ToLowerInvariant();
}
private static bool IsFullyQualified(string tagName)
{
return tagName.Contains(".");
}
}
}
现在正在提交正确的 longLowerCaseTagName
(android.app.fragment) 但在查询中它无法解析类型。
我的建议是,当应该解析类型时,不加载片段控件。也许还有其他方法可以解决类型问题?
另外,如果我添加自定义类型(给出标签 Mvx.MyCustomType
在 axml 中)它没有得到解决。我需要在其中添加一些内容吗 MvxBindingAttributes.xml
在这种情况下?
谢谢您的帮助!
解决方案
首先对代码进行解释:
MvvmCross Binder 使用的自定义 XML 膨胀器工厂尝试以与标准 2.x Android XML 膨胀器非常相似的方式加载视图。
视图类型解析的默认代码确实位于: https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross.Binding/Android/Binders/MvxViewTypeResolver.cs
如果您的 xml 包含诸如以下的名称 <MyCompany.MyProject.MyViews.MyFirstView />
然后是视图类型解析器:
首先检查缩写并将其扩展为完整的命名空间 - 默认情况下唯一已知的缩写是
Mvx.
扩展为:Cirrious.MvvmCross.Binding.Android.Views.
. 。如果您想添加更多缩写,请覆盖ViewNamespaceAbbreviations
在 https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross.Binding/Android/MvxBaseAndroidBindingSetup.cs然后检查未缩写的名称是否是非命名空间名称。如果是,则假定该类是 Android 命名空间,并在其前面添加
android.view.
或者android.widget.
然后将完全命名空间名称转换为全部小写,作为不区分大小写的查找键
使用该小写键在所有加载的程序集中搜索从 View 派生的所有类型。
缓存结果(无论是否为空)以加速后续的通货膨胀。
所有这些行为都是为了匹配默认的 Android xml 视图膨胀代码 http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.6_r1/android/view/LayoutInflater.java#LayoutInflater.createViewFromTag%28java.lang.String% 2Candroid.util.AttributeSet%29
有了这个解释 - 这是您问题的答案:
MvvmCross 目前尚不包含任何 Fragment 支持。官方的 MonoDroid 片段支持本身上周才发布,我还没有收到任何人请求片段 - Android“片段”似乎让大多数人回到了基于 Activity 和 Dialog 的代码。
简而言之;查看文档, fragment
不是 Android View - 它看起来像 Fragment 直接继承自 Java.Lang.Object - 请参阅 http://developer.android.com/reference/android/app/Fragment.html
因此,MvvmCross ViewTypeResolver 目前无法处理片段。
我建议,如果您今天需要 mvvmcross 和片段,那么您最好的选择是用您自己的解析器替换默认解析器(使用 IoC) - 但我无法对此提供太多建议,因为我还没有完全阅读并了解 droid 文档 http://developer.android.com/guide/topics/fundamentals/fragments.html
根据我创建当前通货膨胀代码的经验,我认为当您这样做时,您会找到源必需的阅读材料 - 例如看 : http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/view/LayoutInflater.java#LayoutInflater.createViewFromTag%28android.view.View% 2Cjava.lang.String%2Candroid.util.AttributeSet%29
我无法向您提供有关何时提供官方 mvvmcross 片段支持的任何信息 - 目前尚未计划。
支持自定义视图,但通常不会存在于 Mvx.
缩写命名空间。
它们更有可能存在于您的 UI 应用程序命名空间中,或某些共享库中。
要查看正在运行的自定义视图,请参阅教程中的 PullToRefresh 示例 - https://github.com/slodge/MvvmCross/blob/master/Sample%20-%20Tutorial/Tutorial/Tutorial.UI.Droid/Resources/Layout/Page_PullToRefreshView.axml