我用MVVM模式编写了一些WPF应用程序,它将TabControl绑定到“TabViewModelItem”的集合。
主窗口XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModel="clr-namespace:XcomSavesGameEditor.ViewModel"
x:Class="XcomSavesGameEditor.MainWindow"
xmlns:Views="clr-namespace:XcomSavesGameEditor.View"
Title="X-COM Saved Game Editor" Height="650" Width="850" Background="#FF1B0000">
<Window.DataContext>
<ViewModel:TabsManagerViewModel/>
</Window.DataContext>
<Grid>
... (some not relevant code removed for clearity of question) ...
<TabControl x:Name="myTabs" Background="Black" Margin="0,25,0,0" BorderThickness="0,0,0,0" BorderBrush="Black" ItemsSource="{Binding Tabs}" >
<TabControl.Resources>
<DataTemplate DataType="{x:Type ViewModel:Tab0a_FileSaveData_ViewModel}">
<Views:Tab0a_FileSaveData_View />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:Tab0b_Summary_ViewModel}">
<Views:Tab0b_Summary_View />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:Tab1_Research_ViewModel}">
<Views:Tab1_Research_View />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:Tab2_Engineering_ViewModel}">
<Views:Tab2_Engineering_View />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:Tab3_Barracks_ViewModel}">
<Views:Tab3_Barracks_View />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:Tab4_Hangar_ViewModel}">
<Views:Tab4_Hangar_View />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:Tab5_SituationRoom_ViewModel}">
<Views:Tab5_SituationRoom_View />
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
<!-- this is the header template-->
<DataTemplate>
<Grid Margin="0">
<Border Margin="0,0,0,0"
Background="Black"
BorderBrush="Black"
BorderThickness="0,0,0,0" Padding="0,0,0,0">
<StackPanel Orientation="Horizontal"
Margin="0,0,0,0">
<Image Name ="tabImage" Source="{Binding TabImage_Disabled}" />
</StackPanel>
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter TargetName="tabImage" Property="Source" Value="{Binding TabImage_Enabled}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<!-- this is the body of the TabItem template-->
<DataTemplate>
<Grid>
<Grid.Background>
<ImageBrush ImageSource="{Binding TabImage_Background}"/>
</Grid.Background>
<UniformGrid>
<ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="{Binding TabContents}" />
</UniformGrid>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
并且包含选项卡集合的ViewModel是代码:
public sealed class TabsManagerViewModel : ViewModelBase
{
private ObservableCollection<TabViewModelItem> _tabs;
public ObservableCollection<TabViewModelItem> Tabs
{
get { return _tabs; }
set
{
_tabs = value;
RaisePropertyChanged("Tabs");
}
}
public TabsManagerViewModel()
{
Tabs = new ObservableCollection<TabViewModelItem>();
Tabs.Add(new TabViewModelItem { TabName = "File_Save_Data", TabImage_Enabled = _aEnabledTabImages[(int)enum_Tabs.SaveFileData_Tab], TabImage_Disabled = _aDisabledTabImages[(int)enum_Tabs.SaveFileData_Tab], TabImage_Background = _aBackgroundTabImages[(int)enum_Tabs.SaveFileData_Tab], TabContents = new Tab0a_FileSaveData_ViewModel() });
Tabs.Add(new TabViewModelItem { TabName = "Summary", TabImage_Enabled = _aEnabledTabImages[(int)enum_Tabs.Summary_Tab], TabImage_Disabled = _aDisabledTabImages[(int)enum_Tabs.Summary_Tab], TabImage_Background = _aBackgroundTabImages[(int)enum_Tabs.Summary_Tab], TabContents = new Tab0b_Summary_ViewModel() });
... (rest of code removed for clearity of question)
}
}
所以基本上它的标签控件绑定到“TabViews”的集合。 并且基于对象数据类型,它显示了View1或View2。 注意:View1&amp; View 2是UserControls,每个都绑定到它自己的ViewModel。 这个概念很好。
现在我问的问题在哪里? 我的问题是: 每次我点击另一个标签&amp;然后返回到相同的选项卡,我得到再次调用的特定选项卡ViewModel构造函数,我希望ViewModel对象可以保留。
这是一个问题,因为当我在标签之间切换时,它会导致我丢失对该页面所做的任何修改。并且因为每次都会调用ctor,over&amp;结束,我甚至无法使用VIewModel来存储这些信息。
我的问题是: 1)当tab处于非活动状态时,有什么方法可以阻止TabControl配置ViewModel对象?意味着预先创建所有ViewModel的对象&amp;隐藏时不要丢弃它们? 2)使用这个概念的“变通方法”存在,允许我存储给定标签的“可视树”,所以如果我离开它并且&amp;然后重新打开它,它会存储所有信息(如选中的复选框,书面文字等)。
感谢您对此事的任何帮助。
的问候, 伊詹
答案 0 :(得分:3)
问题的解决方案是扩展TabControl并替换默认行为,以便它不会卸载旧标签。 最终解决方案(包含控件和控件模板)是@ Stop TabControl from recreating its children
感谢Shoe指出我正确的方向导致最终解决方案:)
答案 1 :(得分:0)
我有类似的问题,我提出了这个解决方案
void OnAddWorkSpace(object Sender, EventArgs e)
{
WorkspaceViewModel loclViewModel = (e as WorkSpaceEventArgs).ViewModel;
DataTemplate loclTemplate = (DataTemplate)Resources[new DataTemplateKey(loclViewModel.GetType())];
if (loclTemplate != null)
{
DXTabItem loclTabItem = new DXTabItem();
loclTabItem.Content = loclTemplate.LoadContent();
(loclTabItem.Content as DependencyObject).SetValue(DataContextProperty, loclViewModel);
loclTabItem.HeaderTemplate = (DataTemplate)FindResource("WorkspaceItemTemplate");
loclTabItem.Header = (loclTabItem.Content as DependencyObject).GetValue(DataContextProperty);
MainContentTabs.Items.Add(loclTabItem);
}
}
我在ViewModel中创建了一个事件处理程序,我的View订阅了它。我的ViewModel对象被添加到集合中。现在,每当添加ViewModel时,我的MainViewModel都会调用这个偶数处理程序。
在这里,我们需要找到为我们正在添加的ViewModel的DataType定义的DataTemplate。一旦我们掌握了这一点,我们就可以创建一个标签项,然后从datatemplate加载内容。
由于我使用的是DevExpress TabControl,我创建了DXTabItem。 TabItem也应该一样。