2

WPF でのデータ バインディングに問題があります。シナリオは次のとおりです。ダイヤル パッドをシミュレートするユーザー コントロールを作成しました (つまり、'0' から '9' までの数字と '#' および 'Clear' キーを含む 12 個のボタンの配列)。コントロールはクラス ライブラリ内に存在し、MVVM パターンに従って実装されています。これは主に、クラス ライブラリ内のコンポーネントを簡単に単体テストする必要があるためです。

コントロールのビュー モデルは非常に単純です。基本的には、ユーザーがダイヤル パッドのキー ボタンを押すたびに、公開されている "DialedNumber" 文字列 (モデルに内部的に接続されています) を更新します。バインドは正しく機能しており、デバッガーを使用して、ダイヤル パッドのボタンを押すとビューモデル内の "DialedNumber" 変数が更新されていることを確認できます。

この DialPad コントロールは、別の XAML ファイル (Panel.xaml) で使用され、カスタム クラス ライブラリに属する​​複数のコントロールが配置されています。

ここで、DialPad 内に保持されている「DialedNumber」文字列を表示するために、Panel ファイル内に TextBlock を追加したいと考えています。これは、Panel.xaml のコード スニペットです。

<PanelControls:DialPad x:Name="MyDialPad" DialedNumber="55325"/>
<TextBlock Text="{Binding ElementName=MyDialPad, Path=DialedNumber}" />

私が得ている結果は、テキストブロックが開始時に正しい番号 (つまり、「55325」) を表示することですが、ダイヤルパッドのキーを押してもその内容は更新されません (DialPad のビューモデルは押したときに更新されますが)。デバッガーで確認したように、新しいキー)。

DialPad ビューのコード ビハインドは次のとおりです。

public partial class DialPad : UserControl
{
    public DialPad()
    {
        InitializeComponent();
        DataContext = new DialPadViewModel();
    }

    public void DialedNumberChanged(object sender, EventArgs e)
    {
        return;
    }

    public DialPadViewModel DialPadViewModel
    {
        get { return DataContext as DialPadViewModel; }
    }

    public string DialedNumber
    {
        get
        {
            var dialPadViewModel = Resources["DialPadVM"] as DialPadViewModel;
            return (dialPadViewModel != null) ? dialPadViewModel.DialedNumber : "";
        }
        set
        {
            var dialPadViewModel = Resources["DialPadVM"] as DialPadViewModel;
            if (dialPadViewModel != null)
            {
                dialPadViewModel.DialedNumber = value;
            }
        }
    }
}

DialPad ビュー モデルは次のとおりです。

public class DialPadViewModel : ObservableObject
{
    public DialPadViewModel()
    {
        _dialPadModel = new DialPadModel();
    }

    #region Fields

    private readonly DialPadModel _dialPadModel;
    private ICommand _dialPadKeyPressed;

    #endregion

    #region Public Properties/Command

    public DialPadModel DialPadModel
    {
        get { return _dialPadModel; }
    }

    public ICommand DialPadKeyPressedCommand
    {
        get
        {
            if (_dialPadKeyPressed == null)
            {
                _dialPadKeyPressed = new RelayCommand(DialPadKeyPressedCmd);
            }
            return _dialPadKeyPressed;
        }
    }

    public string DialedNumber
    {
        get { return _dialPadModel.DialedNumber; }
        set
        {
            _dialPadModel.DialedNumber = value;
            RaisePropertyChanged("DialedNumber");
        }
    }

    #endregion

    #region Private Helpers

    private void DialPadKeyPressedCmd(object parameter)
    {
        string keyPressedString = parameter.ToString();

        if (keyPressedString.Length > 0)
        {
            if (char.IsDigit(keyPressedString[0]))
            {
                DialedNumber += keyPressedString[0].ToString(CultureInfo.InvariantCulture);
            }
            else if (keyPressedString == "C" || keyPressedString == "Clr" || keyPressedString == "Clear")
            {
                DialedNumber = "";
            }
        }
    }

    #endregion
}

私の問題をもう一度述べましょう。Panel.xaml のテキストブロックは開始時に正しい番号 (55325) を表示しますが、DialPadButtons を押してもその値は更新されません。DialPadKeyPressedCmd 内にブレークポイントを配置し、ダイヤル パッドのキーを押すたびにメソッドが実行されることを確認できます。

4

3 に答える 3

1

DependencyPropertiesは、値を取得するために他のプロパティを指すことを目的としています。したがって、を指すかDialPadViewModel.DialedNumber、UserControlが使用されているときに他の文字列(バインディングまたは「551」などのハードコードされた値)を指すことができますが、両方を行うことはできません。

あなたの場合、誰かが依存関係プロパティにバインドすると、現在の値(へのバインド)が新しい値DialedNumberに置き換えられます。DialPadViewModel.DialedNumber

コードの外観と実行したい内容に応じて、いくつかの方法があります。

まず、コントロールを使用したい人はViewModelも使用しDialedNumber、パブリック依存関係プロパティを作成しないように要求できます。

したがって、プロパティSomeOtherDialedNumberとバインディングを使用してカスタムクラスを作成することを許可する代わりに

<DialPad DialedNumber="{Binding SomeOtherDialedNumber}">

DialPadViewModelDialPadコントロールを使用するときはいつでも、コードでを使用する必要があります。this.DataContext = new DialPadViewModelこれを機能させるには、ユーザーがUserControlにを提供するため、コードビハインドのUserControlを削除する必要がありDialPadViewModelます。また、暗黙のDataTemplateを使用して、常にUserControlで描画するようにWPFに指示できDialPadViewModelますDialPad

<DataTemplate DataType="{x:Type DialPadViewModel}">
    <local:DialPad />
</DataTemplate>

私が考えることができる他の代替手段は、いくつかのPropertyChange通知を使用してDependencyPropertyをViewModelプロパティと同期させることです。

依存関係プロパティが変更されるたびに更新する必要があり(プロパティ変更通知にはDialPadViewModel.DialedNumberDependencyPropertyDescriptor.AddValueChangedDialedNumberを使用する必要がある場合があります)、変更時に依存DialedNumber関係プロパティのソースを更新するための何かを作成する必要もありDialPadViewModel.DialedNumberます。

個人的には、UserControlにViewModelがある場合は、最初のオプションを使用します。そうでない場合は、ViewModelを完全に削除し、ViewModelを使用せずに、コードビハインドでUserControlのロジックを構築します。

これは、WPFがUIレイヤーとデータレイヤーの2つのレイヤーで機能するためです。はDataContextデータ層であり、ViewModelは通常データ層の一部です。UserControlのコンストラクターでデータレイヤー(DataContext)を明示的に設定することで、データレイヤーをUIレイヤーと結合します。これは、MVVMを使用する最大の理由の1つである関心の分離に反します。UserControlは、実際にはきれいなシェルのみである必要があり、必要なデータレイヤーの上に配置できる必要があります。

于 2012-09-27T16:21:08.827 に答える
1

View に DialPad を配置すると、ViewViewModel に DialPadViewModel-Property (パブリック + グローバル) を作成できます。

public DialPadViewModel DialPadViewModel = new DialPadViewModel();

View の DataContext-Binding を ViewViewModel に設定し、DialPads DataContext もそれにバインドします。

<local:DialPad DataContext="{Binding}"/>

これで、DialPadViewModel のプロパティにバインドできます:

<TextBox Text="{Binding Path=DialPadViewModel.DialedNumber}"/>

これが、View と DialPad から DialPadViewModel にアクセスする方法です。

編集:

次に、DialPad.xaml.cs の DialedNumber プロパティを次のように変更してみてください。

public string DialedNumber
{
    get
    {
        return DialPadViewModel.DialedNumber;
    }
    set
    {
        DialPadViewModel.DialedNumber = value;
    }
}

編集2:私は問題を見つけました:

DialPad.xaml では、すべてのコマンドがリソースから DialPadViewModel にバインドされ、TextBloc は DialPads DataContext (DialPadViewModel の別のインスタンス) にバインドされました。

そのため、DialPad ボタンを押すたびに、DataContext の DPVM インスタンスからの DialedNumber ではなく、リソースの DPVM インスタンスから DialedNumber の値を変更していました。

于 2012-09-27T16:11:29.100 に答える
0

ビューに TextBox を追加し、その Text プロパティをビューモデルの DialedNumber プロパティにバインドできるようです。

 <TextBox Text="{Binding Path=DialedNumber}"></TextBox>

ビューモデル プロパティは次のようになります。

    private string _dialedNumber;
    [DefaultValue("551")]
    public string DialedNumber
    {
        get { return _dialedNumber; }
        set
        {
            if (value == _dialedNumber)
                return;
            _dialedNumber= value;
            _yourModel.DialedNumber= _dialedNumber;
            this.RaisePropertyChanged("DialedNumber");
        }
    }

あなたの質問を誤解した場合はお知らせください。

于 2012-09-27T16:05:12.143 に答える