10

私はすべてを見たと思っていたので、これは私を困惑させましたが、何かが欠けているに違いありません. MSDN マガジンの従来の MVVM パターンから外れました。

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

MVVMを学びながら。ただし、通常はほとんどのコードをコピーして必要に応じて置き換えますが、今日は何かをゼロから構築したいと思っていたので、思ったよりも多くのコードがあることに気付きました。リソース ディクショナリを使用した場合、MVVM はバインドでは動作しないように見えましたが、データ コンテキストでは直接動作します。この質問は、最終的に、他の開発者が見つけたバインディングの使用を提案することを望んでいます。

質問の要約は次のとおりです: リソース ディクショナリの 'DataTemplate' が以下に示すように機能しないように見えるのに、直接の 'DataContext' メソッドがバインディングのビューですぐに機能するのはなぜですか?

コードビハインドの設定ビューとコードビハインドを混在させているためですか。または、他の何かが原因である可能性があります。ビューの XAML で「DataContext」を直接設定すると、プロパティとその実装がビューモデルで正しく設定されているように見えますが、リソース ディクショナリで設定しないのはなぜですか? この方法の利点は、一度に多数の関係を設定できることだと思いました。それを機能させるために他の設定を行う必要があるかどうか、私は興味があります。彼らがデータ テンプレートを使用する MVVM メソッドの主な例は興味深いですが、「バインディング」を機能させるために私が行っている以上に、それらを設定する必要があるようです。

私にとってうまくいかなかったもの:

メイン ウィンドウの xaml でいくつかの非常に基本的なことを実行しようとしましたが、コードの一部を省略してさらに簡単にしました。

メイン ウィンドウの XAML:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/charts" x:Class="WPFTesting12_2.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ResourceDictionary Source="Resources.xaml"/>
    </Window.Resources>
    <Grid>
        <DockPanel x:Name="dockpanel">
            <Menu DockPanel.Dock="Top" Height="30">
                <MenuItem Header="Charting">
                    <MenuItem Header="MVVMDataBound" x:Name="mnuDataBoundSeriesMVVMCharting" Click="mnuDataBoundSeriesMVVMCharting_OnClick"/>
                </MenuItem>
            </Menu>
            <TextBlock Height="5" Background="Black" DockPanel.Dock="Top" />
            <DockPanel x:Name="dockchildren" DockPanel.Dock="Bottom"/>
        </DockPanel>
    </Grid>
</Window>

メイン ウィンドウ コード ビハインド:

public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();

            this.WindowState = WindowState.Maximized;
        }


        private void mnuDataBoundSeriesMVVMCharting_OnClick(object sender, RoutedEventArgs e)
        {
            View.DataBoundMVVMChart c = new DataBoundMVVMChart();

            dockchildren.Children.Clear();
            dockchildren.Children.Add(c);
        }
    }
}

リソース ディクショナリ:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:vw="clr-namespace:WPFTesting12_2.View"
                    xmlns:vm="clr-namespace:WPFTesting12_2.ViewModel"
                    >
  <DataTemplate DataType="{x:Type vm:DataBoundMVVMChartViewModel}">
    <vw:DataBoundMVVMChart/>
 </DataTemplate>

<Style TargetType="MenuItem">
        <Setter Property="Background" Value="Wheat"/>
    </Style>
    <Style TargetType="Menu">
        <Setter Property="Background" Value="Wheat"/>
    </Style>

</ResourceDictionary>

DataBoundMVVMChart.xaml の表示:

<UserControl x:Class="WPFTesting12_2.View.DataBoundMVVMChart"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFTesting12_2.ViewModel"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <ResourceDictionary Source="..\Resources.xaml"/>
    </UserControl.Resources>
    <Grid>
        <DockPanel>
            <Menu DockPanel.Dock="Top">
                <MenuItem Header="TesterContent"/>
            </Menu>
            <Label DockPanel.Dock="Bottom" Width="300" x:Name="label" Height="50" Foreground="Blue" FontSize="24"  Content="{Binding Path=HelloString}"/>
        </DockPanel>
    </Grid>
</UserControl>

上記のビューにバインドする ViewModel:

namespace WPFTesting12_2.ViewModel
{
    class DataBoundMVVMChartViewModel : INotifyPropertyChanged
    {
        private string _HelloString;

        public string HelloString
        {
            get { return _HelloString; }
            set 
            {
                _HelloString = value;
                RaisePropertyChanged("HelloString");
            }
        }

        public DataBoundMVVMChartViewModel()
        {
            HelloString = "Hello there from the ViewModel";
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}

さて、バインディングはビューで失敗しますが、色のリソースは入ってきます。だから私は何か間違ったことをしたと思っていましたが、コードビハインドはすぐにプロパティを取得します. それでは次に進みましょう:

何が機能したか:

魔法のように、これらの 4 行をビューに追加すると、次のようになります。

上部の「UserControl」セグメントの宣言にこれを追加します。

xmlns:local="clr-namespace:WPFTesting12_2.ViewModel"

次に、UserControl の DataContext への参照を設定します。

<UserControl.DataContext>
        <local:DataBoundMVVMChartViewModel/>
    </UserControl.DataContext>
4

2 に答える 2

30

WPF を使用する場合、データ レイヤー ( DataContext) と UI レイヤー (XAML) の 2 つのレイヤーがあることを認識することが重要です。

バインディングは、データ レイヤーからビュー レイヤーにデータをプルするために使用されます。

あなたが書くとき

<UserControl.DataContext>
    <local:DataBoundMVVMChartViewModel/>
</UserControl.DataContext>

DataBoundMVVMChartViewModelの新しいインスタンスを作成し、その UserControl のデータ層に使用する必要があることを WPF に伝えています。

あなたが書くとき

<Label Content="{Binding HelloString}" />

DataContext「HelloString」という名前のプロパティをデータ レイヤー ( ) で検索し、それをプロパティに使用するように Label に指示していContentます。

プロパティ "HelloString" がデータ層に存在しない場合 ( のDataContextように設定しない限り存在しません<UserControl.DataContext>)、バインディングは失敗し、出力ウィンドウにバインディング エラー以外は何も表示されません。

あなたのDataTemplateからあなたResourceDictionaryは、とは別のものDataContextです。

実際、aResourceDictionaryはその名の通り、WPF が必要に応じてアプリケーションで使用できるリソースの辞書です。ただし、ディクショナリ内のオブジェクトは、既定ではアプリケーションの UI 自体の一部ではありません。代わりに、使用するには何らかの方法で参照する必要があります。

しかし、あなたに戻りますDataTemplate

<DataTemplate DataType="{x:Type vm:DataBoundMVVMChartViewModel}">
    <vw:DataBoundMVVMChart/>
</DataTemplate>

WPF は DataTemplates を使用して、特定の種類のオブジェクトを描画する方法を認識します。あなたの場合、これDataTemplateは WPF に、 type のオブジェクトを描画する必要があるときはいつでも、DataBoundMVVMChartViewModelを使用して描画する必要があることを伝えていますDataBoundMVVMChart

オブジェクトを UI に挿入するにContentは、通常、次のようなプロパティが使用されます。

MyLabel.Content = new DataBoundMVVMChartViewModel();

また

<ContentControl Content="{Binding SomeDataboundChartViewModelProperty}" />

私は実際に、質問でリンクしたのとまったく同じ記事でMVVMの学習を開始しましたが、それを理解するのにも多くの苦労がありました.

興味のある方は、WPF/MVVM に関するブログ記事をいくつか用意しておりますので、この技術をよりよく理解するのに役立つかもしれません。

あなたの実際の質問については:

MVVM、リソース ファイルのデータ テンプレート、またはビュー自体の DataContext でバインドするための推奨される方法は?

UIDataTemplate.Resources1 つの特定のDataContext.

これは、MVVM で再利用可能なコントロールを作成する場合に特に重要です。たとえば、 があり、などのコントロール自体にCalculatorUserControlを割り当てた場合、コントロールの作成時に作成されたもの以外でそれを使用することはできません。DataContext<UserControl.DataContext>CalculatorUserControlDataContext

したがって、通常DataContext、起動時に一度アプリケーション全体に を設定し、アプリケーションで別のまたはDataTemplatesを描画する方法を WPF に指示するために使用します。ViewModelsModels

アプリケーション全体がデータ レイヤーに存在し、XAML はデータ レイヤーとやり取りするための使いやすいインターフェイスにすぎません。(コード サンプルを見たい場合は、Simple MVVM Exampleの投稿を参照してください)

于 2013-05-08T18:24:59.420 に答える
2

暗黙的に使用するDataTemplates場合は、ビュー モデル ファーストのアプローチを使用する必要がありますが、コンテキストとしてビュー モデルを使用せずにビューを追加DockPanelします。ContentControlそれぞれのビューモデルを (またはに)追加するだけで、そのビューモデルを としてビューがItemsControlから自動的に作成されます。DataTemplateDataContext

例えば

<ItemsControl Name="ic"/>

ic.Items.Add(new DataBoundMVVMChartViewModel());

個人的には、ビュー ファーストよりもこれを好みます(たとえば、独自の を割り当てるビューを追加するなどDataContext)。通常、ビュー モデルへの参照が必要なため、ビューは二次的なものであり、ビュー モデルと対話することによって間接的に操作されます。

于 2013-05-08T17:55:11.433 に答える