このシナリオでは、お勧めのようにIMultiValueConverter
を使用できます。しかし、他のシナリオでは有用なツールですが、それはここの仕事にとって間違ったツールです。その理由は、この場合、非UIデータを格納する場所としてのUI要素の不適切な使用を永続させるためです。
WPFプログラムの作成中は、MVVMスタイルのプログラミングに従うことをお勧めします。用語「MVVM」は、文字通り「モデル、ビュー、ビューモデル」を意味します。その観点から、モデルとビューの間には、常に専用の「アダプター」タイプがあります。しかし、MVVMのパラダイムの重要な部分は、ビューロジックをモデルロジックから分離することについて厳密にすることです。これは、「ビューモデル」タイプの余分なレイヤーなしで行うことができます。これにより、MVVMはMVC(「モデル、ビュー、コントローラ」)およびMVP(「モデル、ビュー、プレゼンター」)と同じツールセットに置かれます。
これらのすべての鍵は、モデルデータ構造で表現されるビジネスロジックを持ち、値の変更された通知(WPFでは、主なメカニズムはINotifyPropertyChanged
)を提供する型によって実装されていることです。完全に別々に表現されたロジックを表示することもできます(WPFでは、ほとんどの場合、多くの場合、XAMLで宣言されています)。
この例では、サンプルデータ、キャリブレータ、コントロール、および合計プリペット数など、関心のあるデータを表すモデルデータ構造が必要です。最後のものは単に最初の3つの合計です。これらを追跡し、他の3つが変更されたときに合計値を正しく更新できるクラスがあれば、XAMLで宣言されたビューにこれを直接バインドすることができます。すべて。例えば
:
class ViewModel : INotifyPropertyChanged
{
private int _sampleCount;
public int SampleCount
{
get { return _sampleCount; }
set { _UpdateField(ref _sampleCount, value, OnCountChanged); }
}
private int _calibratorCount;
public int CalibratorCount
{
get { return _calibratorCount; }
set { _UpdateField(ref _calibratorCount, value, OnCountChanged); }
}
private int _controlCount;
public int ControlCount
{
get { return _controlCount; }
set { _UpdateField(ref _controlCount, value, OnCountChanged); }
}
private int _totalPrepCount;
public int TotalPrepCount
{
get { return _totalPrepCount; }
set { _UpdateField(ref _totalPrepCount, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnCountChanged(int previousValue)
{
TotalPrepCount = SampleCount + CalibratorCount + ControlCount;
}
protected void _UpdateField<T>(ref T field, T newValue,
Action<T> onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
注:
- 上記のクラスは、4つのプロパティ、我々はを追跡する値ごとに1つのプロパティがあります。
- 3つのプロパティは単なる値のコンテナです。それらが変更されたときに呼び出されるコールバックメソッドがあります。そのメソッドでは、コードは4番目のプロパティを3つの合計に設定します。
INotifyPropertyChanged
インターフェイスには、ただ1つのメンバー、PropertyChanged
イベントがあります。 MVVMスタイルのコードを扱うときには、実際にこのイベントを実装する基本クラスと、上記の_UpdateField()
メソッドのようなヘルパーメソッドを持つと便利です。これらのプロパティーセッターは、それぞれのプロパティに必要な繰り返しロジックを処理するために呼び出すことができます。上記の例では、例を簡略化するために、このロジックをすべて1つのクラスにまとめましたが、適切な基本クラスを維持することをお勧めします(私と他の多くの人がVisual Studioでスニペットを設定しましたこのボイラープレートコードをプロジェクトに簡単に挿入できます)。その定義されたビューモデルで
、XAMLは、このような何かに見えるように簡略化されています
<Window x:Class="TestSO45170241SliderExample.MainWindow"
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:l="clr-namespace:TestSO45170241SliderExample"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:ViewModel/>
</Window.DataContext>
<Grid>
<Label Content="Sample Selection" FontSize="16" FontStyle="Italic" FontWeight="Bold"
HorizontalAlignment="Left" Margin="0,-30,0,0" VerticalAlignment="Top"/>
<Label Content="Patient Samples (max 64)" HorizontalAlignment="Left" Margin="10,10,0,0"
VerticalAlignment="Top" FontStyle="Italic"/>
<Slider HorizontalAlignment="Left" Margin="181,14,0,0"
VerticalAlignment="Top" Cursor="Hand" Width="160" Maximum="64"
Value="{Binding SampleCount}" IsSnapToTickEnabled="True"/>
<TextBlock HorizontalAlignment="Left" Margin="165,16,0,0"
TextWrapping="Wrap" Text="{Binding SampleCount}" VerticalAlignment="Top"/>
<Label Content="Calibrators (max 7)" HorizontalAlignment="Left" Margin="10,36,0,0"
VerticalAlignment="Top" FontStyle="Italic"/>
<Slider HorizontalAlignment="Left" Margin="181,40,0,0"
VerticalAlignment="Top" Cursor="Hand" Width="160" Maximum="7"
Value="{Binding CalibratorCount}" IsSnapToTickEnabled="True"/>
<TextBlock HorizontalAlignment="Left" Margin="165,42,0,0"
TextWrapping="Wrap" Text="{Binding CalibratorCount}" VerticalAlignment="Top"/>
<Label Content="Control Samples (max 4)" HorizontalAlignment="Left" Margin="10,62,0,0"
VerticalAlignment="Top" FontStyle="Italic"/>
<Slider HorizontalAlignment="Left" Margin="181,66,0,0"
VerticalAlignment="Top" Cursor="Hand" Width="160" Maximum="4"
Value="{Binding ControlCount}" IsSnapToTickEnabled="True"/>
<TextBlock HorizontalAlignment="Left" Margin="165,68,0,0"
TextWrapping="Wrap" Text="{Binding ControlCount}" VerticalAlignment="Top"/>
<Label Content="Total Sample Preparations Selected:" HorizontalAlignment="Left"
Margin="10,105,0,0" VerticalAlignment="Top" FontWeight="Bold" FontStyle="Italic"/>
<TextBlock HorizontalAlignment="Left" Margin="225,110,0,0"
FontWeight="Bold" FontStyle="Italic" Text="{Binding TotalPrepCount}"
VerticalAlignment="Top"/>
</Grid>
</Window>
を(脇:MVVMのアプローチをサポートするために変更すること以外に、私はあなたの基本は変更されませんでしたWPFのさまざまなレイアウトコンテナと要素のスタイリング機能を利用する方法は、親しみを持たせることがまず必要なことだと私は同意しますが、ここでそれらを紹介すると、問題が混乱するだけです。元のUIはほとんど変わっていませんが、元々のものとは異なるものに集中でき、賭けを理解するのに役立ちますER伸延なし側面を結合データ。)この実装で
は、全くMainWindow.xaml.cs
ファイルに追加ないコードは存在しません。そのファイルにあるのはコンストラクタのInitializeComponent()
へのデフォルト呼び出しで、Visual StudioのWPFプロジェクト用テンプレートから提供されます。
XAMLでは、イベントハンドラサブスクリプションをSlider.Value
プロパティに直接バインドしました。 TextBlock.Text
プロパティも同じプロパティにバインドされていることにも注意してください。このようにしてWPFは、スライダ値をビジネスロジックのみのデータ構造に格納し、ビュー内のテキストフィールドにそれらの値を再表示するという重い作業をすべて行います。ビューモデルはint
値を格納しますが、スライダはdouble
を使用し、テキストブロックはもちろんstring
を使用します。
もちろん、TotalPrepCount
フィールドは、表示のために興味のあるプロパティにも拘束されています。
最後に、私も自分の単純な例では、あなたは1本のデータバインディングアプローチを適用したい場合があり、追加の場所を持っていることに注意しましょう。特に、スライダにはそれぞれ最大値があり、ビューにハードコードされています。 MVVMの目的は、ビューがビジネスロジックについての知識をにカプセル化する必要がないことです。これには、許可される値のすべての範囲(*)を知る必要がないことも含まれます。
だから、あなたのビューモデルはまた、例えばかもしれませんSlider.Maximum
プロパティとLabel.Content
プロパティの両方にバインドされているMaxSampleCount
プロパティです。後者の場合、Binding.StringFormat
プロパティを使用して、値を適切なテキストに組み込むことができます。たとえば:
<Label Content="{Binding MaxSampleCount, StringFormat=Patient Samples (max {0})" ... />
私は容易にネイティブのWin32コントロールのようなUI APIを使用しての何年も何年も後に、MFC、Windowsフォーム、JavaのAPIを(スイング、AWT、私が最初にWPFを使用しようとし始めたときにすることを認めますSWT)、そしてMac OSのCocoaフレームワーク(データバインディングの形式を使用していますが、XAMLのような宣言的UIは使用していません)でも、私は、他のすべてのAPIで使用されている手続き型アプローチから、 WPFで使用される宣言的および手続き的アプローチ。
しかし、私は、ほとんどの場合、密最高で書かれているMSDNで提供されるドキュメントから厳密にそれを学ぶために、単なる従うことが難しく、多くの場合、完全に役に立たないしようとしていました。誰かが私に、私が上に示したような例を見せてくれたなら(そして彼らは存在していましたが、元気でした;私はどこにいたのかわかりませんでした)、MVVMの基本的なアプローチがどれほど簡単か分かりました。そのアプローチに従えば、WPFプログラムを書くことがどれほど迅速にできるのでしょうか。
私は上記のあなたがWPFの生産的使用のために軌道に乗ることができますし、分かりやすい方法で、あなたの基本を示したいと考えています。
レイアウトを作成する代わりに、 'Margin'のコンテナ(行/列の' Grid'、 'StackPanel'、等)を使用してみてください。問題は、すべてのイベントハンドラが呼び出すメソッドに計算を移し、そこでテキストを設定します。バインディング+ MVVMの使用を開始し、プロパティ 'public double Sum => ...'を作成し、sumを計算するために使用されるすべてのプロパティの通知( 'INotifyPropertyChanged')を上げる方が簡単です。 – Sinatr
@Sinatrご回答いただきありがとうございます!できるだけ早くこれを調べて、成功すれば教えてあげましょう! – WSU
binding + mvvmもっと簡単にアプローチできますか?あなたは深刻ですか?始まっている男のためにそれはwaaayyより難しいです。それは彼が望むことをする "プロ"の方法かもしれませんが、確かに最も簡単ではない、彼はスライダが変わるたびにテキストを更新するメソッドを作成することができます。 –