本当にTextChanged
イベントを処理する必要がありますか? Text
プロパティにバインドするだけで、変更を通知できます。
<TextBox Text="{Binding TextValue, Mode=TwoWay}" />
そして、ビューモデルで:
private string _textValue;
public string TextValue
{
get
{
return _textValue;
}
set
{
if (_textValue == value)
return;
_textValue = value;
OnTextChanged(value); // react to the changed value
}
}
編集:
Text
内部から値を取得したい場合は、次の 2 つの点に注意する必要がありますCommand
。
まず、CommandParameter
バインディングを修正する必要があります。を使用{Binding Text}
すると、実際にビュー モデルのプロパティにバインドしようとします。つまり、最初にTextBox.Text
プロパティを同じビュー モデル プロパティにバインドする必要があります。コメントで言ったように、フォーカスの喪失だけでなく、すべての変更に関する情報が必要なため、得られる値は十分に最新ではないため、それはあなたにとっては良くありません。
したがって、正しいアプローチは 2 回目の試み、つまり構文TextBox
を使用して に直接バインドすることです。ElementName
残念ながら、トリガーはビジュアル ツリーの一部ではないため、XAML ネーム スコープにアクセスできません (詳細については、このブログ投稿を参照してください)。MVVMHelpers.Metro パッケージNameScopeBinding
から使用することで、これを回避できます。
<Behaviors:NameScopeBinding x:Key="MyTextBox"
Source="{Binding ElementName=MyTextBox}" />
ElementName
これでバインディングを機能させることができます:
<i:InvokeCommandAction Command="{Binding UpdateText}"
CommandParameter="{Binding Source.Text, Source={StaticResource MyTextBox}}"/>
あなたはまだ2番目の問題を抱えています。バインドしている値は、フォーカスが失われたときにのみ更新されるため、イベントText
を処理するときに正しい値を取得できません。解決策は、それ自体TextChanged
にバインドすることです。TextBox
<i:InvokeCommandAction Command="{Binding UpdateText}"
CommandParameter="{Binding Source, Source={StaticResource MyTextBox}}"/>
そして、コマンド内でText
から直接プロパティを取得しますTextBox
:
private void OnUpdateText(object parameter)
{
var value = ((TextBox) parameter).Text;
// process the Text value as you need to.
}
編集2:
PCL にあるビュー モデルで上記のコードを動作させるには、いくつかの方法があります。
最も単純なハックは、リフレクションを使用することです。PCL で使用できるため、Text
プロパティにアクセスしてその値を読み取ることができます。
private void OnUpdateText(object parameter)
{
var textProperty = textSearch.GetType().GetProperty("Text");
var value = textProperty.GetValue(parameter, null) as string;
// process the Text value as you need to.
}
よりクリーンなソリューションは、WinRT 固有のコードを、インターフェイスを介して抽象化された別のアセンブリに配置することです。まず、PCL ライブラリにインターフェイスを作成します。
public interface IUiService
{
string GetTextBoxText(object textBox);
}
ビュー モデルを変更して、コンストラクターでこのインターフェイスを受け入れるようにします。
public ViewModel(IUiService uiService)
{
_uiService = uiService;
}
コマンド ハンドラーでは、インターフェイスでメソッドを使用します。
private void OnUpdateText(object parameter)
{
var value = _uiService.GetTextBoxText(parameter);
// process the Text value as you need to.
}
そのインターフェイスを WinRT ライブラリに実装します。
public class UiService : IUiService
{
public string GetTextBoxText(object textBox)
{
var typedTextBox = textBox as TextBox;
return typedTextBox.text;
}
}
アプリケーションでは、このライブラリを参照し、実装をビュー モデルに渡します。
var viewModel = new ViewModel(new UiService);
私のお気に入りのアプローチは異なります。イベントがトリガーされるたびに自動的に更新されるプロパティBehavior
を公開するように作成します。Text
TextChanged
public class TextChangedBehavior : Behavior<TextBox>
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(TextChangedBehavior),
new PropertyMetadata(null));
public string Text
{
get { return (string) GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.TextChanged += OnTextChanged;
Text = AssociatedObject.Text;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.TextChanged -= OnTextChanged;
}
private void OnTextChanged(object sender, TextChangedEventArgs textChangedEventArgs)
{
Text = AssociatedObject.Text;
}
}
TextValue
この長い回答の冒頭ですでに提案されているように、プロパティをこの動作にバインドし、プロパティ セッターの変更に反応することができます。
<TextBox>
<i:Interaction.Behaviors>
<b:TextChangedBehavior Text="{Binding TextValue, Mode=TwoWay}" />
</i:Interaction.Behaviors>
</TextBox>