Maui: [Especificação] Arquitetura Slim Renderer

Criado em 19 mai. 2020  ·  56Comentários  ·  Fonte: dotnet/maui

AVISO: esta especificação ainda é um WIP, ainda estamos testando esse conceito

Descrição

A arquitetura de renderizadores Slim se beneficia de recursos de múltiplos alvos e de projeto único.

Exemplo

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);
          }
     }
}

Padronização de renderizadores

Todos os renderizadores padrão serão portados para esta arquitetura, para todas as plataformas

Cadastro de renderizadores

O rendererRegistrar existirá no serviço de dependência e será acessado por serviceCollection.Get<IRendererRegistrar>() , permitindo controlar a qual renderizador está associado a qual controle

Interfaces em renderizadores

Conceito de mapeador

O mapeador de propriedades é responsável por disparar ações nas alterações das propriedades de resposta. O próprio renderizador slim não se inscreve nas alterações de propriedade, mas algumas ações declaradas são executadas em resposta às alterações.

A propriedade do mapeador de propriedades de um controle é public static e pode ser estendida pelo código do usuário.

O mapeador de propriedades não desempenha nenhum papel no ciclo de feedback (botão clicado, texto inserido)

TODO: discuta o que usar para a chave do mapeador. string ou object ? Seria bom evitar a comparação de strings no caso de podermos comparar referências (no caso de BindableProperties)

Como usar renderizadores personalizados legados

Como usar controles de terceiros, dependendo de renderizadores antigos

Como complementar os renderizadores existentes

O novo modelo de extensibilidade para esta arquitetura é baseado no mapeador de propriedades. Quando você deseja adicionar suporte para uma nova propriedade, requer apenas o mapeamento da nova propriedade. Para que a propriedade exista, a subclasse do controle é necessária, mas a subclasse do renderizador não.

Compatibilidade com versões anteriores

Quer queiramos manter a compatibilidade com versões anteriores de renderizadores personalizados existentes, ou subclasses de renderizadores antigos influenciarão a arquitetura deste

Dificuldade: muito alta

proposal-open slim renderer

Comentários muito úteis

Por favor, não tente permanecer compatível com as versões anteriores a todo custo. Isso é algo novo. Não precisa ser compatível com o XF. Você pode fazer algo melhor.

Todos 56 comentários

O Xamarin forma renderizadores wpf e alguns renderizadores Android, como ButtonRenderer, são rápidos, e sabemos o que "rápido" significa aqui.
Esses renderizadores serão rápidos ou não?
Desde já, obrigado.

@ysmoradi Sim! Esses novos renderizadores seguirão o padrão de renderização rápida (ou seja, sem visualização do wrapper ao redor da visualização principal). Planejamos fazer isso para todas as plataformas, não apenas para Android e WPF.

Por favor, não tente permanecer compatível com as versões anteriores a todo custo. Isso é algo novo. Não precisa ser compatível com o XF. Você pode fazer algo melhor.

Por que não fazer a estrutura de interface do usuário com o próprio conjunto de controles sem qualquer tipo de mapeamento e lógica comportamental totalmente escrita em c # que seria renderizada com a biblioteca gráfica do Skia? Como as pessoas usam um design fortemente customizado, não há necessidade de tentar corresponder às diretrizes de design da plataforma. A única necessidade é a possibilidade de personalizações flexíveis. Por favor, corrija-me se eu estiver faltando alguma coisa, mas não entendo por que o benefício está sobre a arquitetura do Renderer.

Com essa abordagem, é possível escrever um renderizador de plataforma cruzada em vez do renderizador específico da plataforma? Como mapear o controle de botão com controle afiado do céu.

O renderizador de plataforma é um projeto ruim. Como você pode ver, existem muitas bibliotecas de controle xamarin que não oferecem suporte a UWP devido ao limite da plataforma.
Veja um exemplo, a sombra em UWP. Você não pode obter uma sombra de canto de um botão de canto (é claro, você pode alterar o modelo do botão para fazer isso, mas isso é outra coisa).

Eu sei que é muito difícil construir uma renderização multiplataforma. Mas a vibração nos disse que isso é viável. A longo prazo, um renderizador de plataforma cruzada é a melhor solução.

Acho que renderizar o aplicativo inteiro como uma tela 2d personalizada pode funcionar perfeitamente para aplicativos móveis.

Mas pode não funcionar para aplicativos de desktop ou aplicativos complexos porque há muitas ações do usuário que precisam ser reimplementadas, como arrastar e soltar, seleção de texto, atalho de teclado para manipular texto e assim por diante.

Por que não fazer a estrutura de interface do usuário com o próprio conjunto de controles sem qualquer tipo de mapeamento e lógica comportamental totalmente escrita em c # que seria renderizada com a biblioteca gráfica do Skia? Como as pessoas usam um design fortemente customizado, não há necessidade de tentar corresponder às diretrizes de design da plataforma. A única necessidade é a possibilidade de personalizações flexíveis. Por favor, corrija-me se eu estiver faltando alguma coisa, mas não entendo por que o benefício está sobre a arquitetura do Renderer.

Acho que renderizar o aplicativo inteiro como uma tela 2d personalizada pode funcionar perfeitamente para aplicativos móveis.

Mas pode não funcionar para aplicativos de desktop ou aplicativos complexos porque há muitas ações do usuário que precisam ser reimplementadas, como arrastar e soltar, seleção de texto, atalho de teclado para manipular texto e assim por diante.

Por que não fazer a estrutura de interface do usuário com o próprio conjunto de controles sem qualquer tipo de mapeamento e lógica comportamental totalmente escrita em c # que seria renderizada com a biblioteca gráfica do Skia? Como as pessoas usam um design fortemente customizado, não há necessidade de tentar corresponder às diretrizes de design da plataforma. A única necessidade é a possibilidade de personalizações flexíveis. Por favor, corrija-me se eu estiver faltando alguma coisa, mas não entendo por que o benefício está sobre a arquitetura do Renderer.

Você está absolutamente certo sobre tudo isso, mas a equipe não é forçada a escolher a única abordagem. Acho que tudo isso é falta de tempo. Quero dizer, eles só precisam lançar um "novo" framework de interface do usuário totalmente multiplataforma em um ano junto com .net 6. E é muito menos arriscado tomar o bom e velho framework testado pelo tempo como base. Está tudo bem e deveria estar. Mas eu acredito que em um longo tempo a renderização de canvas 2d customizada tem muito mais benefícios e realmente merece ser chamada de "plataforma cruzada". O Xamarin forms é muito bom e tem um grande progresso para hoje. Mas é hora de seguir em frente. As equipes da Microsoft e do xamarin têm engenheiros muito inteligentes e provavelmente estão considerando essa abordagem ou talvez até tenham algumas conexões com http://avaloniaui.net/ como um trunfo

Por que não fazer a estrutura de interface do usuário com o próprio conjunto de controles sem qualquer tipo de mapeamento e lógica comportamental totalmente escrita em c # que seria renderizada com a biblioteca gráfica do Skia? Como as pessoas usam um design fortemente customizado, não há necessidade de tentar corresponder às diretrizes de design da plataforma. A única necessidade é a possibilidade de personalizações flexíveis. Por favor, corrija-me se eu estiver faltando alguma coisa, mas não entendo por que o benefício está sobre a arquitetura do Renderer.

Pode ser legal ter um cinza padrão de 4ª renderização para desenvolvedores do Skia que irá mudá-lo 100% com certeza para entregar um design rico,
Para back combability deixaria esses 3 como estão, mas adicionaria "desenhe você mesmo, querido desenvolvedor" _skia_render e assumiria 90% da responsabilidade por ele, desenvolvedor.

Se o conceito de renderizadores deve ser mantido, pode-se pensar em eliminar a ponte entre o código de IU compartilhado e os renderizadores por meio de INotifyPropertyChanged e manipuladores de eventos? ie

  • Em vez de definir uma _property_ no controle compartilhado e um evento PropertyChanged sendo propagado, a propriedade pode ser mapeada e definida diretamente no renderizador da plataforma?
  • Em vez de chamar um _método_ no controle compartilhado e um evento sendo disparado e manipulado pelo renderizador, o método pode ser mapeado e envolvido diretamente no renderizador da plataforma?

INotifyPropertyChanged é ótimo para design MVVM e modelos de visualização fracamente acoplados, mas sempre pareceu desajeitado como um mecanismo de ponte entre o código de IU compartilhado e os renderizadores da plataforma. Isso, por sua vez, levaria a um melhor desempenho, menos 'conversas' entre a interface do usuário compartilhada e a camada de renderizador e uma melhor experiência do desenvolvedor.

Isso é longo, mas vale a pena assistir a um pouco de "beisebol interno" em Maui.
https://www.youtube.com/watch?v=_MGh3xipWm4

Parece que a arquitetura de Maui suportará controles de plataforma e controles desenhados em tela e, além disso, o nobre @Clancey continuará a trabalhar em um conjunto de renderização baseado em skia para Maui, que não funcionará apenas no tipo MVU de Maui, mas também para o padrão MVVM.

À primeira vista, Maui parecia uma mudança de marca de Forms, mas em uma inspeção mais detalhada, é uma reestruturação da arquitetura de Forms para tornar suas camadas mais fracamente acopladas e, assim, apoiar muitas das coisas que estamos perguntando neste tópico. Tempos divertidos à frente.

Isso é um pouco fora do tópico, mas é algo que eu gostaria de perguntar apenas por causa de sua relevância para exatamente isso:

Como a memória funciona com SKCanvasView (ou Skia em geral)? Cada um sempre ocupa memória proporcional ao seu tamanho? Isso muda se se sobrepõe a outras?

Se, por exemplo, eu tivesse um controle de gradiente (renderizador escrito em Skia) e acima dele tivesse um botão semitransparente (renderizador escrito em Skia), isso ocuparia o dobro da memória ou o contexto gráfico é de alguma forma compartilhado? Que tal se os controles Skia se sobrepusessem a controles não Skia?

Já considerei implementar alguns controles gráficos sofisticados no Forms usando o Skia antes, mas não entender como a memória funciona sempre me preocupou o suficiente, que nunca.

@GalaxiaGuy Acho que usar um controle skia sobreposto a um controle não skia, assim como um controle winform hospedado em um controle wpf. Você pode fazer isso, mas não o melhor.
Se você tiver dois controles renderizados por SKCanvasView , o contexto gráfico não será compartilhado. A melhor maneira é compor os dois renderizados e desenhá-los em uma única tela.
Em meu teste, o desempenho de SkiaSharp não é tão ruim se você apenas fizer algumas coisas estáticas. E tento fazer algumas animações, o uso da CPU é um pouco alto no meu laptop.

Por que tantas pessoas estão obcecadas com o Skia? Uma boa especificação de renderização seria independente do mecanismo de renderização usado no nível baixo. Se um renderizador de plataforma em particular deseja usar Skia (ou Direct2D ou OpenGL ou qualquer outro), isso não deve ser algo com que a camada de aplicativo deve se preocupar.

A maior promessa do XAML com WPF anos atrás, era a ideia de controles sem aparência, em que os gráficos reais dos controles eram transferidos para modelos. O Xamarin Forms usava XAML sem essa capacidade, e esse era seu ponto mais fraco, apenas anos depois parcialmente corrigido pela especificação do Drawing.
Eu não acho que precisamos de outro conjunto de interfaces e abstrações sobre os componentes existentes em vários sistemas operacionais e estruturas, mas um controle baseado em XAML verdadeiramente sem aparência - independentes de plataforma e back-ends de renderização gráfica específicos da plataforma. E com certeza, o modelo padrão pode muito bem ser o controle nativo real, mas o Santo Graal são os modelos gráficos definir uma vez, usar em todos os lugares.

A maior promessa do XAML com WPF anos atrás, era a ideia de controles sem aparência, em que os gráficos reais dos controles eram transferidos para modelos. O Xamarin Forms usava XAML sem essa capacidade, e esse era seu ponto mais fraco, apenas anos depois parcialmente corrigido pela especificação do Drawing.

Concordou! E você realmente precisa de um número muito pequeno de primitivas de renderização para realizar provavelmente 99% de tudo que um aplicativo precisa:

  • Bordas (incluindo opções de sombra projetada e bordas arredondadas)
  • Linhas / Elipses / Retângulos
  • Renderização de texto simples
  • Entrada de texto simples
  • Renderização de rich text
  • Entrada de rich text
  • Renderização de HTML
  • Apresentador de imagem
  • Apresentador de áudio / vídeo
  • Pincéis de gradiente sólido e linear / radial

As plataformas de renderização XF se tornaram tão inchadas porque sempre que um novo tipo de controle é adicionado ao framework, ele é feito com um novo renderizador, em vez de construir sobre primitivos existentes dentro do framework.

Sim, muito mais lógica teria que ser movida para a camada de estrutura, sendo o mais desafiador quando se trata de controles de itens ( VirtualizingStackPanel é fundamental para ter um visualizador de itens escalonáveis, mas que eu saiba nunca foi efetivamente transportado para fora do WPF porque é tão complexo). Mas como o WPF é de código aberto, muito disso pode ser transferido para o MAUI agora e acho que finalmente é o momento em que isso deve começar a acontecer.

você realmente precisa de um número muito pequeno de primitivas de renderização para realizar provavelmente 99% de tudo que um aplicativo precisa.

A plataforma Uno está usando essa abordagem.

@velocitysystems

Em vez de definir uma propriedade no controle compartilhado e um evento PropertyChanged sendo propagado, a propriedade pode ser mapeada e definida diretamente no renderizador de plataforma?

Esse também é um grande objetivo dessa mudança. Assim que estivermos do outro lado dessas mudanças, os renderizadores não terão ideia do que significa BindableObject ou INPC

Esse também é um grande objetivo dessa mudança. Assim que estivermos do outro lado dessas mudanças, os renderizadores não terão ideia do que significa BindableObject ou INPC

Portanto, um método no renderizador será invocado pelo framework sempre que um BindableProperty mudar em vez do renderizador ter que se inscrever em PropertyChanged ?

@legistek certo

Isso basicamente inverte as dependências

Portanto, os renderizadores funcionarão apenas com o IButton.

E então System.Maui adicionará uma referência ao projeto de renderizadores em oposição a agora como os renderizadores têm referências a Xamarin.Forms.Core

Eu verifiquei um pico que temos aqui
https://github.com/dotnet/maui/pull/66

Então você pode ver como isso pode ser

Estarei fazendo um stream hoje às 3:30 PDT com @davidortinau e falaremos sobre os renderizadores finos

https://www.twitch.tv/microsoftdeveloper

Junte-se a nós! Confira! E faça perguntas!

@PureWeen Infelizmente eu perdi. Haverá uma gravação disponível no YouTube?

Esse também é um grande objetivo dessa mudança. Assim que estivermos do outro lado dessas mudanças, os renderizadores não terão ideia do que significa BindableObject ou INPC.

Isso é enorme, uma melhoria realmente substancial. Sem dúvida, também com a mudança para Maui, o modelo de herança complexo usado em muitos dos renderizadores será removido em favor de uma abordagem mais composicional?

Vou revisar o nº 66 hoje.

Olhando para o # 66, é bom ver que os renderizadores finos são construídos e invocados com 'isca e troca' ao invés de usar reflexão. Apenas alguns pensamentos:

  • Os renderizadores Slim resolverão os problemas de GC, especialmente no Android, onde há uma incompatibilidade entre o ciclo de vida de controle gerenciado e nativo? Isso é especialmente perceptível em visualizações filhas em layouts virtualizados que levam aos temidos ObjectDisposedException .
  • Os renderizadores Slim levarão à descontinuação de Effect ? Os efeitos podem ser úteis, mas, em última análise, eles adicionam complexidade e ainda outro potencial de latência para o ciclo de vida do layout.
  • Como uma propriedade 'bidirecional' funcionaria com o novo design do renderizador? Por exemplo, digamos que eu tenha um MediaElement com uma propriedade Position ( TimeSpan ). O setter atualiza a posição atual e recupera a posição atual do reprodutor de mídia nativo, ou seja, AVPlayer , MediaPlayer . Existe um projeto para mapear um _getter_ com renderizadores finos?

Os renderizadores Slim resolverão os problemas de GC, especialmente no Android, onde há uma incompatibilidade entre o ciclo de vida de controle gerenciado e nativo? Isso é especialmente perceptível em visualizações filhas em layouts virtualizados que levam à temida ObjectDisposedException.

Temos algumas ideias aqui !! Queremos retrabalhar um pouco as estratégias de descarte para resolver a maioria, senão todas as exceções de ODE. No momento, descartamos tudo de forma superagressiva no Android / iOS, mas tenho quase certeza de que podemos contar com o GC para fazer o que o GC faz. Se apenas nos certificarmos de remover a referência de tudo e deixar o GC fazer o trabalho, isso deve ajudar em muitos desses casos

Os renderizadores Slim levarão à depreciação do Effect? Os efeitos podem ser úteis, mas, em última análise, eles adicionam complexidade e ainda outro potencial de latência para o ciclo de vida do layout.

Definitivamente, é uma boa coisa a ser examinada à medida que desenvolvemos essa ideia. Assim que chegarmos a um design final para tudo isso, daremos uma olhada nos efeitos. Mas, sim, eu posso ver os efeitos se tornando obsoletos, já que eles são uma forma de explorar os elementos nativos sem ter que usar o renderizador completo. Mappers basicamente efeitos obsoletos

Como uma propriedade 'bidirecional' funcionaria com o novo design do renderizador? Por exemplo, digamos que eu tenha um MediaElement com uma propriedade Position (TimeSpan). Setter atualiza a posição atual e recupera a posição atual do reprodutor de mídia nativo, ou seja, AVPlayer, MediaPlayer. Existe um projeto para mapear um getter com renderizadores finos?

Ainda estamos trabalhando nisso um pouco. Corrija-me se eu estiver errado @Clancey, mas o ActionMapper foi nossa abordagem atual para isso, sim? https://github.com/dotnet/maui/blob/slim-renderers/Maui.Core/PropertyMapper.cs#L91

Como uma propriedade 'bidirecional' funcionaria com o novo design do renderizador? Por exemplo, digamos que eu tenha um MediaElement com uma propriedade Position (TimeSpan). Setter atualiza a posição atual e recupera a posição atual do reprodutor de mídia nativo, ou seja, AVPlayer, MediaPlayer. Existe um projeto para mapear um getter com renderizadores finos?

Ainda estamos trabalhando nisso um pouco. Corrija-me se eu estiver errado @Clancey, mas o ActionMapper foi nossa abordagem atual para isso, sim? https://github.com/dotnet/maui/blob/slim-renderers/Maui.Core/PropertyMapper.cs#L91

Não exatamente. Portanto, o ActionMapper é a mesma coisa que um PropertyMapper, com a exceção de que eles não são chamados durante a fase SetElement. Então, para coisas como WebView, GoBack. Você não quer chamar isso durante a inicialização, mas ainda é algo que você precisa para se comunicar com o Renderer.

Já oferecemos suporte para mapeamento bidirecional. ou seja, entrada. Quando o valor do texto muda para a entrada. o IEntry tem um string Text {get;set;} e nós simplesmente configuramos o valor. Portanto, para elementos de mídia, você tem 2 opções. Um é simplesmente retroceder a posição / hora quando ela muda. Se você quiser fazer algo, você deve consultar. Você pode fazer isso. As visualizações xplat têm acesso ao renderizador. view.Renderer.NativeView as NativeMediaView Agora você pode retirar quaisquer propriedades que desejar!

Aqui estão alguns vídeos de nossos streams durante o Build

@Clancey 's aqui será mais aprofundado
https://www.youtube.com/watch?v=_MGh3xipWm4

Eu toco neles um pouco aqui com David
https://www.youtube.com/watch?v=lAmwjfZY1IM

Como uma propriedade 'bidirecional' funcionaria com o novo design do renderizador? Por exemplo, digamos que eu tenha um MediaElement com uma propriedade Position (TimeSpan). Setter atualiza a posição atual e recupera a posição atual do reprodutor de mídia nativo, ou seja, AVPlayer, MediaPlayer. Existe um projeto para mapear um getter com renderizadores finos?

Ainda estamos trabalhando nisso um pouco. Corrija-me se eu estiver errado @Clancey, mas o ActionMapper foi nossa abordagem atual para isso, sim? https://github.com/dotnet/maui/blob/slim-renderers/Maui.Core/PropertyMapper.cs#L91

Não exatamente. Portanto, o ActionMapper é a mesma coisa que um PropertyMapper, com a exceção de que eles não são chamados durante a fase SetElement. Então, para coisas como WebView, GoBack. Você não quer chamar isso durante a inicialização, mas ainda é algo que você precisa para se comunicar com o Renderer.

Já oferecemos suporte para mapeamento bidirecional. ou seja, entrada. Quando o valor do texto muda para a entrada. o IEntry tem um string Text {get;set;} e nós simplesmente configuramos o valor. Portanto, para elementos de mídia, você tem 2 opções. Um é simplesmente retroceder a posição / hora quando ela muda. Se você quiser fazer algo, você deve consultar. Você pode fazer isso. As visualizações xplat têm acesso ao renderizador. view.Renderer.NativeView as NativeMediaView Agora você pode retirar quaisquer propriedades que desejar!

Outra coisa a considerar aqui são os registros que estão chegando em C # 9. A especialidade é que eles são imutáveis ​​e têm init acessor de propriedade. Portanto, para torná-los utilizáveis ​​em uma ligação bidirecional, o mapeador precisa ser capaz de retornar uma nova instância usando o operador with .

Eu realmente espero que as visualizações sejam vinculáveis ​​aos registros, porque isso torna muito mais fácil quando se trata de MVVM puro ou mesmo MVU puro.

Pergunta: o diagrama que você postou mostra os controles do Windows sendo renderizados por Windows.UI.* , mas pelo que entendi, isso agora está em processo de descontinuação e não terá nenhuma atualização: todas as melhorias nas renderizações de design fluentes estão ocorrendo em Microsoft.UI.* como parte do projeto WinUI. Você pode comentar sobre isso?

Eu acho que mapear para controles nativos é um grande erro, essa é a parte terrível do Xamarin.Forms, você não pode fazer layouts únicos e bonitos facilmente, você tinha que seguir o conceito e abordagem dos controles WPF e Flutter sem aparências com um render engine escrito em C ++ usando OpenGL / DirectX / Metal, pois facilita a portabilidade, desempenho e flexibilidade além de não depender de estruturas de plataforma que estão em constante mudança.

A questão está aqui para falar sobre os novos Mapeadores de Arquitetura / Propriedade. Não o que eles mapeiam. Apenas para reiterar. Arquitetura Slim Render para nativo não significa que nunca faremos e nunca poderemos fazer uma abordagem de controle desenhado. Mas isso nos permite misturar e combinar controles nativos e não nativos, onde se você for simplesmente desenhado, é mais difícil. Eu pretendo continuar trabalhando em controles baseados no Skia que seguem a mesma Arquitetura Slim Renderer, incluindo a camada de desenho. https://github.com/Clancey/Comet/tree/dev/src/Comet.Skia/Handlers.

Meus 2 centavos nessa coisa de renderizador (que admito que não entendo totalmente, TBH):

Tive uma ideia sobre como poderíamos implementar ambos os controles renderizados por plataforma (por exemplo, envolvendo UIButton) _e_ controles sem aparência (a la WPF) usando a mesma classe de controle. É muito simples, honestamente: faça com que a classe Maui Button use um modelo de controle e remova todo o código de renderizador específico da plataforma dele. Em seguida, forneça um modelo na caixa para Button que contenha um ButtonRenderer. O ButtonRenderer é o que se comunica com Cocoa / UIKit / UWP / etc, com código específico da plataforma para cada kit de ferramentas de UI, e a classe Button usada pelo desenvolvedor do aplicativo simplesmente encaminha suas propriedades para ele. Se o usuário quiser usar um botão de desenho personalizado, ele pode simplesmente substituir o modelo e usar classes de desenho (o que quer que pareça) em vez do ButtonRenderer, assim como fazemos no WPF. Sinceramente, não sei se isso já é possível (ou mesmo já usado) em Maui hoje, pois nunca tive tempo para entender o Xamarin. Formulários tão profundamente quanto eu entendo WPF.

Me diga o que você acha!

Estou tentando entender o que os renderizadores Slim significariam para diferentes modelos de aplicativos (MVVM, MVU, ...).

O diagrama inicial parece dizer que cada modelo de aplicativo diferente terá seu próprio conjunto de renderizadores.
Mas, na minha opinião, seria melhor ter um conjunto de renderizadores por tipo de renderização (por exemplo, renderizar para controles nativos como XF, renderizar para tela, etc.).
O renderizador não precisa estar ciente do modelo do aplicativo, ele só precisa saber qual valor é mapeado para qual propriedade, para que possa aplicar a atualização correta ao controle subjacente.
Apenas o IButton será implementado de forma diferente para cada modelo de aplicativo e será responsável por chamar as funções mapeadas de seu renderizador.

Isso é importante porque bibliotecas de terceiros como o Fabulous não terão a mão de obra da Microsoft para implementar (com todos os bugs que vêm com ele) todos os renderizadores apropriados para cada controle em cada plataforma.

Outro ponto é: as interfaces de controle ( IButton ) devem ser somente getter para serem consumidas pelos renderizadores.
Os renderizadores não definem valores e cada modelo de aplicativo moldará os controles de maneira diferente (BindableProperty, BindingObject, etc.).
Por exemplo, Fabulous terá visões imutáveis. Apenas internamente, ele estará autorizado a definir a mutação para a instância de IButton .

Dessa forma, o Fabulous pode usar diretamente a interface IButton como uma visualização do leitor sobre seu dicionário interno para que os renderizadores possam trabalhar.

// 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 Tudo o que você disse é como funciona :-)

O desenho lá é confuso no que diz respeito aos renderizadores.

A única parte com a qual você precisará se preocupar é o Botão Fabuloso e, a partir daí, cuidaremos de todo o resto

Na maioria das vezes, as interfaces são somente leitura

Esta é a interface usada pelo botão
https://github.com/dotnet/maui/blob/slim-renderer-samples/Maui.Core/Views/IText.cs

Tudo o que é realmente sobre você (no que diz respeito aos renderizadores) é sinalizar para o renderizador que ele deve consumir novamente o IButton

Por exemplo, na versão BindableObject de tudo isso, estamos apenas chamando o método updateproperty do Renderer aqui

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

Em algum momento (em breve?) @Clancey terá uma versão pública do Comet que você poderá conferir para ver como ele está fazendo isso.

Eu iria verificar
https://github.com/dotnet/maui/blob/slim-renderer-samples

Você provavelmente pode adicionar seu próprio Fabulous.Core head e então começar a adicionar implementações às interfaces

@PureWeen Oh legal. Obrigado, vou tentar brincar com os exemplos que você vinculou para ver como funciona.

@PureWeen @Clancey Tenho certeza de que a equipe do Maui cuidará disso, mas os novos renderizadores Slim podem favorecer a composição em vez da herança. A herança é útil, mas infelizmente no XF ela tornou algumas das hierarquias de renderização incrivelmente complexas e difíceis de manter.

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

dá 404, é privado?

@ Rand-Random

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

@velocitysystems

Tenho certeza de que a equipe do Maui cuidará de tudo isso, mas os novos renderizadores Slim podem favorecer a composição em vez da herança. A herança é útil, mas infelizmente no XF ela tornou algumas das hierarquias de renderização incrivelmente complexas e difíceis de manter.

É assim que eles são construídos. Há uma classe base muito fina que herda diretamente do bom e velho System.Object

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

E não tem laços nativos.

A partir daí, tudo é definido através do que é basicamente um Dicionário

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

Que funciona basicamente como um decorador.

Você pode decorar mapeadores com mapeadores adicionais e pode injetar suas próprias funções etc.

Nosso objetivo é que 95 por cento dos cenários de usuários sejam cobertos apenas adicionando seu próprio Func ao mapeador ou apenas acessando os elementos nativos diretamente, já que tudo será multi-direcionado

@PureWeen Qual seria o canal mais apropriado para discutir a implementação desses renderizadores finos em sua amostra?

Eu tenho algumas perguntas como:

  • Os valores padrão serão definidos em um local centralizado? No XF, eles são definidos atualmente ao criar os campos BindableProperty, mas eles não estarão presentes, dependendo do modelo do aplicativo.
  • A classe Application também se tornará (parcialmente) uma interface? Ele define muitos comportamentos da IU (recursos, menu, página principal) e seria ótimo implementar de forma diferente.
  • O Medir / Organizar / etc será extraído das interfaces de controle? Eu não acho que realmente faça sentido que os modelos de aplicativos os implementem de maneira diferente.

Os valores padrão serão definidos em um local centralizado? No XF, eles são definidos atualmente ao criar os campos BindableProperty, mas eles não estarão presentes, dependendo do modelo do aplicativo.

Essa é uma boa pergunta. @Clancey ? Não tenho certeza se já definimos isso. Há uma fase de configuração inicial onde todos os mapeadores são chamados com o valor atual das propriedades (valor padrão), mas não tenho certeza se temos um plano ainda para valores padrão e como eles serão generalizados

A classe Application também se tornará (parcialmente) uma interface? Ele define muitos comportamentos da IU (recursos, menu, página principal) e seria ótimo implementar de forma diferente.

Sim! Esperamos recolher todas as classes de aplicativo (nativas e xplat) em uma única classe de aplicativo. Por que você está perguntando sobre isso? Estou apenas curioso para saber seu caso de uso aqui para que possamos nos certificar de abordar

O Medir / Organizar / etc será extraído das interfaces de controle? Eu não acho que realmente faça sentido que os modelos de aplicativos os implementem de maneira diferente.

Nesse ponto, esse é o plano. A ideia será extrair todo o nosso código de layout para que nenhum dependa de BindableObject / Property. Desta forma, Blazor / Comet / other pode apenas usar um StackLayout e o resultado será o mesmo.

Por que você está perguntando sobre isso? Estou apenas curioso para saber seu caso de uso aqui para que possamos nos certificar de abordar

Ainda não tenho certeza do que quero. Mas no Fabulous, não temos atualmente uma boa história para definir estilos globais e menu principal (como no macOS). Já que deixamos nossos usuários criarem uma subclasse da classe Application, basicamente dizemos a eles para definir recursos / menu como fariam no Xamarin.Forms clássico.

Portanto, idealmente, todas as propriedades relacionadas à IU do aplicativo também fariam parte da visualização, dessa forma, seríamos capazes de aplicar nossa lógica de diferenciação de visualização nela também.

Algo parecido

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 Outra pergunta: Quem será o responsável por desencadear eventos como TextChanged , Toggled , etc.? Os controles ou os renderizadores?

Uma coisa que acho que simplificaria muito a implementação de outros modelos de aplicativo é a possibilidade de não acionar eventos de mudança de estado quando as mudanças são programáticas.

Por exemplo, hoje, TextChanged on Entry é acionado quando o usuário escreve algo ou quando fazemos MyEntry.Text = "New value"; .
Acho que reagir a uma mudança programática não é realmente útil e implícito, o que é ruim para raciocinar sobre o código.

Além disso, isso levou a um loop infinito no Android porque a plataforma dispara seus eventos com um pequeno atraso e forçou o Fabulous a sair de sincronia sem possibilidade de voltar.
A única solução que encontramos foi primeiro cancelar a inscrição do evento antes de definir o valor e, em seguida, inscrever-se novamente ...

Uma pergunta curiosa. Quando a MAUI é agnóstica quanto à arquitetura, por que os controles são nomeados por nomes de arquitetura? Por exemplo, no diagrama acima, temos Maui. Mvvm .ButtonRenderer.Android? @PureWeen @Clancey

O XF tem algo chamado Layouts compactados (que tem bugs)
Temos tal coisa (sem bugs com certeza!) No MAUI?

Eu vejo como as pessoas reagem neste tópico sobre ter uma abordagem Flutter / Skia para renderizar a interface do usuário e eu concordo principalmente com eles.
Estou muito feliz que o MAUI potencialmente terá suporte para controles e renderizações personalizados / não nativos.
No entanto, devo dizer que a capacidade de trabalhar com a interface do usuário nativa protege a estrutura no lado político das coisas.
E sim, estou apontando na Apple. Devido às últimas notícias, eu não ficaria surpreso se em algum momento, por algum motivo, o uso do Flutter fosse considerado como 'exploração de recursos não documentados / restritos' ou 'não cumprimento das diretrizes da IU da Apple' e assim por diante.

Eu vejo como as pessoas reagem neste tópico sobre ter uma abordagem Flutter / Skia para renderizar a interface do usuário e eu concordo principalmente com eles.
Estou muito feliz que no MAUI potencialmente haverá suporte para controles e renderizações personalizados / não nativos.
No entanto, devo dizer que a capacidade de trabalhar com a interface do usuário nativa protege a estrutura no lado político das coisas.
E sim, estou apontando na Apple. Devido às últimas notícias, eu não ficaria surpreso se em algum momento, por algum motivo, o uso do Flutter fosse considerado como 'exploração de recursos não documentados / restritos' ou 'não cumprimento das diretrizes da IU da Apple' e assim por diante.

Se o MAUI suportar a Web (como o Flitter), podemos sempre renderizar no WebView.
É improvável que a Apple ouse bloquear aplicativos baseados em WebView, porque algumas grandes empresas são representadas na AppStore apenas por meio do WebView

Eu vejo como as pessoas reagem neste tópico sobre ter uma abordagem Flutter / Skia para renderizar a interface do usuário e eu concordo principalmente com eles.
Estou muito feliz que no MAUI potencialmente haverá suporte para controles e renderizações personalizados / não nativos.
No entanto, devo dizer que a capacidade de trabalhar com a interface do usuário nativa protege a estrutura no lado político das coisas.
E sim, estou apontando na Apple. Devido às últimas notícias, eu não ficaria surpreso se em algum momento, por algum motivo, o uso do Flutter fosse considerado como 'exploração de recursos não documentados / restritos' ou 'não cumprimento das diretrizes da IU da Apple' e assim por diante.

Se o MAUI suportar a Web (como o Flitter), podemos sempre renderizar no WebView.
É improvável que a Apple ouse bloquear aplicativos baseados em WebView, porque algumas grandes empresas são representadas na AppStore apenas por meio do WebView

que já é contra essas diretrizes - https://developer.apple.com/app-store/review/guidelines/#minimum -functionality

Depois de ter lido um pouco atrás e em quarto o que todo este novo mundo de MAUI parece ser, por favor, pelo amor de tudo o que é sagrado, faça uma escrita uma vez, use em todos os lugares um mecanismo de renderização como o SKIA ou outro motor de renderização multiplataforma, tendo que implementar customizado A IU em cada plataforma, como no Xamarin Forms, parece velha e como se fosse uma solução criada no sétimo círculo do inferno.

se a compatibilidade com versões anteriores for obrigatória "apenas" tornar o suporte de renderização novo e moderno uma forma de renderizar componentes mais antigos, já vi outras plataformas terem uma solução bacana para isso, a mais recente que usei está no mecanismo de interface do usuário da unidade, onde o novo UXML moderno tem um IMGUI Render.

@ jackie0100
Eu concordo plenamente

ter que implementar UI customizada em cada plataforma como no Xamarin Forms parece antigo e como se fosse uma solução criada no sétimo círculo do inferno.

Quanto à implementação do renderizador, que tal a ideia de um IView É uma visualização nativa (em vez de um IView TEM uma visualização nativa). ou seja, herança em vez de composição? Isso levaria à arquitetura mais rápida e enxuta, com absolutamente zero "sobrecarga de formulários". Você está basicamente trabalhando com visualizações nativas puras e apenas uma interface comum.

Então, você poderia fazer coisas como, na terra do iOS, apenas lançar sua visão para ser um UIView e adicionar um filho nativo a ela (qualquer tipo que você quiser) porque um IView é um UIView. Da mesma forma, se você quiser fazer 'incorporação nativa', é fácil porque um IView é um UIView, você pode simplesmente adicionar uma de suas IViews à sua visualização nativa porque eles são a mesma coisa. Isso permitiria maciçamente a interoperabilidade <-> maui nativa e com o mais alto nível de desempenho e menor consumo de memória.

Eu meio que sinto vontade de fazer um protótipo sozinho. Talvez um projeto de fim de semana / noite ...

image

Se o MAUI suportar a Web (como o Flitter), podemos sempre renderizar no WebView.

Não precisa do WebView no iOS: pode renderizar diretamente em OpenGL ou Metal .

Ou use o Skia com OpenGL ou Metal por baixo.

capacidade de trabalhar com UI nativa protege a estrutura no lado político das coisas. [Maçã]

Em algum ponto, a Apple removeu de sua política escrita o requisito de usar widgets de IU nativos. Não vejo nenhuma maneira prática de reverter a política de volta a ser restritiva.

Independentemente disso, ser _capaz de trabalhar com controles nativos é uma boa opção.

@legistek

Por que tantas pessoas estão obcecadas com o Skia? Uma boa especificação de renderização seria independente do mecanismo de renderização ...

Embora eu concorde totalmente em ser "agnóstico", há _muito_ de detalhes que devem ser implementados para renderizar qualquer IU interativa - se você for diretamente para OpenGL / Metal / Vulkan / qualquer que seja o mecanismo de renderização de baixo nível. As pessoas estão obcecadas com o Skia porque ele é uma _camada intermediária_ eficaz entre as preocupações com a interface do usuário do aplicativo e o mecanismo de renderização real: o Skia lida com _muito_ do que teria que ser projetado e implementado, se tudo o que você tem é metal puro. Não há razão para reinventar este trabalho. Embora não deva ser o alvo _somente_, é um alvo extremamente valioso e maduro, o que tornará muito mais fácil, digamos, mudar de OpenGL para Vulkan.

Também suspeito que direcionar o Skia seria muito menos complicado do que a manutenção do Xamarin Forms de duas heirarquias paralelas de widgets - os widgets de plataforma cruzada e os widgets nativos.

O Skia pode até apressar o dia em que o .Net Maui terá um alto desempenho no navegador . Novamente, porque em vez de construir a partir de um nível baixo, de renderização, você está começando em uma abstração de nível médio apropriada. Isso seria uma grande vitória.

Olá a todos, não se esqueçam:
https://github.com/dotnet/maui/discussions/103

Tendo assistido aos vídeos recentes do maui, a menos que eu esteja enganado, parece que houve uma tendência para ter controles mais estilizados com o controle nativo sendo sobreposto com o desenho feito na plataforma no lado dependente. Quer seja skia ou algum tipo de interoperabilidade em lote com o desenho de tela nativo, espero que essa abordagem seja seguida! O modelo de renderizador da plataforma XF sempre foi ironicamente o que mais prejudicou as plataformas de IU da Microsoft, sendo o menos usado.

Eu também deixaria aberta a capacidade de um controle explicitamente não ter um componente nativo e para o compositor de layout detectar isso, isso pode permitir uma redução automatizada nas visualizações nativas criadas (ou seja, se todos os controles em um contêiner forem rótulos maui desenhados com skia, ele poderia tornar o contêiner um SkView e apenas chamar a operação de desenho no rótulo controles filhos), no Android, que aumentaria a velocidade em coisas como elementos de lista que têm muitas imagens + controles de texto, por exemplo.

Eu não entendo o que é um renderizador.
Se o programa para absorver as diferenças visuais do destino é chamado de renderizador, ele deve ser absorvido por Xamarin e MAUI juntos. Do contrário, acho que é um Xamarin e MAUI inacabados. E nunca será concluído.
Acho que a programação de aplicativos deve ser mais independente das diferenças no ambiente de destino.

Eu não entendo o que é um renderizador.
Se o programa para absorver as diferenças visuais do destino for chamado de renderizador, ele deve ser absorvido por Xamarin e MAUI juntos. Se não, acho que é um Xamarin e MAUI inacabados. E isso nunca será concluído.
Acho que a programação de aplicativos deve ser mais independente das diferenças no ambiente de destino.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

jsuarezruiz picture jsuarezruiz  ·  3Comentários

jsuarezruiz picture jsuarezruiz  ·  6Comentários

jsuarezruiz picture jsuarezruiz  ·  12Comentários

probonopd picture probonopd  ·  50Comentários

4creators picture 4creators  ·  31Comentários