7

私は WPF を使用して、適度なサイズのアプリケーションを 2 つ開発しました。WPF のクリーンさとその機能に感銘を受けました。同僚の 1 人 (たまたまビジネス アプリを開発している) に WPF のさまざまな利点を説明したとき、彼は次の問題について私に挑戦し、私は完全に困惑しました。

問題:

彼は、約 2 分で次のようにアプリケーションをコーディングしました。

  1. 新しい WinForms プロジェクトを開きます。
  2. クラスを定義しLoanます。
  3. プロジェクトをビルドします。
  4. を使用してオブジェクト データ ソースを定義しますLoan
  5. データ ソース エクスプローラーで、Loanデータ ソースのビュー タイプを [詳細] に変更します。
  6. データ ソースをデザイナーのフォームにドラッグします。
  7. Loan[]1 つのオブジェクトを含むデータ ソースを提供します。
  8. アプリケーションをビルドして実行します。

コード:

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

デザイナー:

ここに画像の説明を入力

アプリケーション:

ここに画像の説明を入力

ウィンドウ内でAmountまたはの値を変更すると、それに応じて の値も変更されます。これはビジネス アプリで非常に便利な機能であることを説明した後、エンティティ内の 1 つのプロパティに変更を加えるとすぐにビューが更新され、計算されたプロパティが即座に更新され、ユーザー エクスペリエンスが向上します。典型的なビジネス エンティティ クラスには多くのプロパティがあることを考えると、これにより多くのコーディングを節約できます。それから彼は私にWPFで同じことをするように頼んだ。RateTotal

私は最初に、ここでどんな種類の黒魔術が行われているのかわからないことを彼に説明しました. テキストボックスはどのようにTotal自動的に更新されますか? これは私の最初の質問です:

Q1. クラスは実装されLoanていませんINotifyPropertyChanged。では、またはテキストボックスがフォーカスを失ったとき、テキストボックスはどのようTotalに更新されるのでしょうか?AmountRate

それから私は、WPF で同じことを簡単に行う方法がわからないことを彼に伝えました。ただし、 UIで 3TextBlock秒と 3秒の同じアプリを WPF で作成しました。また、クラスを実装TextBoxする必要がありました。とにバッキング フィールドを追加しました。これらのプロパティが設定されているときはいつでも、プロパティのプロパティ変更通知を発生させました。最終的に、WinForms アプリと同じことを行うコントロールが適切に配置されていないアプリが残っていました。ただし、これは WinForms メソッドよりもはるかに困難でした。LoanINotifyPropertyChangedAmountRateTotal

家に帰ってから、LoanデータソースをWPFウィンドウにドラッグアンドドロップするという素晴らしいアイデアを思いつきました(表示モードを詳細に変更した後)。案の定、WinForms アプリと同じ種類の UI が得られ、データ ソースをLoan[]WinForms アプリと同じに設定したら、完成したように見えました。私はアプリを実行し、自動的に変更されることを期待してAmountRateフィールドを変更しました。Totalしかし、私はがっかりしました。Totalフィールドは変更されませんでした:

ここに画像の説明を入力

コード:

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. 以前は WinForms のブラック マジックに戸惑いましたが、WPF では同じブラック マジックが機能しないため、今は困惑しています。なんで?

Q3. TotalWinForms の例のように、フィールドを自動的に更新するように WPF バージョンを作成するにはどうすればよいですか?

Q4. この種のビジネスアプリの開発には、どのプラットフォームが優れている/高速ですか? WPF に代わってより良い議論をする場合、何を見ればよいでしょうか?

問題が明確だったことを願っています。説明が必要な場合はお知らせください。ありがとう。

4

2 に答える 2

6

Q1: Windows フォームのデザイナ ファイルを見ると、3 つのテキスト ボックスに対して約 300 行のコードが生成されていることがわかります。このコードの一部は次のようになります。

this.amountTextBox.DataBindings.Add(
    new System.Windows.Forms.Binding("Text", 
        this.loanBindingSource, "Amount", true));

Binding と BindingSource は連携してバインドされた値を更新し、値の 1 つが変更されるたびにすべてのバインドされたコントロールが更新されます (リフレクションを使用)。

Q2: WPF デザイナーは .Designer.cs ファイルと関連するコードの混乱を作成しないためです。INotifyPropertyChange を明示的に実装する必要があります。これは、たとえば MVVM Light の ViewModelBase を使用して簡素化できます。

public class Loan : ViewModelBase
{
    public decimal Amount
    {
        get
        {
            return this.amount;
        }
        set
        {
            if (Set(() => Amount, ref this.amount, value))
            {
                RaisePropertyChanged(() => Total);
            }
        }
    }

Q3: 1) Amount または Rate の変更により、そのプロパティだけでなく、計算されたプロパティ 'Total' についてもプロパティ変更通知が発生します。2) 金額とレートのバインドを変更します。Binding="{Binding Amount, UpdateSourceTrigger=LostFocus}"

Q4: WPF 質問なし (IMHO)。WPF の方法は、よりテストしやすく、保守しやすく、理解しやすいものです。

于 2013-02-13T18:44:05.347 に答える
1

Q4 への回答:

1 つのクラスに対して 3 つのばかげたテキスト ボックスを生成する機能を持つ winform に関係なく、WPF ははるかに優れた、スケーラブルで強力なフレームワークです。ハードウェアアクセラレーションなどによりパフォーマンスが大幅に向上し、次のようなwinformで大量のコードを使用するタスクを実行するためのコードがほとんどまたはまったく必要ありません。

<CheckBox x:Name="chk"/>
<TextBox IsEnabled="{Binding IsChecked,ElementName=chk}"/>

また、典型的な基幹業務アプリケーションは数千または数十万のレコードを処理する必要があり、UI 仮想化は大きな違いをもたらします

肝心なのは、winforms は、(winforms 自体よりも Visual Studio の機能である) いくつかのデザイナー グッズを持っているにもかかわらず、基幹業務に関しては実用的で適切ではないということです。

于 2013-02-13T17:24:27.943 に答える