MVVMを実際に使用している場合は、[OK]ボタンのクリックを誰かが処理する必要がありますCommand
。このコマンドは、から来ている必要がありますViewModel
。バインドされたExpliticly
プロパティは、再びあなたから来ている必要がありますViewModel
。だから何があなたを止めていますか。
- バインディングを使用せず、
Explicit
バインディングを使用しますOneWay
。
- ボタンで、コマンドをバインドし、コマンドパラメーターを
OneWay
バインドされたDependencyプロパティにバインドします。
- コマンドの実行ハンドラー(ViewModelのメソッドである必要があります)で、パラメーターが来るようにViewModelのプロパティを変更します。
NotifyPropertyChanged
あなたのからそのプロパティのを上げますViewModel
。
例えば
[OK]ボタンをクリックすると、TextBoxのテキストをモデルに更新する必要があると仮定します。
そのために、プロパティEmployeeViewModel
を持つクラスがありEmployeeName
ます。プロパティには、ゲッターとセッターがあります。セッターはプロパティ変更通知を発行します。ビューモデルには、実行するコマンドを返すICommand
という名前の別のプロパティもあります。SaveNameCommand
EmployeeViewModel
私のビューのデータコンテキストタイプです。MyviewにはTextBox
(x:Name = "EmployeeNameTxBx"という名前の)OneWay
がバインドされてEmployeeName
おり、ボタンは。としてバインドされていOK
ます。Button.Command
プロパティをEmployeeViewModel.SaveNameCommand
プロパティにバインドし、プロパティにButton.CommandParameter
バインドしEmployeeNameTxBx.Text
ます。
<StackPanel>
<TextBox x:Name="EmployeeNameTxBx"
Text="{Binding EmployeeName, Mode=OneWay}" />
<Button Content="OK"
Command="{Binding SaveNameCommand}"
CommandParameter="{Bidning Text, ElementName=EmployeeNameTxBx}" />
</StackPanel>
私の中EmployeeViewModel
には、自分のOnSaveNameCommandExecute(object param)
を実行するメソッドがありSaveNameCommand
ます。
これでこのコードを実行します...
var text = (string)param;
this.EmployeeName = text;
この方法では、[OK]ボタンをクリックするだけで、TextBoxのテキストEmployeeName
がモデルのプロパティに更新されます。
編集
以下のコメントを見ると、UIに検証を実装しようとしていることがわかります。今、これは物事を少し変えます。
IDataErrorInfo
および関連する検証は、入力コントロール(TextBoxなど)がTwoWayにバインドされている場合にのみ機能します。はい、それが意図された方法です。では、「これは、IDataErrorInfoを使用する場合、モデルへの無効なデータの受け渡しを許可しないという概念全体がMVVMでは無駄であることを意味しますか?」
実際はそうではなくて!
MVVMは、有効なデータのみが返される必要があるというルールを適用しないを参照してください。それは無効なデータを受け入れ、それがどのようにIDataErrorInfo
機能し、エラー通知を発生させるかです。重要なのは、ViewModelはビューの単なるソフトコピーであるため、汚れている可能性があるということです。確認する必要があるのは、この汚れがサービスやデータベースなどの外部インターフェイスにコミットされていないことです。
ViewModel
このような無効なデータフローは、無効なデータをテストすることによって制限する必要があります。TwoWay
バインディングを有効にすると、そのデータが表示されます。したがって、実装していることを考えると、MVVMで完全に許可されIDataErrorInfo
ているバインディングが必要です。TwoWay
アプローチ1:
ボタンクリック時にUIの特定のアイテムを明示的に検証したい場合はどうなりますか?
これには、遅延検証トリックを使用します。ViewModelには、isValidatingというフラグがあります。デフォルトではfalseに設定します。
IDataErrorInfo.this
プロパティで、isValidatingフラグをチェックして検証をスキップします...
string IDataErrorInfo.this[string columnName]
{
get
{
if (!isValidating) return string.Empty;
string result = string.Empty;
bool value = false;
if (columnName == "EmployeeName")
{
if (string.IsNullOrEmpty(AccountType))
{
result = "EmployeeName cannot be empty!";
value = true;
}
}
return result;
}
}
次に、OKコマンド実行ハンドラーで、従業員名を確認してから、同じプロパティのプロパティ変更通知イベントを発生させます...
private void OnSaveNameCommandExecute(object param)
{
isValidating = true;
this.NotifyPropertyChanged("EmployeeName");
isValidating = false;
}
これにより、[OK]をクリックした場合にのみ検証がトリガーされます。EmployeeName
検証が機能するには、無効なデータが含まれている必要があることに注意してください。
アプローチ2:
MVVMでTwoWayモードなしでバインディングを明示的に更新したい場合はどうなりますか?
次に、を使用する必要がありますAttached Behavior
。ビヘイビアーは[OK]ボタンにアタッチされ、バインディングを更新する必要があるすべてのアイテムのリストを受け入れます。
<Button Content="OK">
<local:SpecialBindingBehavior.DependentControls>
<MultiBinding Converter="{StaticResource ListMaker}">
<Binding ElementName="EmployeeNameTxBx" />
<Binding ElementName="EmployeeSalaryTxBx" />
....
<MultiBinding>
</local:SpecialBindingBehavior.DependentControls>
</Button>
これListMaker
は、IMultiValueConverter
値をリストに変換するだけのaです。
Convert(object[] values, ...)
{
return values.ToList();
}
プロパティが変更されたハンドラーSpecialBindingBehavior
があります...DependentControls
private static void OnDependentControlsChanged(
DependencyObject depObj,
DependencyPropertyChangedEventArgs e)
{
var button = sender as Button;
if (button != null && e.NewValue is IList)
{
button.Click
+= new RoutedEventHandler(
(object s, RoutedEventArgs args) =>
{
foreach(var element in (IList)e.NewValue)
{
var bndExp
= ((TextBox)element).GetBindingExpression(
((TextBox)element).Textproperty);
bndExp.UpdateSource();
}
});
}
}
ただし、以前の純粋なMVVMベースの**アプローチ1を使用することをお勧めします。