MvvmCross ViewTypeResolver не разрешает тег (фрагмент или пользовательский тип)
-
12-12-2019 - |
Вопрос
Реальная ситуация такова, что я добавил в MvxViewTypeResolver
классифицируйте случай «Фрагмент», чтобы он выглядел так:
#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
в этом случае?
Спасибо за помощь!
Решение
Сначала объяснение кода:
Пользовательская фабрика надувателя XML, используемая MvvmCross Binder, пытается загрузить представления аналогично стандартному наполнителю XML для Android версии 2.x.
Код по умолчанию для разрешения типа представления действительно находится в: 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 в настоящее время не содержит поддержки фрагментов.Официальная поддержка фрагментов MonoDroid была выпущена только на прошлой неделе, и мне еще никто не запрашивал фрагменты - «фрагментация» Android, похоже, удерживает большинство людей от кода на основе действий и диалогов.
Коротко просматривая документацию, fragment
не является представлением Android - похоже, что фрагмент наследуется непосредственно от Java.Lang.Object - см. http://developer.android.com/reference/android/app/Fragment.html
По этой причине MvvmCross ViewTypeResolver в настоящее время не может работать с фрагментами.
Я бы предположил, что если вам сегодня нужны и mvvmcross, и фрагменты, то лучше всего заменить преобразователь по умолчанию (с использованием IoC) на свой собственный преобразователь, но я не могу дать много советов по этому поводу, поскольку я еще не полностью прочитал и понял документацию по дроиду 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.
сокращенное пространство имен.
Они с гораздо большей вероятностью будут жить в пространстве имен вашего приложения пользовательского интерфейса или в какой-либо общей библиотеке.
Чтобы увидеть настраиваемое представление в действии, см. пример PullToRefresh в руководстве: https://github.com/slodge/MvvmCross/blob/master/Sample%20-%20Tutorial/Tutorial/Tutorial.UI.Droid/Resources/Layout/Page_PullToRefreshView.axml