2

MvmmCross v3 フレームワークとWindows.UI.Interactivityを使用して WinRT に取り組んでいます。

コマンドを起動するイベント TextChanged で EventTrigger を持つ TextBox が必要です。また、CommandParameter に textBox のテキストが必要です。

だから私はこのコードを持っています

   <i:EventTrigger EventName="TextChanged">
                    <i:InvokeCommandAction  Command="{Binding UpdateText}" CommandParameter="{Binding Text}"/>
                </i:EventTrigger>


public ICommand UpdateText
{
    get
    {
        return new MvxCommand<object>((textSearch) =>
            {
                // code...
            });
    }
}

しかし、私の textSearch パラメーターは "{Windows.UI.Xaml.Controls.TextChangedEventArgs}" に等しく、これらのプロパティはすべて NULL です。

次のようなバインディングで ElementName を明示的に宣言しようとしました

CommandParameter="{Binding Path=Text, ElementName=tes}

しかし、それも失敗しました。

ありがとう

4

1 に答える 1

7

本当に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を公開するように作成します。TextTextChanged

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>
于 2013-06-04T05:58:36.067 に答える