wpf 使用 mvvm 在选项卡项中动态包含关闭按钮
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28298574/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Include a close button in a tab item dynamically using mvvm
提问by Ani_1317
I have the a tabcontrol in my MainWindow. The default/first tab of the tabcontrol is the home user control. In the home page I have a button that can add further tabs.
我的 MainWindow 中有一个 tabcontrol。tabcontrol 的默认/第一个选项卡是家庭用户控件。在主页中,我有一个可以添加更多选项卡的按钮。
MainWindow.xaml:
主窗口.xaml:
<Window.Resources>
<DataTemplate x:Key="ClosableTabItemTemplate">
<Button Content="X" Cursor="Hand" DockPanel.Dock="Right" Focusable="False"
FontFamily="Courier" FontSize="9" FontWeight="Bold" Margin="0,1,0,0" Padding="0"
VerticalContentAlignment="Bottom" Width="16" Height="16"/>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl Name="tabMain" ItemsSource="{Binding TabItems,UpdateSourceTrigger=PropertyChanged}" />
</Grid>
In my view model I have the add functionality where a new tab has been added. I need the close button for all these newly added tabs.
在我的视图模型中,我有添加功能,其中添加了一个新选项卡。我需要所有这些新添加的标签的关闭按钮。
public MainViewModel()
{
try
{
Home Item2 = new Home();
TabItems.Add(new TabItem() { Header = "Home", Content = Item2 });
}
catch(Exception ex)
{
MessageBox.Show("Exception "+ex);
}
//Function to add new tabs.
public void AddNewTabs()
{
ChildWindow childContent = new ChildWindow();
TabItem item = new TabItem() { Header = "New Tab", Content = childContent};
item.MouseDoubleClick += new MouseButtonEventHandler(tab_MouseDoubleClick);
TabItems.Add(item);
}
Right now new tabs are being added but without the close button. I have tried giving
现在正在添加新标签,但没有关闭按钮。我试过给予
item.HeaderTemplate = FindResource("ClosableTabItemTemplate") as DataTemplate;
But it shows error.
但它显示错误。
Any help would be appreciated.
任何帮助,将不胜感激。
Thanks in advance.
提前致谢。
回答by James Willock
回答by ELH
You view model must not interact directly with the view in order to respect the Mvvm pattern, meaning that you need to use commands instead of Events, don't use any view related control in your View model logic ..
为了尊重 Mvvm 模式,您的视图模型不得直接与视图交互,这意味着您需要使用命令而不是事件,不要在您的视图模型逻辑中使用任何与视图相关的控件..
here a cleaner way to achieve what you're looking for :
这里有一种更干净的方式来实现您正在寻找的东西:
FirstIn the view use the TabControlContentTemplateand ItemTemplateInstead :
首先在视图中使用TabControlContentTemplate和ItemTemplate代替:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Button Content="Add new tab" Command="{Binding AddNewTabCommand}"></Button>
<TabControl Grid.Row="1" Name="TabMain" ItemsSource="{Binding TabItems,UpdateSourceTrigger=PropertyChanged}" >
<TabControl.ItemTemplate>
<DataTemplate >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Header}"/>
<Button Content="X" Cursor="Hand" DockPanel.Dock="Right" Focusable="False"
FontFamily="Courier" FontSize="9" FontWeight="Bold" Margin="0,1,0,0" Padding="0"
VerticalContentAlignment="Bottom" Width="16" Height="16" Command="{Binding DataContext.CloseTabCommand,RelativeSource={RelativeSource AncestorType={x:Type Window}}}" CommandParameter="{Binding ElementName=TabMain,Path=SelectedItem}"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Content}" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
Second, In the ViewModel Create a class TabItem that will hold a tab Content and header (customize it as needed), you may want to implement the INotifyPropertyChangedinterface if the class reflect any changes to the view,
其次,在 ViewModel 中创建一个 TabItem 类,该类将保存一个选项卡内容和标题(根据需要自定义),INotifyPropertyChanged如果该类反映了对视图的任何更改,您可能需要实现该接口,
Third, define the commands to add and romove a TabItem from TabItems ObservableCollection,
第三,定义从 TabItems 添加和删除 TabItem 的命令ObservableCollection,
here the viewModel Code :
这里的 viewModel 代码:
public class TabItem
{
public String Header { get; set; }
public String Content { get; set; }
}
public class MainViewModel : INotifyPropertyChanged
{
private ObservableCollection<TabItem> _tabItems;
public ObservableCollection<TabItem> TabItems
{
get
{
return _tabItems;
}
set
{
if (_tabItems == value)
{
return;
}
_tabItems = value;
OnPropertyChanged();
}
}
private RelayCommand _addNewTabCommand;
public RelayCommand AddNewTabCommand
{
get
{
return _addNewTabCommand
?? (_addNewTabCommand = new RelayCommand(
() =>
{
TabItems.Add(new TabItem()
{
Header = "NewTab",
Content = "NewContent"
});
}));
}
}
private RelayCommand<TabItem> _closeTabCommand;
public RelayCommand<TabItem> CloseTabCommand
{
get
{
return _closeTabCommand
?? (_closeTabCommand = new RelayCommand<TabItem>(
(t) =>
{
TabItems.Remove(t);
}));
}
}
public MainViewModel()
{
TabItems = new ObservableCollection<TabItem>()
{
new TabItem()
{
Header = "Home",
Content = "Home Content"
},
new TabItem()
{
Header = "Header1",
Content = "Content1"
}
};
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
the output :
输出 :


Ps: My MainWindowView DataContextis set to MainWindowViewModel, and tha's why i am using AncestorTypeto find the CloseTabCommand
Ps:我的MainWindow视图DataContext设置为MainWindowViewModel,这就是我AncestorType用来查找CloseTabCommand

