1

私は次のようなコンテンツコントロールを持っています:

<ContentControl x:Name="grid1ContentControl" Content="{Binding MainGridViewModel}" />

MainGridViewModelは、タイプMainGridViewModelTypeのプロパティです。

次のようなDataTemplateもあります。

<DataTemplate DataType="{x:Type App:MainGridViewModelType}">...

MainGridViewModelプロパティを初期化(つまり設定)し、NotifyPropertyChangedイベントを発生させます。

この時点で、MainGridViewModelを設定し、ContentControlでのバインドの結果として、MainGridViewModelプロパティタイプ(つまり、MainGridViewModelType)に一致するDataTemplateコンテンツをその場所のビジュアルツリーに追加することをフレームワークに通知する必要があります。 ContentControlが配置されている場所。

実際、RaisePropertyChanged()メソッドがMainGridViewModelプロパティのセッターで実行されているのを見ることができます。ただし、ビジュアルツリーインスペクターを使用してビジュアルツリーを検査する場合、MainGridViewModelの初期化後、ContentControlのContentPresenterはDataTemplateのコンテンツを表示しません。なんで?

ユーザーの操作に応じてMainGridViewModelを再度設定した後、期待したビジュアルツリーの更新を取得することに注意してください。

私が思いついた唯一の回避策は、DataTemplate ax:Keyを指定し、ContentControlのContent値を明示的に設定し、タイプをそのDataTemplateに一致させるフレームワークに依存せず、それを適用することです

ContentControl grid1ContentControl = VisualElementFinder.FindDescendantByName(mwin, "grid1ContentControl") as ContentControl;
grid1ContentControl.SetValue(ContentControl.ContentTemplateProperty, mwin.FindResource("MainGridViewModelKey") as DataTemplate);

私は同じ問題にぶつかり続けます。ビジュアルが初期化された後、フレームワークがバインドされたプロパティの後続の割り当てにどのように反応することが期待されるかについての私の理解にはギャップがあります。以下に説明するように、私はウィルの提案を取り入れてプロトタイプを開発しました。今後ともよろしくお願いいたします。

これは、このテーマに関する私のブログエントリへのリンクです。プロトタイププロジェクトへの直接リンクは次のとおりです

これは、さらに議論するためのコンテキストを提供するMainWindowコードです。プロトタイププロジェクトでは、NewTabControlViaContentControlCommandは機能しますが、NewTabControlCommandは機能しません。

MainWindow.xaml:

    <Window x:Class="DynamicTabControlSimpleProto.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:vm="clr-namespace:DynamicTabControlSimpleProto.ViewModel"
        xmlns:vw="clr-namespace:DynamicTabControlSimpleProto.View"
        xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        mc:Ignorable="d"
        Height="300"
        Width="500"
        Title="Dynamic TabControl Prototype"
        DataContext="{Binding Main, Source={StaticResource Locator}}">

    <Window.Resources>
        <DataTemplate DataType="{x:Type vm:TabControlViewModel}">
            <vw:TabControlUserControl />
        </DataTemplate>

        <DataTemplate x:Key="tabControlDataTemplate">
            <vw:TabControlUserControl />
        </DataTemplate>

    </Window.Resources>

    <Grid x:Name="LayoutRoot">

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="4" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <StackPanel Name="stackPanel" Grid.Column="0">
            <Button
                Content="NewTabControl" 
                Command="{Binding NewTabControlCommand}"
                CommandParameter="{Binding Path=DataContext}" />

            <Button
                Content="NewTabControlViaContentControl" 
                Command="{Binding NewTabControlViaContentControlCommand}"
                CommandParameter="{Binding ElementName=tabControlContentControl}" />
        </StackPanel>

        <DockPanel
            Name="dockPanel"
            Grid.Column="2">
            <Border 
                BorderBrush="Blue"
                BorderThickness="5">
                <ContentControl x:Name="tabControlContentControl" DataContext="{Binding TabControlViewModel, diag:PresentationTraceSources.TraceLevel=High}" />
            </Border>
        </DockPanel>
    </Grid>
</Window>

MainWindowViewModel.cs

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Windows.Controls;
using DynamicTabControlSimpleProto.View;
using System.Windows;

namespace DynamicTabControlSimpleProto.ViewModel
{

    public class MainViewModel : ViewModelBase
    {
        public string Welcome
        {
            get
            {
                return "Welcome to MVVM Light";
            }
        }

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel()
        {
            NewTabControlCommand = new RelayCommand<object>(obj =>
                {
                    this.NewTabControl(obj);
                });

            NewTabControlViaContentControlCommand = 
                new RelayCommand<ContentControl>(tabControlContentControl =>
                {
                    this.NewTabControlViaContentControl(tabControlContentControl);
                });


        }

        public TabControlViewModel TabControlViewModel
        {
            get
            {
                return _tabControlViewModel;
            }
            private set
            {
                _tabControlViewModel = value;
                RaisePropertyChanged("TabControlViewModel");
            }
        }

        public RelayCommand<object> NewTabControlCommand
        {
            get;
            private set;
        }

        private TabControlViewModel _tabControlViewModel = null;

        void NewTabControl(object obj)
        {
            TabControlViewModel = new TabControlViewModel();
        }

        public RelayCommand<ContentControl> NewTabControlViaContentControlCommand
        {
            get;
            set;
        }

        void NewTabControlViaContentControl(ContentControl tabContentControl)
        {
            TabControlViewModel = new TabControlViewModel();
            MainWindow mwin = Application.Current.MainWindow as MainWindow;
            tabContentControl.SetValue(ContentControl.ContentTemplateProperty, mwin.FindResource("tabControlDataTemplate") as DataTemplate);
        }



    }
}
4

1 に答える 1

1

上記で機能していなかったテクニックにエラーが見つかったと思います。コードで行っていたのと同じ方法で、XAMLで直接DataContextを設定しようとしたことで、つまり、ViewModelに直接設定しようとしたことでわかりました。私がこれを試したとき、それもうまくいきませんでした。

たとえば、メインウィンドウのDataContextをViewModelに設定しても機能しません。

<Window DataContext="vm:MainViewModel" ...>

ただし、ウィンドウのDataContextをより高いレベルのコンポーネント(私の場合はApp.xaml)のリソースで宣言されたViewModelに設定すると、すべてが正常に機能します。

App.xamlの場合:

<Application.Resources>
    <vm:MainViewModel x:Key="MainViewModel" />
</Application.Resources>

次に、MainWindow.xamlで:

<Window DataContext="{Binding Source={StaticResource MainViewModel}}" ...>

上記の例の元のコードで行っていたのは、DataContextをViewModelに直接設定するのと似ていると思います。なぜなら、ContentControlがBindingを作成していたとしても、必要な要素はViewModelである必要があると思うからです。または別の、リソースとして追加する必要があります。そうして初めて、ContentControlのDataContext Bindingをリソースに設定でき、フレームワークは、ViewModelタイプの期待されるマッピングをDataTemplateビジュアルツリー要素に提供します。

上記の情報はすべて、ContentControlsに役立ちます。特に、私の最初の質問のコードソリューションは、説明されていることを達成するための最良かつ唯一の方法である可能性があります。ただし、ItemsControlの場合は話が異なります。この投稿が大きく分岐するリスクを冒して、ブログの投稿にこれらの追加の洞察を含めました。

于 2012-04-18T15:06:53.153 に答える