Ho utilizzato WPF per sviluppare due applicazioni di dimensioni moderate. Sono rimasto molto impressionato dalla pulizia di WPF e dalle sue caratteristiche. Quando ho spiegato a uno dei miei colleghi (che succede a sviluppare applicazioni di business) i vari benefici di WPF, mi ha sfidato con questo problema che mi aveva totalmente perplesso:Qual è la risposta WPF a questo?
Il problema:
ha codificato un applicazione nel modo seguente in circa 2 minuti:
- Aprire un nuovo progetto WinForms.
- Definire una classe
Loan
. - Progetto di costruzione.
- Definire un'origine dati oggetto utilizzando
Loan
. - In Explorer origini dati, modificare il tipo di visualizzazione dell'origine dati
Loan
in Dettagli. - Trascinare l'origine dati sul modulo nella finestra di progettazione.
- Fornire l'origine dati con un
Loan[]
contenente un oggetto. - Costruisci ed esegui l'applicazione.
Il codice:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WinForms_DataBinding_Example
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
loanBindingSource.DataSource = new Loan[] { new Loan() };
}
}
public class Loan
{
public decimal Amount { get; set; }
public decimal Rate { get; set; }
public decimal Total { get { return Amount * Rate; } }
}
}
Il progettista:
L'applicazione:
Ora ogni volta si modifica il valore di Amount
o Rate
nella finestra, il valore di Total
cambia di conseguenza. Dopo aver spiegato che questa è una funzionalità molto utile nelle app aziendali in cui qualsiasi modifica apportata a una proprietà in un'entità aggiorna immediatamente la vista in cui le proprietà calcolate vengono aggiornate istantaneamente rendendo l'esperienza utente migliore. Considerando che la tipica classe di entità aziendale ha molte proprietà, questo consente di risparmiare un sacco di codice. Poi mi ha chiesto di fare lo stesso in WPF.
Prima gli ho spiegato che non capisco che tipo di magia nera va avanti qui. Come si aggiorna automaticamente la casella di testo ? Questa è la mia prima domanda:
Q1. La classe Loan
non implementa INotifyPropertyChanged
o qualcosa di simile. Quindi, come viene aggiornata la casella di testo quando le caselle di testo o perdono lo stato attivo?
Poi gli ho detto che non so come fare la stessa cosa così facilmente in WPF. Tuttavia, ho scritto la stessa app in WPF con 3 TextBlock
se 3 TextBox
s nell'interfaccia utente. Dovevo anche realizzare l'attrezzo Loan
della classe INotifyPropertyChanged
. Aggiunti i campi di supporto a Amount
e Rate
. Ogni volta che queste proprietà venivano impostate, ho sollevato una notifica di modifica delle proprietà per la proprietà Total
. Alla fine, mi è rimasta una app con controlli mal allineati che ha fatto la stessa cosa dell'app WinForms.Tuttavia, questo era molto più difficile da fare rispetto al metodo WinForms.
Sono tornato a casa e ho avuto la brillante idea di trascinare l'origine dati Loan
sulla finestra WPF (dopo aver modificato la modalità di visualizzazione per i dettagli). Abbastanza sicuro, ho avuto lo stesso tipo di interfaccia utente come nell'app WinForms e dopo aver impostato l'origine dati sullo stesso Loan[]
come nell'app WinForms, sembrava essere completo. Ho eseguito l'app, modificato i campi Amount
e Rate
sperando di vedere Total
cambiarsi automaticamente. Tuttavia, sono rimasto deluso. Il campo Total
non è cambiata:
Il codice:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WinForms_DataBinding_Example;
namespace WPF_Grid_Example
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
System.Windows.Data.CollectionViewSource loanViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("loanViewSource")));
// Load data by setting the CollectionViewSource.Source property:
loanViewSource.Source = new List<Loan>() { new Loan() };
}
}
}
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:WinForms_DataBinding_Example="clr-namespace:WinForms_DataBinding_Example;assembly=WinForms_DataBinding_Example" mc:Ignorable="d" x:Class="WPF_Grid_Example.MainWindow"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded_1">
<Window.Resources>
<CollectionViewSource x:Key="loanViewSource" d:DesignSource="{d:DesignInstance {x:Type WinForms_DataBinding_Example:Loan}, CreateList=True}"/>
</Window.Resources>
<Grid>
<Grid x:Name="grid1" DataContext="{StaticResource loanViewSource}" HorizontalAlignment="Left" Margin="121,123,0,0" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Content="Amount:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="0" VerticalAlignment="Center"/>
<TextBox x:Name="amountTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="0" Text="{Binding Amount, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
<Label Content="Rate:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="1" VerticalAlignment="Center"/>
<TextBox x:Name="rateTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="1" Text="{Binding Rate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
<Label Content="Total:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="2" VerticalAlignment="Center"/>
<TextBox x:Name="totalTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="2" Text="{Binding Total, Mode=OneWay}" VerticalAlignment="Center" Width="120"/>
</Grid>
</Grid>
</Window>
Q2. Sono stato confuso prima dalla magia nera di WinForms, ero confuso ora perché la stessa magia nera non funzionava in WPF. Perché?
Q3. Come faccio a rendere la versione WPF per aggiornare automaticamente il campo Total
come nell'esempio WinForms?
Q4. Quale piattaforma è migliore/più veloce per questo tipo di sviluppo di app aziendali? Se devo fare una discussione migliore per conto di WPF, cosa dovrei guardare?
Spero di essere stato chiaro riguardo al problema. Per favore fatemi sapere se sono necessari chiarimenti. Grazie.
wow .. Sono impressionato, winforms può generare automaticamente uno schermo con 3 caselle di testo ... e allora? qualsiasi altra cosa è impossibile in winforms, mentre WPF ti dà la possibilità di personalizzare TUTTO e di associare QUALSIASI COSA a QUALSIASI COSA, non solo, ad esempio la proprietà Text, come in winforms. Le applicazioni line-of-business del mondo reale non sono semplici caselle di testo, richiedono una logica molto complessa, e Winform richiede un codice infernale per fare applicazioni reali, contro le proprietà semplici e XAML. –
@HighCore: sono sicuro che hai ragione. Ma il tuo commento non risponde a nessuna delle mie domande. :( – nakiya
In generale, mi sembra che si stiano confrontando due framework basati su un caso d'uso specifico, non credo che porti a risultati equi – Ameen