Microsoft-ui-xaml: Adicionar suporte de validação de entrada para UWP com INotifyDataErrorInfo

Criado em 14 jan. 2019  ·  50Comentários  ·  Fonte: microsoft/microsoft-ui-xaml

Proposta: adicionar suporte à validação de entrada com INotifyDataErrorInfo

Resumo

Adicione suporte de validação de entrada com INotifyDataErrorInfo que é compatível com x:Bind e Binding. Ambas as extensões de marcação devem obter uma nova propriedade ValidatesOnNotifyDataErrors que é - como na vinculação do WPF - true por padrão.

Justificativa

Atualmente, a UWP não possui nenhuma validação de entrada incorporada à plataforma. Mas todo aplicativo de linha de negócios requer validação de entrada. É um dos recursos mais importantes para um aplicativo corporativo adequado. Há uma entrada no uservoice que diz que esse recurso virá com o WinUI, mas ainda não vi nada: https://wpdev.uservoice.com/forums/110705-universal-windows-platform/suggestions/13052589-uwp-input -validação

feature proposal needs-winui-3 team-Markup

Comentários muito úteis

O INDEI exige que você implemente todas as suas entidades e subentidades.

Você pode elaborar mais sobre isso?

Usando regras, nenhuma alteração é necessária, tudo funciona automaticamente usando apenas atributos de validação.

Na maioria das vezes, tudo funciona automaticamente ao usar ValidationAttributes e INotifyDataErrorInfo também. Vou mostrar alguns trechos de código aqui que estão na especificação, só para estarmos (espero) na mesma página.

FWIW, estamos planejando ter essa classe ValidationBase ao vivo no Toolkit, para que você não precise escrever esse código clichê sozinho.

public class ValidationBase : INotifyPropertyChanged, INotifyDataErrorInfo
{
   public event PropertyChangedEventHandler PropertyChanged;
   public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

   protected void SetValue<T>(ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
   {
       if (!EqualityComparer<T>.Default.Equals(currentValue, newValue))
       {
           currentValue = newValue;
           OnPropertyChanged(propertyName, newValue);
       }
   }

   readonly Dictionary<string, List<ValidationResult>> _errors = new Dictionary<string, List<ValidationResult>>();
   public bool HasErrors
   {
       get
       {
           return _errors.Any();
       }
   }
   public IEnumerable GetErrors(string propertyName)
   {
       return _errors[propertyName];
   }

   private void OnPropertyChanged(string propertyName, object value)
   {
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
       Validate(propertyName, value);
   }

   private void AddErrors(string propertyName, IEnumerable<ValidationResult> results)
   {
       if (!_errors.TryGetValue(propertyName, out List<ValidationResult> errors))
       {
           errors = new List<ValidationResult>();
           _errors.Add(propertyName, errors);
       }

       errors.AddRange(results);
       ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
   }

   private void ClearErrors(string propertyName)
   {
       if (_errors.TryGetValue(propertyName, out List<ValidationResult> errors))
       {
           errors.Clear();
           ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
       }
   }

   public void Validate(string memberName, object value)
   {
       ClearErrors(memberName);
       List<ValidationResult> results = new List<ValidationResult>();
       bool result = Validator.TryValidateProperty(
            value,
            new ValidationContext(this, null, null)
            {
                MemberName = memberName
            },
            results
            );

        if (!result)
        {
            AddErrors(memberName, results);
        }
    }
}

Seu modelo derivaria dessa classe e ficaria assim:

public class Person : ValidationBase
{
    private string name;
    [MinLength(4)]
    [MaxLength(6)]
    public string Name
    {   
        get { return name; }
        set { SetValue(ref name, value); }
    }
}

Supondo que essa classe Person esteja definida como uma propriedade ViewModel em seu Page , você se vincula a isso e a validação acontece automaticamente:

<TextBox Text="{x:Bind ViewModel.Name, Mode=TwoWay}" />

Entendo que isso pode ser um pouco diferente do que você está fazendo hoje, mas estamos tentando não apoiar duas maneiras diferentes de fazer a mesma coisa, se não for necessário. Deixe-me saber se isso faz sentido, ou se você acha que ainda está faltando algo!

Todos 50 comentários

@LucasHaines como isso se relaciona com os recursos de validação de entrada que você está analisando?

@jevansaks Isso está diretamente relacionado ao trabalho de validação de entrada que estou descrevendo.

Excelente. Se você tiver algum material de visualização para compartilhar, ficarei feliz em experimentá-lo e fornecer comentários e opiniões.

image

Este é o tipo de validação mencionado durante o Build 2018

`
x:Name="UserName" Header="Nome de usuário:"
Text="{x:Bind ViewModel.Person.UserName,
UpdateSourceTrigger=PropertyChanged,
Modo=Duas Vias}" />

x:Nome="Senha" Header="Senha:"
Password="{x:Bind ViewModel.Person.Password,
UpdateSourceTrigger=LostFocus,
Modo=Duas Vias}"/>
`

@thomasclaudiushuber qual a importância de fazer isso funcionar como parte de {Binding}? Só pergunto porque os desafios técnicos lá não são triviais, assim como não poder trabalhar no nível inferior. Nossa ideia original era apenas suportar x:Bind, que exigirá apenas alterações no compilador de marcação e é capaz de trabalhar em nível inferior.

Além disso, estávamos planejando apenas dar suporte ao paradigma INotifyDataErrorInfo e DataAnnotations. Não pretendíamos adicionar algo análogo a Binding.ValidationRules e, portanto, não sentimos que havia necessidade suficiente de um ValidatesOnNotifyDataErrors.

Adoraríamos receber seus comentários enquanto continuamos a trabalhar nesse recurso para que ele possa ser feito da maneira certa!

@stevenbrix

Resposta curta: Sim, o que você pensa e o que planeja parece ótimo. Apenas x:Bind está bem, e apenas INotifyDataErrorInfo também está bem.

Grandes:

Apenas x: Vincular? 👍

Em todos os casos de WPF-LOB, posso pensar que sempre houve um tipo de ViewModel que era conhecido em tempo de compilação, sem digitação de pato, então x:Bind está bem. Eu escrevi {Binding} nesta edição também, pois achei que você pode suportá-lo para obter a mesma sintaxe do WPF. Mas isso é mais "bom de ter" do que super importante. E como {Binding} e x:Bind são duas coisas completamente diferentes nos bastidores e as coisas de tempo de execução com {Binding} não são triviais como você mencionou, esqueça {Binding}. Eu acho que tê-lo apenas para x:Bind é totalmente bom, funcionará para os casos de uso que eu puder imaginar. E de todas as conferências que fiz sobre UWP e x:Bind, posso dizer que x:Bind é um dos recursos UWP mais favoritos de todos os desenvolvedores XAML e eu disse a todos eles "Prefira x:Bind sobre Binding onde quer que você posso". :) Obter erros de intellisense, perf, step-in-code e tempo de compilação faz com que x:Bind seja o novo padrão na UWP, portanto, ter o suporte de validação apenas ali é bom e uma boa decisão imo.

Apenas INotifyDataErrorInfo e paradigma DataAnnotations? 👍

Apenas suportar o paradigma INotifyDataErrorInfo e DataAnnotations parece bom para mim. O WPF não coleta anotações de dados automaticamente, você precisa conectá-las manualmente em sua implementação INotifyDataErrorInfo usando a classe Validator. Você quer dizer isso quando diz "paradigma DataAnnotations", certo? Ou você planeja suporte a DataAnnotation integrado que permite que um dev apenas coloque uma Data Annotation em uma propriedade e isso simplesmente funciona? Como no ASP.NET Core MVC? Embora isso seja ótimo, acho que não é necessário. Ter as classes ValidationContext, Validator e ValidationResult e as outras classes de System.ComponentModel.DataAnnotations é suficiente imo.

Adicionar Binding.ValidationRules? Nãooooooo ;-)

Não, definitivamente não adicione isso. INotifyDataErrorInfo é suficiente e é o melhor. Acho que nunca mais usei ValidationRules depois que o suporte a IDataErrorInfo foi adicionado ao WPF (se bem me lembro, isso foi no .NET Framework 3.5). E quando INotifyDataErrorInfo foi adicionado no .NET Framework 4.5, meus clientes e eu usamos essa interface em todos os projetos para validação de entrada. Apoiar apenas esta interface é bom.

Adicionar ValidatesOnNotifyDataErrors? Não mas...

Sim, você não precisa adicionar este. Mas não tem nada a ver com o Binding.ValidationRules. Esta propriedade está diretamente relacionada à interface INotifyDataErrorInfo. Na extensão de marcação de vinculação do WPF, ValidatesOnNotifyDataErrors é, por padrão, true, o que significa que {Binding} pega a validação INotifyDataErrorInfo implementada se o objeto vinculado implementa essa interface. Se você definir a propriedade ValidatesOnNotifyDataErrors na extensão de marcação Binding como false, a extensão de marcação Binding não selecionará a implementação INotifyDataErrorInfo para a validação. Então, talvez isso não seja muito difícil de implementar com x:Bind, mas talvez não precisemos disso. Então, não, não faça isso. Tudo bem deixar isso de fora. Mas deixe-me descrever o cenário em que eu precisava disso no passado:

Os controles WPF mostram por padrão uma borda vermelha que é definida por meio de Validation.ErrorTemplate. Agora vamos supor que você tenha uma implementação INotifyDataErrorInfo com uma classe que tenha a propriedade FirstName. É necessário, então você retornará um erro se a propriedade FirstName for nula ou vazia. Agora você vinculou um TextBox a essa propriedade FirstName. Quando um usuário remove esse nome, uma borda vermelha é exibida. Ótimo, exatamente o que você deseja. Mas talvez você tenha em outro local na interface do usuário outro controle que também esteja vinculado à propriedade FirstName. Por exemplo, um TextBlock em um Tab-Header. O WPF exibirá nesse TextBlock uma borda vermelha também quando houver um erro de validação. Mas isso pode não ser o que você quer. Você quer o erro apenas no TextBox onde o usuário pode alterar o nome, mas não no TextBlock no cabeçalho da guia. Para se livrar da borda vermelha no TextBlock, você não precisa editar o ErrorTemplate do TextBlock, em vez disso, basta ativar a validação INotifyDataErrorInfo no TextBlock-FirstName-Binding definindo a propriedade ValidatesOnNotifyDataErrors como false. Esse é o único caso de uso que eu já tive para essa propriedade. :)

Eu espero que isso ajude.

Resumo

Sim, concordo totalmente, ter validação de entrada apenas em x:Bind com suporte para INotifyDataErrorInfo é um bom plano.

Não, é um plano fantástico, já estou super empolgado!

@thomasclaudiushuber obrigado pelo acompanhamento detalhado! Os cenários principais que você descreve estão alinhados com o que acreditamos ser o verdadeiro gerador de valor, e é bom ouvir isso. O design geral desse recurso e API está em fluxo, principalmente devido ao trabalho anterior que o WPF teve. Havia algumas coisas importantes para chamar aqui:

  1. Conforme discutido acima, havia certos aspectos do sistema de validação do WPF que não consideramos agregar valor ou foram substituídos por padrões melhores e, portanto, não planejamos trazê-los para a UWP.

  2. Certos recursos/funcionalidades do sistema de validação do WPF tiram vantagens dos recursos principais do WPF que não existem na UWP. Mais notavelmente aqui está a camada de adorno, que permite que qualquer UIElement no WPF exiba visuais de validação, não apenas controles (por meio da adição de alguma parte do modelo).

  3. O UWP Xaml atualmente não tem o conceito de eventos anexados, e espelhar a classe Validation adicionaria o evento Validation.Error. Não que isso seja um fator decisivo, apenas algo a ser destacado, pois geralmente somos cautelosos em adicionar novos conceitos, pois isso apenas aumenta a complexidade. Além disso, como o trabalho requer alterações no modelo do controle, apenas o conjunto de controles para os quais fornecemos as alterações específicas do modelo funcionaria imediatamente. De um modo geral, ter uma API que parece funcionar, mas não funciona em alguns cenários não é uma boa prática, então pensamos que seria melhor nos divorciarmos desse modelo. Isso significaria ter algo como uma interface comum e/ou atributos que os controles implementam.

Ainda estamos no processo de entender como fazer revisões de API e especificações no novo e empolgante mundo de código aberto. Adoraríamos receber o feedback da comunidade, então esperamos que possamos lançar as propostas da API em breve para que a comunidade possa dar uma olhada e nos ajudar a conseguir algo com o qual todos estão empolgados!

@stevenbrix Quando você começar a especificação de código aberto para os recursos de validação, você fornecerá as ilustrações de como a validação ficará, bem como os cenários de amostra para que a conversa possa ser um pouco mais ampla para aqueles que estão mais no lado da interface do usuário , do que a codificação :)

@mdtauk Absolutamente. A IU atual que compartilhamos ainda é precisa. Se você tiver comentários, sinta-se à vontade para fornecer neste tópico.

@LucasHaines A interface do usuário parece boa para mim. Mas gostaria de saber como você pode ajustar como os erros são exibidos. Não encontrei nada sobre isso e não sei se você já tem algo para compartilhar nessa área. Haverá algo semelhante como a propriedade Validation.ErrorTemplate anexada do WPF?

Existe um cronograma para quando uma especificação/proposta formal será lançada para isso?
O que posso fazer para ajudar isso a entrar no produto mais cedo?

Eu concordo com @mrlacey acima... Eu realmente poderia usar isso agora, então fico feliz em ajudar onde puder.

Estamos trabalhando em uma especificação aberta e informarei a todos que ela está disponível no repositório de especificações.

Pergunta: por que não oferecer suporte a IDataErrorInfo também? É suportado no padrão .net, e seria estranho não suportá-lo? Isso não deve afetar o desempenho das pessoas que não o usam, pois pode ser verificado em tempo de compilação qual interface usar para a ligação?

Iniciamos a revisão de especificações abertas para validação de entrada no repositório de especificações abertas. https://github.com/Microsoft/microsoft-ui-xaml-specs/pull/26

Oi pessoal, como estamos acompanhando isso - temos um ETA?

@knightmeister Temos uma especificação aberta criada aqui . Sinta-se à vontade para participar da revisão e ajudar a moldar o recurso. Estamos planejando enviá-lo como parte do WinUI 3.0. Se você quiser mais informações sobre o roteiro do WinUI 3.0, confira o problema #717.

Olá a todos - por favor, dê uma olhada nas últimas amostras na especificação. @stevenbrix fez ótimas atualizações nas amostras e abordou outros comentários.

Uma pergunta: as informações de validação fluirão para a hierarquia de controle? Por exemplo, será possível para um controle de contêiner (por exemplo, TabView ou Pivot) saber que existe um controle filho em um estado inválido?

Pense em uma exibição complexa com vários controles de contêineres, onde você deseja destacar quais partes da exibição requerem atenção, por exemplo, alterando o estilo de um cabeçalho Pivot quando qualquer controle filho estiver em um estado inválido.

Esta é uma questão crítica para mim.
Todo o meu sistema de validação XAML é baseado em regras de validação WPF, ele lê o campo e o modelo de entidade do BindingExpression e cria regras de validação de acordo com os atributos de validação DA (veja isto ).

Por exemplo, será possível para um controle de contêiner (por exemplo, TabView ou Pivot) saber que existe um controle filho em um estado inválido?

@tbolon sim, isso é algo que pode ser feito, embora seja improvável que haja suporte embutido nesses contêineres para isso. Pensamos em criar um controle Form que tivesse essa funcionalidade embutida, mas provavelmente está na lista de pendências no momento. Como no WPF, há um evento ValidationError (esse nome pode estar errado) que cada controle dispara quando se torna inválido/válido. Este evento não é um evento roteado, então você tem que se inscrever em cada elemento que você está interessado em ouvir.

Todo o meu sistema de validação XAML é baseado em regras de validação WPF,

@weitzhandler , atualmente não estamos planejando adicionar algo como ValidationRule ao WinUI. Existe algo que usar isso lhe dá mais de usar ValidationAttributes e ter seu modelo implementando INotifyDataErrorInfo ? Eu adoraria ver como seu Model e XAML se parecem para entender melhor seu cenário de uso.

O INDEI exige que você implemente todas as suas entidades e subentidades.
Usando regras, nenhuma alteração é necessária, tudo funciona automaticamente usando apenas atributos de validação.

O INDEI exige que você implemente todas as suas entidades e subentidades.

Você pode elaborar mais sobre isso?

Usando regras, nenhuma alteração é necessária, tudo funciona automaticamente usando apenas atributos de validação.

Na maioria das vezes, tudo funciona automaticamente ao usar ValidationAttributes e INotifyDataErrorInfo também. Vou mostrar alguns trechos de código aqui que estão na especificação, só para estarmos (espero) na mesma página.

FWIW, estamos planejando ter essa classe ValidationBase ao vivo no Toolkit, para que você não precise escrever esse código clichê sozinho.

public class ValidationBase : INotifyPropertyChanged, INotifyDataErrorInfo
{
   public event PropertyChangedEventHandler PropertyChanged;
   public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

   protected void SetValue<T>(ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
   {
       if (!EqualityComparer<T>.Default.Equals(currentValue, newValue))
       {
           currentValue = newValue;
           OnPropertyChanged(propertyName, newValue);
       }
   }

   readonly Dictionary<string, List<ValidationResult>> _errors = new Dictionary<string, List<ValidationResult>>();
   public bool HasErrors
   {
       get
       {
           return _errors.Any();
       }
   }
   public IEnumerable GetErrors(string propertyName)
   {
       return _errors[propertyName];
   }

   private void OnPropertyChanged(string propertyName, object value)
   {
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
       Validate(propertyName, value);
   }

   private void AddErrors(string propertyName, IEnumerable<ValidationResult> results)
   {
       if (!_errors.TryGetValue(propertyName, out List<ValidationResult> errors))
       {
           errors = new List<ValidationResult>();
           _errors.Add(propertyName, errors);
       }

       errors.AddRange(results);
       ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
   }

   private void ClearErrors(string propertyName)
   {
       if (_errors.TryGetValue(propertyName, out List<ValidationResult> errors))
       {
           errors.Clear();
           ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
       }
   }

   public void Validate(string memberName, object value)
   {
       ClearErrors(memberName);
       List<ValidationResult> results = new List<ValidationResult>();
       bool result = Validator.TryValidateProperty(
            value,
            new ValidationContext(this, null, null)
            {
                MemberName = memberName
            },
            results
            );

        if (!result)
        {
            AddErrors(memberName, results);
        }
    }
}

Seu modelo derivaria dessa classe e ficaria assim:

public class Person : ValidationBase
{
    private string name;
    [MinLength(4)]
    [MaxLength(6)]
    public string Name
    {   
        get { return name; }
        set { SetValue(ref name, value); }
    }
}

Supondo que essa classe Person esteja definida como uma propriedade ViewModel em seu Page , você se vincula a isso e a validação acontece automaticamente:

<TextBox Text="{x:Bind ViewModel.Name, Mode=TwoWay}" />

Entendo que isso pode ser um pouco diferente do que você está fazendo hoje, mas estamos tentando não apoiar duas maneiras diferentes de fazer a mesma coisa, se não for necessário. Deixe-me saber se isso faz sentido, ou se você acha que ainda está faltando algo!

Você está certo, mas isso exige que suas entidades não sejam POCOs.
Eu deveria tentar tho. Pode não ser tão ruim usar uma classe EntityBase em um aplicativo LoB. Estou acostumado a usar POCOs.

UWP não tem *TEM Validação* !!!!!!! Acabei de iniciar um projeto. De volta ao WPF até alguns anos.

@rufw91 Eu sei, certo?!

Quais são suas limitações de tempo? A primeira implementação disso está na versão alfa do WinUI3, e devemos ter uma visualização para a área de trabalho do WinUI em breve no período de //Build. Planejamos fazer RTM'ing até o final do ano

UWP não tem *TEM Validação* !!!!!!! Acabei de iniciar um projeto. De volta ao WPF até alguns anos.

Eu decidi ficar com o WPF para os próximos anos também. Eu fiz de tudo (WPF, SL, WP, UWP, etc), no final apenas 1 tecnologia parece sólida, que é WPF. Talvez em alguns anos possa ser interessante verificar onde está o WinUI, mas estou cansado de mudar para novas tecnologias e ficar sozinho no escuro. O WPF é maduro e funciona muito bem. Talvez em alguns anos o Windows como sistema operacional não seja relevante, então vamos aguardar isso antes de fazer mais investimentos na plataforma.

Talvez em alguns anos o Windows como sistema operacional não seja relevante, então vamos aguardar isso antes de fazer mais investimentos na plataforma.

Considerando que acabamos de ultrapassar 1 bilhão de instalações do Windows 10, é difícil acreditar que isso será verdade. Mas eu definitivamente sinto sua frustração e não o culpo por permanecer no WPF. FWIW, nossa equipe está se apropriando do WPF agora, então me avise se houver algo que você queira nos ver fazer lá.

O INDEI exige que você implemente todas as suas entidades e subentidades.

Você pode elaborar mais sobre isso?

Com meu código, todas as entidades POCO podem permanecer livres de implementar essas interfaces e permanecer sem uma classe base. O INPC é implementado automaticamente usando o Fody. A maioria que eu faria é implementar IValidatableObject quando uma validação mais refinada é necessária. E também funciona em subtipos.

FWIW, estamos planejando ter essa classe ValidationBase ao vivo no Toolkit, para que você não precise escrever esse código clichê sozinho.

Isso não é bom. E se minhas entidades já tiverem uma classe base? É também por isso que não sou tão fã de INotifyDataErrorInfo . As propriedades do INPC já são uma dor de cabeça para si mesmas, especialmente ao lidar com aplicativos de dados massivos com toneladas de entidades.

É bastante chocante que a UWP ainda não tenha validação adequada. Esse é um recurso básico crucial em quase qualquer aplicativo e deve ter prioridade.

É bastante chocante que a UWP ainda não tenha validação adequada. Esse é um recurso básico crucial em quase qualquer aplicativo e deve ter prioridade.

Sim, é por isso que estamos trabalhando nisso :)

Isso não é bom. E se minhas entidades já tiverem uma classe base?

Estou apenas tentando entender seu uso aqui. Qual é a classe base e ela poderia derivar dessa classe?

Sim, é por isso que estamos trabalhando nisso :)

Obrigado, muito apreciado. Isso e o resto do seu trabalho.
O que o rótulo needs-winui-3 implica?

Estou apenas tentando entender seu uso aqui. Qual é a classe base e ela poderia derivar dessa classe?

Estou usando o OData Connected Service para obter entidades geradas no meu cliente.
Os objetos gerados são deste padrão:

c# public abstract partial class ContactBase : Microsoft.OData.Client.BaseEntityType, INotifyPropertyChanged

O que o rótulo needs-winui-3 implica?

@weitzhandler
Isso implica que a validação de entrada virá com o WinUI 3. (3.0 como planejado atualmente). Provavelmente não chegará ao WinUI 2, pois isso exigiria alterações no código OS XAML que está no modo de manutenção agora.

Estou usando UWP em um aplicativo Uno Platform. Espero que o WinUI seja coberto após seu lançamento.
Obrigado pela atualização tb!

Estou apenas tentando entender seu uso aqui. Qual é a classe base e ela poderia derivar dessa classe?

Ter uma classe base geralmente é exigido por terceiros, por exemplo, a estrutura de persistência que você usa. UWP/WinUI também exigir uma classe base apenas para validação não é uma opção. Precisa ser uma interface para ser útil, nenhuma de nossas aplicações poderia fazer uso de uma classe base. (Isso não significa que você não pode ter uma classe base para as pessoas que querem usá-la, ela só precisa ser opcional e não a única maneira de fazer validação.)

Ter uma classe base geralmente é exigido por terceiros, por exemplo, a estrutura de persistência que você usa. UWP/WinUI também exigir uma classe base apenas para validação não é uma opção. Precisa ser uma interface para ser útil, nenhuma de nossas aplicações poderia fazer uso de uma classe base.

Vamos recuar um pouco. Acho que os últimos comentários que fiz causaram um pouco de confusão, o que é ruim para mim.

Tudo o que será necessário para o modelo é implementar System.ComponentModel.INotifyDataErrorInfo (ou Windows.UI.Xaml.Data.INotifyDataErrorInfo para C++). O compilador irá gerar corretamente o código para conectá-lo à sua visualização ao usar {x:Bind} .

A classe ValidationBase que mencionei acima é uma classe auxiliar que estávamos planejando enviar no kit de ferramentas da comunidade que implementa isso, junto com INotifyPropertyChanged . Não há necessidade de derivar dele se o seu caso de uso não permitir.

Obrigado pelo seu esclarecimento @stevenbrix.

E quanto aos atributos de validação e IValidatableObject , eles serão respeitados pelo tempo de execução da UWP?

Que tal outros atributos, como o atributo MaxLength que você mencionou anteriormente, um comprimento máximo TextBox será definido automaticamente como no ASP.NET?
O mesmo com DataTypeAttribute , EditableAttribute .
Também DisplayAttribute para gerar cabeçalhos de campo.
Tanto quanto me lembro, todos eles eram suportados no Silverlight.

(veja isso ).

E quanto aos atributos de validação e IValidatableObject, eles serão respeitados pelo tempo de execução da UWP?

Portanto, atualmente teremos suporte para o atributo Required . Alguns controles colocarão automaticamente um pequeno asterisco ao lado do texto do cabeçalho quando isso for usado. Estamos abertos a apoiar mais no futuro, se você quiser. Por favor, abra um problema separado se você quiser ver mais, e apenas para definir as expectativas, é altamente improvável que qualquer suporte de atributo extra faça a versão inicial do WinUI3.

Quanto a IValidatableObject , não tenho certeza de como isso funcionaria. Como generalização, nosso mecanismo funciona simplesmente ouvindo o evento INotifyDataErrorInfo.ErrorsChanged . A validação real do modelo depende do desenvolvedor do aplicativo e geralmente é feita ao transferir o valor do destino para a origem.

Talvez como método alternativo ao ValidationBase que você propôs, deveria haver um conjunto de métodos de extensão, que executassem um processo de validação usando Validator.TryValidateObject , e injetassem os resultados da validação na entidade, notificando as alterações ?
Dessa forma, isso pode ser alcançado facilmente apenas implementando INotifyDataErrorInfo . Também poderíamos ter uma interface que herda de INotifyDataErrorInfo que adiciona uma propriedade que contém a coleção de erros, para que o tempo de execução da UWP ou o kit de ferramentas possa reconhecer como uma entidade validável automatizada e definir a propriedade automaticamente se implementada.

Talvez como método alternativo ao ValidationBase que você propôs, deveria haver um conjunto de métodos de extensão, que executassem um processo de validação usando Validator.TryValidateObject, e injetassem os resultados da validação na entidade, notificando as alterações?

Esta é uma ótima idéia :)

🦙 Quer saber se os novos paradigmas do gerador de fontes também podem ajudar aqui?

Sim @michael-hawker, gosto dos seus pensamentos!

Eu tive os mesmos pensamentos um tempo atrás, quando li pela primeira vez sobre as novas possibilidades do gerador de fonte.

Acho que com os novos paradigmas do gerador de fonte podemos construir/gerar muitas coisas nos bastidores para INotifyDataErrorInfo e INotifyPropertyChanged.

Eu tenho um curso WPF no Pluralsight que faz exatamente isso com T4, INotifyPropertyChanged e INotifyDataErrorInfo, incluindo anotações de dados para validação: https://www.pluralsight.com/courses/wpf-mvvm-advanced-model-treatment
O curso também usa Propriedades anexadas personalizadas para conectar coisas.
O objetivo deste curso é mostrar como você pode construir um aplicativo MVVM WPF que mostre em cada campo de entrada se ele foi alterado e qual era o valor original.

Então, definitivamente, gerar coisas e talvez terminar com uma biblioteca (talvez como parte do WCT) seria incrível. E eu adoraria refazer esse curso para WinUI. :)

@rufw91 Eu sei, certo?!

Quais são suas limitações de tempo? A primeira implementação disso está na versão alfa do WinUI3, e devemos ter uma visualização para a área de trabalho do WinUI em breve no período de //Build. Planejamos fazer RTM'ing até o final do ano

@stevenbrix Espero que sim, tive que voltar para o WPF, na verdade estou quase pronto agora.

Eu abri este .

Para acompanhar isso, depois de uma conversa com @stevenbrix no Twitter, integrei a implementação básica INotifyDataErrorInfo que ele forneceu aqui em uma nova classe ObservableValidator que está sendo incluída no novo MVVM Toolkit (o biblioteca Microsoft.Toolkit.Mvvm ), que também implementa INotifyPropertyChanged e INotifyPropertyChanging 😄

Você pode ver o código relacionado e uma recapitulação de tudo relacionado a essa biblioteca nesta edição .
Também incluí links para a edição original do MVVM Toolkit, bem como mais documentos para novos desenvolvedores.

Você poderia, por favor, nos dar uma atualização sobre isso? Curioso se UWP 10.0 18362 suporta INotifyDataErrorInfo . De acordo com a página de documentação a seguir, https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifydataerrorinfo?view=netcore-3.1 INotifyDataErrorInfo "aplica-se" à UWP 10.0. No entanto, com o UWP 10.0 18362 instalado e direcionado, as caixas de texto não exibem validações INotifyDataErrorInfo . As caixas de texto são descritas em XAML da seguinte forma:

<TextBox Text="{x:Bind ViewModel.Username, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

E usamos ReactiveValidationObject como implementação de INotifyDataErrorInfo aqui.

@worldbeater isso está disponível apenas nas últimas visualizações do WinUI3, você está usando isso?

Obrigado @stevenbrix! Vou experimentar o WinUI3. Fico feliz em saber que INotifyDataErrorInfo e UWP estão fazendo amizade, finalmente ✨

@worldbeater , ainda está em pré-visualização, então adoraríamos receber seus comentários sobre isso! 💪

@worldbeater a propósito, a documentação diz que está disponível no UWP 10.0, mas não significa que seja suportado por ele. A documentação não é clara o suficiente.

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