我正在尝试构建一个包含不同选项卡的WPF窗口。
更准确地说,标签将呈现给定Person
的不同方面(例如简短的演示文稿和此人阅读的书籍列表)。
主窗口有一个允许我们选择人的combox。我希望在组合框中的选定人员更改时刷新选项卡。
public interface IPerson
{
string Name { get; }
int Age { get; }
string[] BooksRead { get;}
}
为了简单起见,我只保留了下面的两个标签。
我按照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>(); } }
}
实际上,SummaryTabViewModel
和BooksReadTabViewModel
的构造函数仅依赖于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
中找到答案 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>