0

MVVM パターンを使用して WPF アプリケーションを実装しています。

このアプリケーションは、基本的に、コントロール ウィジェット (ダイヤル パッド、インターコム回線など) が上に配置された通信パネル (通信パネル) です。コントロール ウィジェットも MVVM パターンを使用して実装されています。これにより、個別に簡単にテストできるようになります。

ビュー モデルで DialedNumber パブリック フィールドを公開する、この「ダイヤル パッド」コントロール ウィジェットがあります。

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

「ダイヤル パッド」コントロール ウィジェットは、ビューのパブリック フィールドを介してそのビュー モデルも公開します。

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

また、ビューモデルのパブリックフィールドから書き込み/読み取りを行うビューを介して公開します。

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

DialPad は通信パネル (これも MVVM を使用して実装) に配置され、ビュー モデルに DialedPABXNumber パブリック フィールドがあります。

public string DialedPABXNumber
    {
        get { return _dialedPABXNumber; }
        set
        {
            _dialedPABXNumber = value;
            OnPropertyChanged("DialedPABXNumber");
        }
    }

ここで、DialPad の DialedNumber フィールドを通信パネルの DialedPABXNumber フィールドにリンクできるようにしたいと考えています。ただし、それを行うために適切な XAML 構文を考え出すのに苦労しています。私のアプローチは次のようになります。

<PanelControls:DialPad x:Name="MyDialPad2" DialPadViewModel.DialedNumber="{Binding Path=CommsPanelViewModel.DialedPABXNumber, Mode=OneWayToSource}"/>

これにより、通信パネルの XAML が読み込まれるときに実行時例外が発生します。すなわち:

不明なメンバー '{http://schemas.microsoft.com/winfx/2006/xaml/presentation}DialPadModel.DialedNumber' を設定できません。

DialPadViewModel.DialedNumber にアクセスしたい XAML で指定するにはどうすればよいですか?

編集:コンポーネントがどのように組み合わされるかについて、この背景情報を追加します。アプリケーションのメイン ウィンドウには 2 つのサブウィンドウがあります。左側のコントロール パネルと、動的に読み込まれる適切な通信パネルです。

<Window x:Class="Comms.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Views="clr-namespace:Comms.View"
    xmlns:ViewModel="clr-namespace:Comms.ViewModel"
    Title="Comms" Height="350" Width="525" Closing="WindowClosing">
<Window.Resources>
    <DataTemplate x:Name="CommsControlPanelViewModel" DataType="{x:Type ViewModel:CommsControlPanelViewModel}">
        <Views:CommsControlPanelView x:Name="CommsControlPanelView"/>
    </DataTemplate>
    <DataTemplate x:Name="CommsPanelViewModel" DataType="{x:Type ViewModel:CommsPanelViewModel}">
        <Views:CommsPanelView x:Name="CommsPanelView"/>
    </DataTemplate>
</Window.Resources>

<StackPanel x:Name="Layout" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Horizontal">
    <ContentControl Content="{Binding CommsControlPanelView}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
    <ContentControl Content="{Binding CommsPanelView}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</StackPanel>

通信パネルは動的に読み込まれます。パネルの XAML ファイルは次のとおりです。

<Border x:Name="CommsPanelBorder"
    Style="{DynamicResource BorderTemplate}"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:PanelControls="clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib"
    VerticalAlignment="Top">
<StackPanel>
    <!-- PABX Dial Pad -->
    <StackPanel Orientation="Horizontal">
    <PanelControls:DialPad x:Name="MyDialPad2" DialPadViewModel.DialedNumber="{Binding Path=CommsPanelViewModel.DialedPABXNumber, Mode=OneWayToSource}"/>
    </StackPanel>
</StackPanel>

4

3 に答える 3

1

あなたがしようとしていることについて少し混乱していますが、あるオブジェクトのプロパティを別のオブジェクトのプロパティにバインドしようとしているようです

まず、プロパティには、通常のプロパティと依存プロパティの 2 種類があります。バインディングを使用してプロパティを設定する場合は、DependencyPropertyである必要があるためDialPadViewModel.DialedNumber、バインディングによって値が提供される場合は、依存関係プロパティである必要があります。

次に、実際のバインディングが参照しようとしていますCommsPanelViewModel.DialedPABXNumber。これは実際には にバインドされMyDialPad2.DataContext.CommsPanelViewModel.DialedPABXNumberますが、コードを正しく理解していれば有効なプロパティではないと思います。

あなたがやろうとしているのCommsPanelViewModelは、 の DataContext である を見つけ、そのプロパティCommsPanelViewにバインドすることだと思います。DialedPABXNumber

これを行うには、最初にバインディングのソースを変更して、 RelativeSourceまたはElementNameCommsPanelViewバインディングのいずれかを介して見つける必要があります。 forは であり、そのビュー モデルには プロパティがあるため、をに設定する必要があります。PathDataContext.DialedPABXNumberDataContextCommsPanelViewCommsPanelViewModelDialedPABXNumber

<PanelControls:DialPad x:Name="MyDialPad2" DialPadViewModel.DialedNumber="{Binding ElementName=CommsPanelView, Path=DataContext.DialedPABXNumber, Mode=OneWayToSource}"/>

とは言ってもCommsPanelView、テンプレートが関係しているため、現在の XAML レイアウトを使用してバインディングで を見つけることができるとは確信していません。試してみてください。そうでない場合でも、いくつかのオプションを利用できます。

プロパティなどの未使用の依存関係プロパティに必要なプロパティを格納してみてください。その後、またはプロパティをTag使用して ContentControl を見つけ、そのプロパティにバインドできます。RelativeSourceElementNameTag

<ContentControl Content="{Binding CommsControlPanelView}" Tag="{Binding CommsPanelView.DialedPABXNumber}" />

MVVM LightMessengerや Prismなどのメッセージング システムを使用EventAggregatorして値を渡すこともできます。(私のブログの記事にこれらの簡単な要約があります)

または、ViewModel レイヤーで 2 つのプロパティをリンクすることもできます。これCommsControlPanelViewModelには、保存するプロパティが含まれており、CommsViewModel.DialedPABXNumber必要に応じて ViewModel レイヤー自体からそのプロパティが更新されます。

于 2012-10-18T14:24:02.807 に答える
0

プロパティにバインドするには、このプロパティが DependencyProperty である必要があります。View に Dummy-Property を作成し、PropertyChangedCallback を介して ViewModel を操作できます。

public static DependencyProperty TestProperty = DependencyProperty.Register("Test", typeof(string), typeof(View), new PropertyMetadata("default", new PropertyChangedCallback(TestPropertyChanged)));
public string Test
{
    get { return GetValue(TestProperty).ToString(); }
    set { SetValue(TestProperty, value); }
}
public static void TestPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    ViewModel vm= ((View)obj).DataContext;
    if (vm.Test != e.NewValue.ToString())
    {
        vm.Test = e.NewValue.ToString();
    }
} 

これで、ビューでこのプロパティにバインドできます。

しかし、これはMVVMパターンに違反していると思いますよね?

于 2012-10-18T11:37:31.520 に答える
0

Blachshma と長い間話し合った後 (Blachshma に感謝します!)、DialPad のモデルを削除し、viewmodel 内のコードをコード ビハインドに移動することで、DialPad コードを修正しました。

パネルの XAML ファイルで使用したバインディングは次のとおりです。

<PanelControls:DialPad x:Name="MyDialPad2" DialedNumber="{Binding Path=CommsPanelViewModel.DialedPABXNumber, Mode=OneWayToSource, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"/>

ダイヤル パッドのボタンをクリックすると、CommsPanelViewModel 内の DialedPABXNumber フィールドの変更が効果的にトリガーされていることが確認できます。これは、私が求めていたものです。ただし、これを行うために DialPad のコードに大幅な変更を加えたため、単体テストを実行できなくなりました。質問に回答済みのマークを付け、この新しい問題に対処するために新しい質問を開きます。

ご意見をお寄せいただきありがとうございます。

于 2012-10-18T14:42:27.777 に答える