3

私はMVVMパターンが初めてです。

TextChanged()イベントが発生するたびに、バインドされたIsEnabled()プロパティの状態が変わらないのはなぜだろうと思っていました。このイベントは、データの検証を確認するためにTextChanged()呼び出しています。IsValid()

私はこの単純なViewModelクラスを持っています

public class myViewModel : ViewModel
{
    public bool IsOk { get; set; }
    public RelayCommand OnValidateExecute { get; set; }

    public myViewModel()
    {
        OnValidateExecute = new RelayCommand(p => IsValid(), p => true);
    }

    public bool IsValid()
    {
        // other codes
        IsOk = MethodName();
        NotifyPropertyChanged("IsOk");
    }
}

ブレークポイントを設定するIsValid()と、コードは正常に動作しています。IsEnabledプロパティが期待どおりに機能しないのはなぜだろうと思っていました。

これは私のXAMLコードです

<TextBox ...other propeties here....>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="TextChanged">
            <i:InvokeCommandAction Command="{Binding OnValidateExecute}">
            </i:InvokeCommandAction>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</TextBox>

<Button x:Name="btnSave" IsEnabled="{Binding IsOk, Mode=TwoWay}" 
            ...other propeties here....>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <i:InvokeCommandAction Command="{Binding OnSaveExecute}">
            </i:InvokeCommandAction>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

私が望むのは、IsOkプロパティが false の場合、ボタンはDisabled、そうでない場合はEnabled.

私のデータバインディングに何か問題がありますか? この質問が以前に尋ねられた場合は、親切にリダイレクトしてください。

更新 1

このコードで発生した別の問題はIsValid()、テキストボックスに値を設定する前に関数が最初にトリガーされることです。ここに例があります。テキストボックスの開始値が であると仮定すると、たとえば9 に変更すると、チェックされる値はではなく0前の値になります。なぜこれが起こっているのですか?バインディングに問題はありますか?09

4

3 に答える 3

2

ここに答えがあり、MVVM フレームワークの重要な部分を含めます。これに加えて、いくつかの追加機能を追加しました。すべてのライブラリをここに置くことはできません。しかし、私はそれが役立つと確信しています。

Commanding を使用する場合はCanExecuteChangedICommandインターフェイスで注意する必要があります。プロパティが変更されたときに、このコマンドをトリガーする必要があります。(私は RelayCommand を使用しません。それは 3.party です。)

Use my DCommand :) this is the most important part

実装が簡単で、FirePropertyChangedメソッドがあります。CanExecuteChangednull でない場合、このメソッドは ICommand で発生します。

コマンドの例

匿名構文

   DCommand commandPost=new DCommand(()=>{
      //TODO:Command's real execute method Post()
        },
      ()=>
      {
         return this.TextBoxBoundProperty.IsValid;
      }
    )

非匿名構文

    DCommand commandPost=(Post,Validate);

これに加えて、viewModel の ctor でメソッドに従って canexecutechanged をトリガーする必要があります。

    this.PropertyChanged += (sender, prop) =>
          {
        //I preffered canExcuteChange for any property changes for my viewmodel class. You could put your own logic. if(prop.PropertyName.equals("thisone"));
        //Just works for this class's property changed
                this.InvokeOnClassPropertyChange(prop.PropertyName, () =>
                {
                    this.commandPost.FirePropertyChanged();
                });
          }

InvokeOnClassPropertyChange は、プロパティが ViewModel クラスのプロパティである場合に機能します。

    public static void InvokeOnClassPropertyChange(this object instance,string PropertyName,Action action)
    {
        Type type = instance.GetType();
        var fulllist = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(w => w.DeclaringType == type).ToList();
        if (fulllist.Select(p => p.Name).Contains(PropertyName))
        {
            action.Invoke();
        }
    }

上記のコードはInvokeOnClassPropertyChange拡張メソッドを示しています。以下は、DCommandICommand の実装を示しています。

   public class DCommand :ICommand
    {
    public void FirePropertyChanged()
    {
        if (CanExecuteChanged!=null)
        CanExecuteChanged(this, EventArgs.Empty);            
    }

    Func<bool> CanExecuteFunc { get; set; }
    Action<object> Action { get; set; }


    public DCommand(Action<object> executeMethod)
    {
        this.Action = executeMethod;            
    }

    public DCommand(Action executeMethod)
    {
        this.Action = new Action<object>(
            (prm) =>
            {
                executeMethod.Invoke();
            }
            );
    }

    public DCommand(Action<object> executeMethod, Func<bool> canExecuteMethod)
        : this(executeMethod)
    {            
        this.CanExecuteFunc = canExecuteMethod;            
    }

    public DCommand(Action executeMethod, Func<bool> canExecuteMethod)
        : this(executeMethod)
    {
        this.CanExecuteFunc = canExecuteMethod;
    }

    public bool CanExecute(object parameter=null)
    {
        if (CanExecuteFunc == null)
            return true;

        return CanExecuteFunc.Invoke();
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter=null)
    {

        if (CanExecuteFunc == null || CanExecute(parameter))
        {
            Action.Invoke(parameter);                
        }

    }
}

結局のところ、テキストボックスのテキストがすぐに変更されたときに ViewModel プロパティを変更したい場合は、この方法でバインドする必要があります。

Text="{Binding BoundProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"

于 2013-05-29T08:42:56.683 に答える
1

Davut Gürbüzの回答を完了するには:

Command プロパティButtonがある場合は、このプロパティを使用する方が優れています(読みやすい)。i:Interaction.Triggers

Davut Gürbüzのように、 RelayCommandにはCanExecuteFunc パラメータがあると言います。このプロパティを使用すると、ボタンの状態が自動的に変更されます。

Xaml コード:

<TextBox
    Text="{Binding BoundProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
    ...other propeties here.... />
<Button
    x:Name="btnSave"
    Command="{Binding OnSaveExecute}"
    ...other propeties here.... />

C#

/// <summary>
/// Gets the OnSaveExecute.
/// </summary>
public RelayCommand OnSaveExecute
{
    get
    {
        return _onSaveExecute 
            ?? (_onSaveExecute = new RelayCommand(
                                    () =>
                                    {
                                              // Save action or call save method
                                    },
                                    () => IsOk));
    }
}
private RelayCommand _onSaveExecute;

/// <summary>
/// Sets and gets the IsOk property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public bool IsOk
{
    get { return _isOk; }
    set
    {
        if (_isOk == value)
        {
            return;
        }
        _isOk = value;
        RaisePropertyChanged("IsOk");
        OnSaveExecute.RaiseCanExecuteChanged();
    }
}
private bool _isOk = false;

/// <summary>
/// Sets and gets the BoundProerty property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public string BoundProerty
{
    get { return _boundProerty; }
    set
    {
        if (_boundProerty == value)
        {
            return;
        }
        _boundProerty = value;
        RaisePropertyChanged("BoundProerty");
        IsValid();
    }
}
private string _boundProerty = false;

public myViewModel()
{
}

public bool IsValid()
{
    // other codes
    IsOk = MethodName();
}
于 2013-05-29T09:58:26.403 に答える
1

以下は私のコードです:

<StackPanel>
    <TextBox x:Name="TextBox1" Margin="5,0,5,0" Width="100">
         <i:Interaction.Triggers>
               <i:EventTrigger EventName="TextChanged">
                    <i:InvokeCommandAction Command="{Binding OnValidateExecute, Mode=OneWay}" CommandParameter="{Binding Text,ElementName=TextBox1}" />
               </i:EventTrigger>
         </i:Interaction.Triggers>
    </TextBox>

    <Button x:Name="btnSave" Width="120" Height="25" Content="click" IsEnabled="{Binding IsOk}">
         <i:Interaction.Triggers>
               <i:EventTrigger EventName="Click">
                    <i:InvokeCommandAction Command="{Binding OnSaveExecute}">
                    </i:InvokeCommandAction>
               </i:EventTrigger>
         </i:Interaction.Triggers>
    </Button>
</StackPanel>

コマンド パラメータのみを追加します。

public class myViewModel : INotifyPropertyChanged
{
    public bool IsOk { get; set; }
    public string Message { get; set; }
    public RelayCommand OnValidateExecute { get; set; }

    public myViewModel()
    {
        OnValidateExecute = new RelayCommand(p => 
            {
                Message = p as string;
                IsValid();
            }, p => true);
    }

    public bool IsValid()
    {
        bool valid = !string.IsNullOrEmpty(Message);
        IsOk = valid;
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("IsOk"));
        }
        return valid;
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

それはうまくいきます。

お役に立てれば。

于 2013-05-29T05:29:38.590 に答える