刷新具有MVVM模式的选项卡式窗口的子DataContext

时间:2014-09-23 10:51:53

标签: c# wpf mvvm tabs ninject

我正在尝试构建一个包含不同选项卡的WPF窗口。 更准确地说,标签将呈现给定Person的不同方面(例如简短的演示文稿和此人阅读的书籍列表)。 主窗口有一个允许我们选择人的combox。我希望在组合框中的选定人员更改时刷新选项卡。

  public interface IPerson
    {
        string Name { get; }

        int Age { get; }

        string[] BooksRead { get;} 
    }

为了简单起见,我只保留了下面的两个标签。

This is the first tab of my window This is the secont tab of my window

我按照MVVM原则(我使用MVVMLight框架)创建了我的示例,我希望我的标签有自己的View控件和ViewModel。

App.xaml用于重新获取ViewModelLocator

  <Application.Resources>
    <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:WpfApplication1.ViewModel" />
  </Application.Resources>

现在主窗口的xaml看起来像

<Window.DataContext>
        <Binding Path="MainViewModel" Source="{StaticResource Locator}" />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <StackPanel Orientation="Horizontal">
                <ComboBox ItemsSource="{Binding AvailablePersons}" IsTextSearchEnabled="True" IsEditable="False" SelectedItem="{Binding SelectedPerson}">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Name}"/>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
            </StackPanel>
        </StackPanel>
        <TabControl Name="Test" VerticalAlignment="Top" HorizontalAlignment="Stretch" SelectedIndex="{Binding SelectedTabIndex}" Grid.Row="2">
            <TabItem Name="HomeTab"  Header="Summary">
                <views:SummaryTabControl/>
            </TabItem>
            <TabItem Name="ContactsTab"  Header="Books">
                <views:BooksTabControl/>
            </TabItem>
        </TabControl>
    </Grid>

现在,SummaryTabControl的视图对于DataContext

具有以下行
<UserControl.DataContext>
    <Binding Path="SummaryTabViewModel" Source="{StaticResource Locator}" />
</UserControl.DataContext>

我们在其他标签BooksTabControl ...

中有类似的内容

现在这里是基于Ninject IoC框架的ViewModelLocator的代码。

 public class ViewModelLocator
    {
        private static readonly IKernel _kernel;

        static ViewModelLocator()
        {
            _kernel = new StandardKernel();
            _kernel.Bind<IMainViewModel>().To<MainViewModel>().InSingletonScope();
            _kernel.Bind<ISummaryTabViewModel>().To<SummaryTabViewModel>();
            _kernel.Bind<IBooksReadTabViewModel>().To<BooksReadTabViewModel>();
            _kernel.Bind<IPerson>().ToMethod((ctx) =>
                {
                    var mainViewModelInstance = _kernel.Get<IMainViewModel>();
                    if (mainViewModelInstance.SelectedPerson == null)
                    {
                        throw new InvalidOperationException();
                    }
                    return mainViewModelInstance.SelectedPerson;
                });
        }

        public static IMainViewModel MainViewModel { get { return _kernel.Get<IMainViewModel>(); } }
        public static ISummaryTabViewModel SummaryTabViewModel { get { return _kernel.Get<ISummaryTabViewModel>(); } }
        public static IBooksReadTabViewModel BooksReadTabViewModel { get { return _kernel.Get<IBooksReadTabViewModel>(); } }

    }

实际上,SummaryTabViewModelBooksReadTabViewModel的构造函数仅依赖于IPerson(请参阅下面的示例)。这就是我创建IPerson到MainViewModel SelectedPerson成员的动态绑定的原因。

public class SummaryTabViewModel : ISummaryTabViewModel
{
    private readonly IPerson _person;
    public SummaryTabViewModel(IPerson person)
    {
        _person = person;
    }

    public string Name { get { return _person.Name; } }
    public int Age { get { return _person.Age; } }
}

技巧是我希望在更改DataContext时重新加载标签SelectedPerson。我尝试了不同的方法,一个是通过发送消息,以便MainWindow的代码隐藏强制重置选项卡的DataContext,但是,选项卡没有重新加载......

在我的情况下,我是否可以强制标签控件重新加载并重新ViewModelLocator以更新'{1}}?

完整的示例代码可在this repository

中找到

1 个答案:

答案 0 :(得分:1)

我不知道定位器的东西,但一个简单的解决方案如下:从你的usercontrol中删除DataContext的东西

<UserControl.DataContext>
   <Binding Path="SummaryTabViewModel" Source="{StaticResource Locator}" />
</UserControl.DataContext>

编辑:除了你的评论。当你想改变一些东西,因为SelectedItem改变了,为什么不在你的MainViewModel中做这个?

public IPerson SelectedPerson
{
    get {...}
    set
    {
        this._selectedPerson=value;
        this.MySummary = SummaryTabViewModel(_selectedPerson);
        OnPropertyChanged("SelectedPerson");
    }
  }

 public ISummaryTabViewModel MySummary 
 {
    get {...}
    set
    {
        this._mySummary = value;
        OnPropertyChanged("MySummary");
    }
 }

XAML

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="50"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
        <StackPanel Orientation="Horizontal">
            <ComboBox x:Name="cbo" ItemsSource="{Binding AvailablePersons}" IsTextSearchEnabled="True" IsEditable="False" SelectedItem="{Binding SelectedPerson}">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}"/>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
        </StackPanel>
    </StackPanel>
    <TabControl Name="Test" VerticalAlignment="Top" HorizontalAlignment="Stretch" SelectedIndex="{Binding SelectedTabIndex}" Grid.Row="2">
        <TabItem Name="HomeTab"  Header="Summary">
            <views:SummaryTabControl DataContext="{Binding Path=MySummary}"/>
        </TabItem>
        <TabItem Name="ContactsTab"  Header="Books">
            <views:BooksTabControl/>
        </TabItem>
    </TabControl>
</Grid>