Maui: [Spec] Arquitectura de renderizado delgado

Creado en 19 may. 2020  ·  56Comentarios  ·  Fuente: dotnet/maui

ADVERTENCIA: esta especificación sigue siendo un WIP, todavía estamos experimentando con este concepto

Descripción

La arquitectura de los renderizadores delgados se beneficia de las características de múltiples objetivos y de un solo proyecto.

Ejemplo

EntryRenderer.cs

public partial class EntryRenderer {
   public static PropertyMapper<IView> ViewMapper = new PropertyMapper<IView> {

     // Add your own method to map to any property         
     [nameof(IView.BackgroundColor)] = MapBackgroundColor

   };
}

EntryRenderer.iOS.cs

// You don’t need to register a new renderer.
public partial class EntryRenderer
{
     // You know what method to call because you named it!
   public static void MapBackgroundColor (IViewRenderer renderer, IView view)
     {
        // You don’t need to call any base methods here or worry about order.

        // Every renderer is consistent; you know where the native view is.
          var nativeView = (NativeView)renderer.NativeView;
          var color = view.BackgroundColor;

          if (color != null) {

            // Phew! That was easy!         
            nativeView.BackgroundColor = UIColor.FromRGB (204, 153, 255);
          }
     }
}

Estandarización de renderizadores

Todos los renderizadores predeterminados se trasladarán a esta arquitectura, para todas las plataformas.

Registro de renderizadores

El renderizadorRegistrar existirá en el servicio de dependencia y serviceCollection.Get<IRendererRegistrar>() accederá a él, lo que permitirá controlar a qué renderizador está asociado a qué control

Interfaces en renderizadores

Concepto de mapeador

El mapeador de propiedades es responsable de desencadenar acciones en los cambios de propiedad de respuesta. Un renderizador delgado en sí mismo no se suscribe a los cambios de propiedad, pero algunas acciones declaradas se ejecutan en respuesta a los cambios.

La propiedad del mapeador de propiedades de un control es public static y puede ampliarse mediante el código de usuario.

El mapeador de propiedades no juega ningún papel en el ciclo de retroalimentación (se hace clic en el botón, se ingresa el texto)

TODO: discutir qué usar para la clave del asignador. string o object ? Sería bueno evitar la comparación de cadenas en caso de que podamos comparar referencias (en el caso de BindableProperties)

Cómo usar renderizadores personalizados heredados

Cómo usar controles de terceros según los renderizadores antiguos

Cómo complementar los renderizadores existentes

El nuevo modelo de extensibilidad para esta arquitectura se basa en el mapeador de propiedades. Cuando desee agregar soporte para una nueva propiedad, solo requiere mapear la nueva propiedad. Para que exista la propiedad, es necesario subclasificar el control, pero no lo es el renderizador.

Compatibilidad con versiones anteriores

Si queremos mantener la compatibilidad con versiones anteriores de los renderizadores personalizados existentes, o las subclases de renderizadores antiguos influirán en la arquitectura de este

Dificultad: muy alta

proposal-open slim renderer

Comentario más útil

No intente mantener la compatibilidad con versiones anteriores a toda costa. Esto es algo nuevo. No tiene que ser compatible con XF. Puedes hacer algo mejor.

Todos 56 comentarios

Los representadores de wpf de formularios de Xamarin y algunos de los representadores de Android, como ButtonRenderer, son rápidos, y sabemos lo que significa "rápido" aquí.
¿Estos renderizadores serán rápidos o no?
Gracias por adelantado.

@ysmoradi ¡Sí! Estos nuevos renderizadores seguirán el patrón de renderizador rápido (es decir, sin vista envolvente alrededor de la vista principal). Planeamos hacer esto para todas las plataformas, no solo para Android y WPF.

No intente mantener la compatibilidad con versiones anteriores a toda costa. Esto es algo nuevo. No tiene que ser compatible con XF. Puedes hacer algo mejor.

¿Por qué no hacer un marco de interfaz de usuario con su propio conjunto de controles sin ningún tipo de asignaciones y lógica de comportamiento completamente escrita en c # que se renderizaría con la biblioteca de gráficos de Skia? Como la gente usa un diseño fuertemente personalizado, no es necesario tratar de igualar las pautas de diseño de la plataforma. La única necesidad es la posibilidad de personalizaciones flexibles. Por favor corríjame si me falta algo, pero no entiendo por qué el beneficio está sobre la arquitectura del renderizador.

Con este enfoque, ¿es posible escribir un renderizador multiplataforma en lugar del renderizador específico de la plataforma? Como el control de botones de mapeo con un control nítido.

El renderizador de plataforma es un mal diseño. Como puede ver, hay muchas bibliotecas de control de xamarin que no son compatibles con UWP debido al límite de la plataforma.
Tomemos un ejemplo, la sombra en UWP. No puede obtener una sombra de esquina de un botón de esquina (por supuesto, puede cambiar la plantilla del botón para hacer esto, pero eso es otra cosa).

Sé que es muy difícil construir un render multiplataforma. Pero Flutter nos dijo que esto es factible. A largo plazo, un renderizador multiplataforma es la mejor solución.

Creo que renderizar toda la aplicación como lienzo 2d personalizado podría funcionar sin problemas para aplicaciones móviles.

Pero es posible que no funcione para aplicaciones de escritorio o aplicaciones complejas porque hay muchas acciones del usuario que deben volver a implementarse, como arrastrar y soltar, selección de texto, atajo de teclado para manipular texto, etc.

¿Por qué no hacer un marco de interfaz de usuario con su propio conjunto de controles sin ningún tipo de asignaciones y lógica de comportamiento completamente escrita en c # que se renderizaría con la biblioteca de gráficos de Skia? Como la gente usa un diseño fuertemente personalizado, no es necesario tratar de igualar las pautas de diseño de la plataforma. La única necesidad es la posibilidad de personalizaciones flexibles. Por favor corríjame si me falta algo, pero no entiendo por qué el beneficio está sobre la arquitectura del renderizador.

Creo que renderizar toda la aplicación como lienzo 2d personalizado podría funcionar sin problemas para aplicaciones móviles.

Pero es posible que no funcione para aplicaciones de escritorio o aplicaciones complejas porque hay muchas acciones del usuario que deben volver a implementarse, como arrastrar y soltar, selección de texto, atajo de teclado para manipular texto, etc.

¿Por qué no hacer un marco de interfaz de usuario con su propio conjunto de controles sin ningún tipo de asignaciones y lógica de comportamiento completamente escrita en c # que se renderizaría con la biblioteca de gráficos de Skia? Como la gente usa un diseño fuertemente personalizado, no es necesario tratar de igualar las pautas de diseño de la plataforma. La única necesidad es la posibilidad de personalizaciones flexibles. Por favor corríjame si me falta algo, pero no entiendo por qué el beneficio está sobre la arquitectura del renderizador.

Tienes toda la razón en todo esto, pero el equipo no está obligado a elegir el único enfoque. Creo que todo esto se debe a la falta de tiempo. Quiero decir que solo necesitan lanzar un marco de interfaz de usuario totalmente multiplataforma "completamente nuevo" en un año junto con .net 6. Y es mucho menos arriesgado tomar como base un buen marco antiguo probado por el tiempo. Está bien y debería estarlo. Pero creo que, en mucho tiempo, el renderizado personalizado de lienzos 2d tiene muchos más beneficios y realmente merece ser llamado "multiplataforma". Los formularios de Xamarin son algo realmente bueno y tienen un gran progreso para hoy. Pero es hora de seguir adelante. Los equipos de Microsoft y xamarin tienen ingenieros muy inteligentes y probablemente estén considerando tal enfoque o tal vez incluso tengan algunas conexiones con http://avaloniaui.net/ como una carta de triunfo.

¿Por qué no hacer un marco de interfaz de usuario con su propio conjunto de controles sin ningún tipo de asignaciones y lógica de comportamiento completamente escrita en c # que se renderizaría con la biblioteca de gráficos de Skia? Como la gente usa un diseño fuertemente personalizado, no es necesario tratar de igualar las pautas de diseño de la plataforma. La única necesidad es la posibilidad de personalizaciones flexibles. Por favor corríjame si me falta algo, pero no entiendo por qué el beneficio está sobre la arquitectura del renderizador.

Podría ser genial tener el 4º render gris predeterminado para que los desarrolladores de Skia lo cambien al 100% para ofrecer un diseño rico,
Para la parte posterior, la peinabilidad dejaría esos 3 como están, pero agregue "dibuje usted mismo, querido desarrollador" _skia_render y asuma el 90% de la responsabilidad del desarrollador.

Si se va a mantener el concepto de renderizadores, ¿se puede pensar en eliminar el puente entre el código de IU compartido y los renderizadores a través de INotifyPropertyChanged y controladores de eventos? es decir

  • En lugar de establecer una _property_ en el control compartido y propagar PropertyChanged evento directamente en el renderizador de la plataforma?
  • En lugar de llamar a un _method_ en el control compartido y un evento que es disparado y manejado por el renderizador, ¿puede el método ser mapeado e involucrado directamente en el renderizador de la plataforma?

INotifyPropertyChanged es excelente para el diseño de MVVM y los modelos de vista de pares sueltos, pero siempre se ha sentido torpe como mecanismo de puente entre el código de interfaz de usuario compartido y los renderizadores de plataforma. Esto, a su vez, conduciría a un mejor rendimiento, menos 'charla' entre la interfaz de usuario compartida y la capa de renderizado y una mejor experiencia de desarrollador.

Esto es largo pero vale la pena ver algo de "béisbol interno" en Maui.
https://www.youtube.com/watch?v=_MGh3xipWm4

Parece que la arquitectura de Maui admitirá tanto los controles representados por la plataforma como los controles dibujados en el lienzo, y además, el noble @Clancey continuará trabajando en un conjunto de renderizado basado en skia para Maui que no solo funcionará en el estilo MVU. de Maui sino también para el patrón MVVM.

A primera vista, Maui parecía un cambio de marca de Forms, pero en una inspección más cercana es una reestructuración de la arquitectura de Forms para hacer que sus capas estén más débilmente acopladas y, por lo tanto, respalden muchas de las cosas que estamos preguntando en este hilo. Tiempos divertidos por delante.

Esto está un poco fuera del tema, pero es algo que quería preguntar solo por su relevancia para esto exactamente:

¿Cómo funciona la memoria con SKCanvasView (o Skia en general)? ¿Cada uno ocupa siempre memoria proporcional a su tamaño? ¿Esto cambia si se superpone a otros?

Si, por ejemplo, tuviera un control de degradado (renderizador escrito en Skia) y por encima de eso tuviera un botón semitransparente (renderizador escrito en Skia), ¿ocuparía el doble de memoria, o el contexto gráfico se comparte de alguna manera? ¿Qué tal si los controles de Skia se superponen a los controles que no son de Skia?

Antes he considerado implementar algunos controles gráficos sofisticados en Forms usando Skia, pero no entender cómo funciona la memoria siempre me ha preocupado tanto que no lo he hecho.

@GalaxiaGuy Creo que usar un control skia superpuesto a un control que no es skia, al igual que un control winform alojado en un control wpf. Puede hacer esto, pero no lo mejor.
Si tiene dos controles representados por SKCanvasView , el contexto de gráficos no se compartirá. La mejor manera es componer los dos renderizados y dibujarlos en un solo lienzo.
En mi prueba, el rendimiento de SkiaSharp no es tan malo si solo haces algunas cosas estáticas. Y trato de hacer algunas animaciones, el uso de la CPU es un poco alto en mi computadora portátil.

¿Por qué tanta gente está obsesionada con Skia? Una buena especificación de renderizado sería independiente del motor de renderizado utilizado en el nivel bajo. Si un renderizador de plataforma en particular quiere usar Skia (o Direct2D u OpenGL o lo que sea), eso no debería ser algo de lo que la capa de aplicación deba preocuparse.

La mayor promesa de XAML con WPF hace mucho tiempo fue la idea de Lookless Controls, donde los gráficos reales de los controles se diferían a las plantillas. Xamarin Forms usó XAML sin esta capacidad, y este fue su punto más débil, solo años después, parcialmente arreglado por la especificación de dibujo.
No creo que necesitemos otro conjunto de interfaces y abstracciones sobre los componentes existentes en varios sistemas operativos y marcos, sino controles verdaderamente sin apariencia basados ​​en XAML, con plantillas visuales primitivas

La mayor promesa de XAML con WPF hace mucho tiempo fue la idea de Lookless Controls, donde los gráficos reales de los controles se diferían a las plantillas. Xamarin Forms usó XAML sin esta capacidad, y este fue su punto más débil, solo años después, parcialmente arreglado por la especificación de dibujo.

¡Acordado! Y realmente necesita una cantidad muy pequeña de primitivas de renderizado para lograr probablemente el 99% de todo lo que necesita una aplicación:

  • Bordes (incluidas opciones para sombra paralela y bordes redondeados)
  • Líneas / Elipses / Rectángulos
  • Representación de texto sin formato
  • Entrada de texto sin formato
  • Representación de texto enriquecido
  • Entrada de texto enriquecido
  • Representación HTML
  • Presentador de imagen
  • Presentador de audio / video
  • Pinceles de degradado sólido y lineal / radial

Las plataformas de renderizado XF se han vuelto tan infladas porque cada vez que se agrega un nuevo tipo de control al marco, se hace con un nuevo renderizador en lugar de construir sobre las primitivas existentes dentro del marco.

Sí, se tendría que mover mucha más lógica a la capa de marco, siendo el más desafiante cuando se trata de controles de elementos ( VirtualizingStackPanel es fundamental para tener un visor de elementos escalable, pero que yo sepa, nunca se ha portado de manera efectiva fuera de WPF porque es muy complejo). Pero dado que WPF es de código abierto, mucho de eso se puede transferir a MAUI ahora y creo que este es finalmente el momento en que eso debería comenzar a suceder.

Realmente necesita una cantidad muy pequeña de primitivas de renderizado para lograr probablemente el 99% de todo lo que necesita una aplicación.

La plataforma Uno está utilizando este enfoque.

@velocitysystems

En lugar de establecer una propiedad en el control compartido y propagar un evento PropertyChanged, ¿se puede asignar la propiedad y establecerla directamente en el renderizador de la plataforma?

Ese también es un gran objetivo de este cambio. Una vez que estemos del otro lado de estos cambios, los renderizadores no tendrán idea de lo que significa BindableObject o INPC

Ese también es un gran objetivo de este cambio. Una vez que estemos del otro lado de estos cambios, los renderizadores no tendrán idea de lo que significa BindableObject o INPC

Entonces, un método en el renderizador será invocado por el marco cada vez que cambie un valor BindableProperty en lugar de que el renderizador tenga que suscribirse a PropertyChanged ?

@legistek derecho

Esto básicamente invierte las dependencias

Por lo tanto, los renderizadores solo funcionarán contra IButton.

Y luego System.Maui agregará una referencia al proyecto de renderizadores opuesto a cómo los renderizadores tienen referencias a Xamarin.Forms.Core en este momento.

Revisé un pico que tenemos aquí
https://github.com/dotnet/maui/pull/66

Para que puedas ver cómo se vería esto

Estaré haciendo una transmisión hoy a las 3:30 PDT (hora del Pacífico) con

https://www.twitch.tv/microsoftdeveloper

¡Únete a nosotros! ¡Echale un vistazo! ¡Y haz preguntas!

@PureWeen Desafortunadamente, me lo perdí. ¿Habrá una grabación disponible en YouTube?

Ese también es un gran objetivo de este cambio. Una vez que estemos del otro lado de estos cambios, los renderizadores no tendrán idea de lo que significa BindableObject o INPC.

Eso es enorme, una mejora sustancial real. Sin duda, también con el traslado a Maui, el complejo modelo de herencia utilizado en muchos de los renderizadores se eliminará en favor de un enfoque más compositivo.

Pasando a la revisión # 66 hoy.

Mirando el n. ° 66, es bueno ver que los renderizadores delgados se construyen e invocan con 'cebo y cambio' en lugar de usar la reflexión. Solo algunos pensamientos:

  • ¿Los renderizadores Slim abordarán los problemas de GC, especialmente en Android, donde hay una discrepancia entre el ciclo de vida de control administrado y nativo? Esto es especialmente notable en las vistas secundarias en diseños virtualizados que conducen al temido ObjectDisposedException .
  • ¿Los renderizadores Slim conducirán a la depreciación de Effect ? Los efectos pueden ser útiles, pero en última instancia, agregan complejidad y otro potencial de latencia al ciclo de vida del diseño.
  • ¿Cómo funcionaría una propiedad 'bidireccional' con el nuevo diseño de renderizador? Por ejemplo, digamos que tengo una propiedad MediaElement con una propiedad Position ( TimeSpan ). Setter actualiza la posición actual y el captador recupera la posición actual del reproductor multimedia nativo, es decir, AVPlayer , MediaPlayer . ¿Existe un diseño para mapear un _getter_ con renderizadores delgados?

¿Los renderizadores Slim abordarán los problemas de GC, especialmente en Android, donde hay una discrepancia entre el ciclo de vida de control administrado y nativo? Esto es especialmente notable en las vistas secundarias en diseños virtualizados que conducen a la temida ObjectDisposedException.

¡Tenemos algunas ideas aquí! Queremos reelaborar un poco las estrategias de eliminación para, con suerte, resolver la mayoría, si no todas, las excepciones de ODE. En este momento, desechamos todo de forma súper agresiva en Android / iOS, pero estoy bastante seguro de que podemos confiar en el GC para hacer lo que hace el GC. Si solo nos aseguramos de eliminar la referencia de todo y dejamos que el GC haga el trabajo, eso debería ayudar en muchos de estos casos

¿Los renderizadores Slim conducirán a la desaprobación de Effect? Los efectos pueden ser útiles, pero en última instancia, agregan complejidad y otro potencial de latencia al ciclo de vida del diseño.

Definitivamente es bueno analizar esto a medida que evolucionamos esta idea. Una vez que alcancemos un diseño final para todo esto, veremos los efectos. Pero, sí, pude ver que los efectos están obsoletos, ya que están pensados ​​como una forma de aprovechar los elementos nativos sin tener que usar el renderizador completo. Mappers básicamente efectos obsoletos

¿Cómo funcionaría una propiedad 'bidireccional' con el nuevo diseño de renderizador? Por ejemplo, digamos que tengo un MediaElement con una propiedad Position (TimeSpan). Setter actualiza la posición actual y el captador recupera la posición actual del reproductor multimedia nativo, es decir, AVPlayer, MediaPlayer. ¿Existe un diseño para mapear un captador con renderizadores delgados?

Todavía estamos trabajando un poco en esto. Corrígeme si me equivoco https://github.com/dotnet/maui/blob/slim-renderers/Maui.Core/PropertyMapper.cs#L91

¿Cómo funcionaría una propiedad 'bidireccional' con el nuevo diseño de renderizador? Por ejemplo, digamos que tengo un MediaElement con una propiedad Position (TimeSpan). Setter actualiza la posición actual y el captador recupera la posición actual del reproductor multimedia nativo, es decir, AVPlayer, MediaPlayer. ¿Existe un diseño para mapear un captador con renderizadores delgados?

Todavía estamos trabajando un poco en esto. Corrígeme si me equivoco https://github.com/dotnet/maui/blob/slim-renderers/Maui.Core/PropertyMapper.cs#L91

No exactamente. Así que ActionMapper es lo mismo que PropertyMapper con la excepción de que no se llaman durante la fase SetElement. Entonces, para cosas como WebView, GoBack. No desea llamar a eso durante la inicialización, pero aún es algo que necesita para comunicarse con el Renderer.

Ya admitimos el mapeo bidireccional. es decir, entrada. Cuando el valor del texto aparece en la entrada. IEntry tiene un string Text {get;set;} y simplemente establecemos el valor. Entonces, para los elementos multimedia, tienes 2 opciones. Uno es simplemente retrasar la posición / tiempo cuando cambia. Si desea convertirlo en algo, consulte en su lugar. Usted puede hacer eso. Las vistas de xplat tienen acceso al renderizador. view.Renderer.NativeView as NativeMediaView ¡Ahora puede realizar las propiedades que desee!

Aquí hay algunos videos de nuestras transmisiones durante Build

@Clancey 's here será más profundo
https://www.youtube.com/watch?v=_MGh3xipWm4

Los toco un poco aquí con David
https://www.youtube.com/watch?v=lAmwjfZY1IM

¿Cómo funcionaría una propiedad 'bidireccional' con el nuevo diseño de renderizador? Por ejemplo, digamos que tengo un MediaElement con una propiedad Position (TimeSpan). Setter actualiza la posición actual y el captador recupera la posición actual del reproductor multimedia nativo, es decir, AVPlayer, MediaPlayer. ¿Existe un diseño para mapear un captador con renderizadores delgados?

Todavía estamos trabajando un poco en esto. Corrígeme si me equivoco https://github.com/dotnet/maui/blob/slim-renderers/Maui.Core/PropertyMapper.cs#L91

No exactamente. Así que ActionMapper es lo mismo que PropertyMapper con la excepción de que no se llaman durante la fase SetElement. Entonces, para cosas como WebView, GoBack. No desea llamar a eso durante la inicialización, pero aún es algo que necesita para comunicarse con el Renderer.

Ya admitimos el mapeo bidireccional. es decir, entrada. Cuando el valor del texto aparece en la entrada. IEntry tiene un string Text {get;set;} y simplemente establecemos el valor. Entonces, para los elementos multimedia, tienes 2 opciones. Uno es simplemente retrasar la posición / tiempo cuando cambia. Si desea convertirlo en algo, consulte en su lugar. Usted puede hacer eso. Las vistas de xplat tienen acceso al renderizador. view.Renderer.NativeView as NativeMediaView ¡Ahora puede realizar las propiedades que desee!

Otra cosa a considerar aquí son los registros que vienen en C # 9. La especialidad es que son inmutables y tienen acceso a la propiedad init . Entonces, para hacerlos utilizables en un enlace bidireccional, el asignador debe poder devolver una nueva instancia utilizando el operador with .

Realmente espero que las vistas se puedan vincular a los registros, porque esto facilita mucho las cosas cuando se trata de MVVM puro o incluso MVU puro.

Pregunta: el diagrama que publicó tiene los controles de Windows representados por Windows.UI.* , pero según tengo entendido, ahora está en proceso de quedar obsoleto y no verá ninguna actualización: todas las mejoras en los renders de diseño fluidos son que tiene lugar en Microsoft.UI.* como parte del proyecto WinUI. ¿Puedes comentar sobre esto?

Creo que el mapeo a controles nativos es un gran error, esta es la parte terrible de Xamarin Forms, no puedes hacer diseños únicos y hermosos fácilmente, tenías que seguir el concepto y enfoque de los controles WPF y Flutter sin apariencias con un render. motor escrito en C ++ usando OpenGL / DirectX / Metal, ya que esto facilita la portabilidad, rendimiento y flexibilidad además de no depender de estructuras de plataforma que están en continuo cambio.

El tema está aquí para hablar de los nuevos Mapeadores de Arquitectura / Propiedad. No contra lo que trazan. Solo para repetir. Slim Render Architecture para nativos no significa que nunca lo haremos y nunca podremos hacer un enfoque de control dibujado. Pero esto nos permite mezclar y hacer coincidir controles nativos vs no nativos donde si va puramente dibujado, es más difícil. Planeo seguir trabajando en los controles basados ​​en Skia que siguen la misma arquitectura de renderizado delgado, incluida la capa de dibujo. https://github.com/Clancey/Comet/tree/dev/src/Comet.Skia/Handlers.

Mi 2 ¢ en esta cosa del renderizador (que admito que no entiendo del todo, TBH):

Tenía una idea sobre cómo podríamos implementar tanto controles renderizados por plataforma (por ejemplo, envolviendo UIButton) _y_ controles sin apariencia (a la WPF) usando la misma clase de control. Honestamente, es bastante simple: haga que la clase Maui Button use una plantilla de control y elimine todo el código de renderizado específico de la plataforma. Luego, proporcione una plantilla en la caja para Button que contenga un ButtonRenderer. ButtonRenderer es lo que habla con Cocoa / UIKit / UWP / etc, con código específico de la plataforma para cada kit de herramientas de IU, y la clase Button utilizada por el desarrollador de la aplicación simplemente le reenvía sus propiedades. Si el usuario quiere usar un botón personalizado, entonces simplemente puede anular la plantilla y usar clases de dibujo (lo que sea que parezca) en lugar del ButtonRenderer, tal como lo hacemos en WPF. Honestamente, no sé si esto ya es posible (o incluso si ya se usa) en Maui hoy, ya que nunca me tomé el tiempo para entender Xamarin.Forms tan profundamente como entiendo WPF.

¡Dime que piensas!

Estoy tratando de entender qué significarían los renderizadores Slim para diferentes modelos de aplicaciones (MVVM, MVU, ...).

El diagrama inicial parece indicar que cada modelo de aplicación diferente tendrá su propio conjunto de renderizadores.
Pero en mi opinión, sería mejor tener un conjunto de renderizadores por tipo de renderizado (por ejemplo, renderizar en controles nativos como XF, renderizar en lienzo, etc.).
El renderizador no necesita conocer el modelo de la aplicación, solo necesita saber qué valor se asigna a qué propiedad para poder aplicar la actualización correcta al control subyacente.
Solo IButton se implementará de manera diferente para cada modelo de aplicación y será responsable de llamar a las funciones asignadas de su renderizador.

Esto es importante porque las bibliotecas de terceros como Fabulous no tendrán la mano de obra de Microsoft para implementar (con todos los errores que vienen con él) todos los renderizadores apropiados para cada control en cada plataforma.

Otro punto es: las interfaces de control ( IButton ) deben ser solo captadores para ser consumidas por los renderizadores.
Los renderizadores no establecen valores y cada modelo de aplicación dará forma a los controles de manera diferente (BindableProperty, BindingObject, etc.).
Por ejemplo, Fabulous tendrá vistas inmutables. Solo internamente, estará autorizado a establecer la mutación en la instancia de IButton .

De esa manera, Fabulous podría usar directamente la interfaz IButton como una vista de lector sobre su diccionario interno para que los renderizadores puedan funcionar.

// This is the type used by our users, sort of a Builder that return a new instance each time
// and append the set value to an internal list 
public struct Button
{
     public Button Text(string value) => (...);

     internal ReadOnlyDictionary<string, obj> Build() { ... }
}

// This will be an implementation of IButton, hidden from our users
internal class FabulousButton : IButton
{
    private ReadOnlyDictionary<string, obj> _properties;
    FabulousButton(ReadOnlyDictionary<string, obj> properties)
    {
        _properties = properties;
    }

    void Update(ReadOnlyDictionary<string, obj> properties)
    {
        var previousProperties = _properties;
        _properties = properties;

        // Diffing of the 2 dictionaries to determine what changed
        // and which mapped functions inside the renderer should be called
        (...)
    }

    public string Text => _properties["Text"];
}

@TimLariviere Todo lo que dijiste es cómo funciona :-)

El dibujo es confuso en cuanto a los renderizadores.

La única parte de esto de la que deberás preocuparte es el botón fabuloso y luego nos encargaremos de todo lo demás.

En su mayor parte, las interfaces son de solo lectura

Esta es la interfaz utilizada por el botón
https://github.com/dotnet/maui/blob/slim-renderer-samples/Maui.Core/Views/IText.cs

Todo lo que realmente depende de usted (en lo que respecta a los renderizadores) es indicarle al renderizador que debe volver a consumir el IButton

Por ejemplo, en la versión BindableObject de todo esto, solo llamamos al método updateproperty del Renderer aquí

https://github.com/dotnet/maui/blob/slim-renderer-samples/System.Maui.Core/VisualElement.cs#L1132

En algún momento (¿pronto?) @Clancey tendrá una versión pública de Comet que puedes ver para ver cómo lo está haciendo.

Yo chequearía
https://github.com/dotnet/maui/blob/slim-renderer-samples

Probablemente puedas agregar tu propio Fabulous. Dirígete a eso y luego comienza a agregar implementaciones a las interfaces

@PureWeen Oh genial. Gracias, intentaré jugar con las muestras que vinculó para ver cómo va.

@PureWeen @Clancey Estoy seguro de que el equipo de Maui estará en todo esto, pero por favor, ¿pueden los nuevos renderizadores Slim favorecer la composición sobre la herencia? La herencia es útil, pero desafortunadamente en XF ha hecho que algunas de las jerarquías de renderizado sean increíblemente complejas y difíciles de mantener.

@PureWeen
Esta URL
https://github.com/dotnet/maui/blob/slim-renderer-samples

da 404, ¿es privado?

@ Aleatorio

https://github.com/dotnet/maui/tree/slim-renderer-samples

@velocitysystems

Estoy seguro de que el equipo de Maui estará en todo esto, pero por favor, ¿pueden los nuevos renderizadores Slim favorecer la composición sobre la herencia? La herencia es útil, pero desafortunadamente en XF ha hecho que algunas de las jerarquías de renderizado sean increíblemente complejas y difíciles de mantener.

Así es como se construyen. Hay una clase base muy delgada que simplemente hereda directamente de los buenos System.Object

https://github.com/dotnet/maui/blob/slim-renderer-samples/Maui.Core/Renderers/View/AbstractViewRenderer.Android.cs

Y no tiene lazos nativos.

A partir de ahí, todo se define a través de lo que básicamente es un Diccionario.

https://github.com/dotnet/maui/blob/slim-renderer-samples/Maui.Core/Renderers/View/AbstractViewRenderer.cs#L31

Que básicamente opera como un decorador.

Puede decorar mapeadores con mapeadores adicionales y puede inyectar sus propias funciones, etc.

Nuestro objetivo es que el 95 por ciento de los escenarios de los usuarios se cubran simplemente agregando su propio Func al mapeador o simplemente accediendo a los elementos nativos directamente, ya que todo será multisectorial.

@PureWeen ¿Cuál sería el canal más apropiado para discutir la implementación de esos renderizadores delgados en su muestra?

Tengo algunas preguntas como:

  • ¿Se definirán los valores predeterminados en un lugar centralizado? En XF, actualmente se definen al crear los campos BindableProperty, pero estos no estarán presentes según el modelo de la aplicación.
  • ¿La clase Aplicación también se convertirá (parcialmente) en una interfaz? Define muchos comportamientos de la interfaz de usuario (recursos, menú, página principal) y sería genial implementarlo de manera diferente.
  • ¿Se extraerá Measure / Arrange / etc de las interfaces de control? No creo que realmente tenga sentido que los modelos de aplicaciones los implementen de manera diferente.

¿Se definirán los valores predeterminados en un lugar centralizado? En XF, actualmente se definen al crear los campos BindableProperty, pero estos no estarán presentes según el modelo de la aplicación.

Esta es una buena pregunta. @Clancey ? No estoy seguro de si hemos definido esto todavía. Hay una fase de configuración inicial en la que se llama a todos los mapeadores con el valor actual de las propiedades (valor predeterminado), pero no estoy seguro de si aún tenemos un plan para los valores predeterminados y cómo se generalizarán.

¿La clase Aplicación también se convertirá (parcialmente) en una interfaz? Define muchos comportamientos de la interfaz de usuario (recursos, menú, página principal) y sería genial implementarlo de manera diferente.

¡Sí! Esperamos colapsar todas las clases de aplicación (nativa y xplat) en una sola clase de aplicación. ¿Por qué preguntas sobre esto? Solo tengo curiosidad por saber tu caso de uso aquí para que podamos asegurarnos de abordar

¿Se extraerá Measure / Arrange / etc de las interfaces de control? No creo que realmente tenga sentido que los modelos de aplicaciones los implementen de manera diferente.

En este punto ese es el plan. La idea será extraer todo nuestro código de diseño para que nada dependa de BindableObject / Property. De esta manera, Blazor / Comet / other puede usar un StackLayout y el resultado será el mismo.

¿Por qué preguntas sobre esto? Solo tengo curiosidad por saber tu caso de uso aquí para que podamos asegurarnos de abordar

No estoy del todo seguro de lo que querría todavía. Pero en Fabulous, actualmente no tenemos una buena historia para definir estilos globales y menú principal (como para macOS). Dado que permitimos que nuestros usuarios subclasifiquen la clase de aplicación ellos mismos, básicamente les decimos que definan recursos / menú como lo harían en el clásico Xamarin.Forms.

Entonces, idealmente, todas las propiedades de la aplicación relacionadas con la interfaz de usuario también serían parte de la vista, de esa manera también podríamos aplicar nuestra lógica de diferencia de vista.

Algo como eso

public interface IAppRoot
{
    IEnumerable<object> Resources { get; }
    IMenu MainMenu { get; }
    IPage MainPage { get; }
}

public class Application
{
    /// Bootstrapping and other logic of MAUI

   public IAppRoot Root { get; set; } // Replaces MainPage, which is typed for pages only
}

@PureWeen Otra pregunta: ¿Quién será responsable de desencadenar eventos como TextChanged , Toggled , etc.? ¿Los controles o los renderizadores?

Una cosa que creo que simplificaría enormemente la implementación de otros modelos de aplicaciones es la posibilidad de no activar eventos de cambio de estado cuando los cambios son programáticos.

Por ejemplo, hoy, TextChanged en Entry se activa tanto cuando el usuario escribe algo como cuando hacemos MyEntry.Text = "New value"; .
Creo que reaccionar a un cambio programático no es realmente útil e implícito, lo cual es malo para razonar sobre el código.

Además, esto condujo a un bucle infinito en Android porque la plataforma activa sus eventos con un ligero retraso y obligó a Fabulous a desincronizarse sin posibilidad de volver.
La única solución que encontramos fue cancelar primero la suscripción del evento antes de establecer el valor y luego volver a suscribirse ...

Una pregunta curiosa. Cuando MAUI es independiente de la arquitectura, ¿por qué los controles se nombran por nombres de arquitectura? Por ejemplo, en el diagrama de arriba tenemos a Maui. Mvvm .ButtonRenderer.Android? @PureWeen @Clancey

XF tiene algo llamado diseños comprimidos (que tiene errores)
¿Tenemos tal cosa (¡sin errores, seguro!) En MAUI?

Veo cómo reacciona la gente en este hilo sobre el enfoque de Flutter / Skia para renderizar la interfaz de usuario y estoy mayormente de acuerdo con ellos.
Estoy muy contento de que MAUI potencialmente tenga soporte para controles y representaciones personalizados / no nativos.
Sin embargo, debo decir que la capacidad de trabajar con IU nativa asegura el marco en el lado político de las cosas.
Y sí, me refiero a Apple. Debido a las últimas noticias, no me sorprendería que en algún momento y por alguna razón, el uso de Flutter fuera considerado como 'explotar funciones no documentadas / restringidas' o 'no seguir las pautas de la interfaz de usuario de Apple', etc.

Veo cómo reacciona la gente en este hilo sobre el enfoque de Flutter / Skia para renderizar la interfaz de usuario y estoy mayormente de acuerdo con ellos.
Estoy muy contento de que en MAUI potencialmente tenga soporte para controles y renderizados personalizados / no nativos.
Sin embargo, debo decir que la capacidad de trabajar con IU nativa asegura el marco en el lado político de las cosas.
Y sí, me refiero a Apple. Debido a las últimas noticias, no me sorprendería que en algún momento y por alguna razón, el uso de Flutter fuera considerado como 'explotar funciones no documentadas / restringidas' o 'no seguir las pautas de la interfaz de usuario de Apple', etc.

Si MAUI es compatible con Web (como Flitter), siempre podemos renderizar en WebView.
Es poco probable que Apple se atreva a bloquear las aplicaciones basadas en WebView, porque algunas grandes empresas están representadas en AppStore solo a través de WebView.

Veo cómo reacciona la gente en este hilo sobre el enfoque de Flutter / Skia para renderizar la interfaz de usuario y estoy mayormente de acuerdo con ellos.
Estoy muy contento de que en MAUI potencialmente tenga soporte para controles y renderizados personalizados / no nativos.
Sin embargo, debo decir que la capacidad de trabajar con IU nativa asegura el marco en el lado político de las cosas.
Y sí, me refiero a Apple. Debido a las últimas noticias, no me sorprendería que en algún momento y por alguna razón, el uso de Flutter fuera considerado como 'explotar funciones no documentadas / restringidas' o 'no seguir las pautas de la interfaz de usuario de Apple', etc.

Si MAUI es compatible con Web (como Flitter), siempre podemos renderizar en WebView.
Es poco probable que Apple se atreva a bloquear las aplicaciones basadas en WebView, porque algunas grandes empresas están representadas en AppStore solo a través de WebView.

eso ya está en contra de las pautas: https://developer.apple.com/app-store/review/guidelines/#minimum -functionality

Después de haber leído un poco lo que parece ser este nuevo mundo de MAUI, por favor, por el amor de todo lo sagrado, haga una escritura una vez, use en todas partes el motor de renderizado como SKIA u otro motor de renderizado multiplataforma, teniendo que implementar un motor de renderizado personalizado. La interfaz de usuario en cada plataforma, como en Xamarin Forms, se siente vieja y como si fuera una solución creada en el séptimo círculo del infierno.

si la compatibilidad con versiones anteriores es imprescindible "simplemente" haga que el soporte de renderizado nuevo y moderno sea una forma de renderizar componentes más antiguos, he visto que otras plataformas tienen una buena solución para esto, la más reciente que he usado es en el motor de interfaz de usuario de la unidad donde el nuevo UXML moderno tiene un IMGUI Render.

@ jackie0100
yo estoy totalmente de acuerdo

tener que implementar una interfaz de usuario personalizada en cada plataforma como en Xamarin Forms se siente viejo y como si fuera una solución creada en el séptimo círculo del infierno.

En cuanto a la implementación del renderizador, ¿qué pasa con la idea de un IView ES una vista nativa (en lugar de un IView TIENE una vista nativa)? es decir, herencia en lugar de composición? Esto conduciría a la arquitectura más rápida y ágil con absolutamente cero "gastos generales de formularios". Básicamente, está trabajando con vistas nativas puras y solo una interfaz común.

Luego, podría hacer cosas como, en la tierra de iOS, simplemente convertir su vista para que sea una UIView y agregarle un hijo nativo (del tipo que desee) porque una IView es una UIView. De manera similar, si desea hacer una 'incrustación nativa', es fácil porque una IView es una UIView, puede agregar una de sus IViews a su vista nativa porque son lo mismo. Esto permitiría enormemente la interoperabilidad nativa <-> maui, y con el mayor nivel de rendimiento y el menor consumo de memoria.

Tengo ganas de hacer un prototipo de esto yo mismo. Quizás un proyecto de fin de semana / noche ...

image

Si MAUI es compatible con Web (como Flitter), siempre podemos renderizar en WebView.

No necesita WebView en iOS: puede renderizar directamente en OpenGL o Metal .

O use Skia con OpenGL o Metal debajo.

La capacidad de trabajar con la interfaz de usuario nativa asegura el marco en el lado político de las cosas. [Manzana]

En algún momento, Apple eliminó de su política escrita el requisito de utilizar widgets de interfaz de usuario nativos. No veo ninguna forma práctica en que revertirían la política y volverían a ser restrictivas.

Independientemente, tener la capacidad de trabajar con controles nativos es una buena opción.

@legistek

¿Por qué tanta gente está obsesionada con Skia? Una buena especificación de renderizado sería independiente del motor de renderizado ...

Si bien estoy totalmente de acuerdo con ser "agnóstico", hay una cantidad de detalles que deben implementarse para renderizar cualquier interfaz de usuario interactiva, si va directamente a OpenGL / Metal / Vulkan / cualquier motor de renderizado de bajo nivel. La gente está obsesionada con Skia porque es una capa intermedia efectiva entre las preocupaciones de la interfaz de usuario de la aplicación y el motor de renderizado real: Skia maneja _mucho_ de lo que tendría que diseñarse e implementarse, si todo lo que tienes es puro metal. No hay razón para reinventar este trabajo. Si bien no debería ser el _ único_ objetivo, es un objetivo extremadamente valioso y maduro, que hará que sea mucho más fácil, digamos, pasar de OpenGL a Vulkan.

También sospecho que apuntar a Skia sería mucho menos engorroso que el mantenimiento de Xamarin Forms de dos jerarquías de widgets paralelas: los widgets multiplataforma y los widgets nativos.

Skia podría incluso acelerar el día en que .Net Maui tenga un alto rendimiento en el navegador . Nuevamente, porque en lugar de construir desde un nivel bajo, de renderizado, está comenzando con una abstracción de nivel medio apropiada. Eso sería una gran victoria.

Hola a todos, no lo olviden:
https://github.com/dotnet/maui/discussions/103

Después de haber visto los videos recientes de maui, a menos que me equivoque, parece que ha habido una tendencia a tener controles más estilizados con el control nativo superpuesto con el dibujo realizado en el lado independiente de la plataforma. Ya sea que se trate de skia o algún tipo de interoperabilidad por lotes con el dibujo de lienzo nativo, ¡espero que se siga este enfoque! Irónicamente, el modelo de renderizador de la plataforma XF siempre ha perjudicado más a las plataformas de interfaz de usuario de Microsoft, siendo las menos utilizadas.

También dejaría abierta la capacidad para que un control no tenga explícitamente un componente nativo y para que el compositor de diseño detecte esto, podría permitir una reducción automatizada en las vistas nativas creadas (es decir, si todos los controles en un contenedor son etiquetas maui dibujadas con skia, podría convertir el contenedor en un SkView y simplemente llamar a la operación de dibujo en los controles secundarios de la etiqueta), en Android, lo que aumentaría la velocidad en cosas como elementos de lista que tienen muchas imágenes + controles de texto, por ejemplo.

No entiendo qué es un renderizador.
Si el programa para absorber las diferencias visuales del objetivo se llama renderizador, debería ser absorbido por Xamarin y MAUI por completo. De lo contrario, creo que es un Xamarin y MAUI sin terminar. Y nunca se completará.
Creo que la programación de aplicaciones debería ser más independiente de las diferencias en el entorno de destino.

No entiendo qué es un renderizador.
Si el programa para absorber las diferencias visuales del destino se llama renderizador, Xamarin y MAUI deberían absorberlo por completo. Si no, creo que es un Xamarin y MAUI sin terminar. Y nunca se completará.
Creo que la programación de aplicaciones debería ser más independiente de las diferencias en el entorno de destino.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

Yaroslav08 picture Yaroslav08  ·  6Comentarios

handicraftsman picture handicraftsman  ·  4Comentarios

probonopd picture probonopd  ·  50Comentarios

UriHerrera picture UriHerrera  ·  3Comentarios

jsuarezruiz picture jsuarezruiz  ·  6Comentarios