我有一个选项卡控件的项目模板的数据模板,如下所示;
<DataTemplate x:Key="TabItemTemplate">
<DockPanel Width="120">
<Button
Command="{Binding Path=DataContext.DeleteTimeTableCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
Content="X"
Cursor="Hand"
DockPanel.Dock="Right"
Focusable="False"
Margin="0,1,0,0"
Padding="0"
VerticalContentAlignment="Bottom"
Width="16" Height="16" />
这没问题,因为它在选项卡控件中为我提供了一个按钮,允许删除当前的选项卡项。
我遇到的问题是我绑定(bind)的删除命令有一个 canExecute 方法,该方法可以更新选项卡控件中所有选项卡上的所有按钮。我只想影响当前选项卡。
我有 CanDelete 属性,我想将其包含在我的命令中。我正在尝试在 CommandParameters 上找到一个很好的示例,因为我认为这是我需要走的路。
有人对最好的方法有好的建议吗?
谢谢。
最佳答案
我怀疑您是否仍然需要帮助,但我想无论如何我都会尝试回答这个问题。
我过去的做法是使绑定(bind)到 TabControl 的项目集合成为简单 ViewModel 对象的集合。这样您就可以为每个选项卡实现 CanXXX 逻辑,而不是作为一个整体来实现 TabControl 或 View 。
在此示例中,我使用 Josh Smith's MVVM article 中显示的 RelayCommand 类。 .
MainViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
namespace TabBinding.ViewModels
{
class MainViewModel : ViewModelBase
{
private ObservableCollection<TabViewModel> _Tabs;
public ObservableCollection<TabViewModel> Tabs
{
get { return _Tabs; }
set
{
_Tabs = value;
OnPropertyChanged(this, "Tabs");
}
}
public MainViewModel()
{
var tabs = new ObservableCollection<TabViewModel>();
tabs.Add(new TabViewModel() { TabHeader = "Tab1", Content="Content For Tab1" });
tabs.Add(new TabViewModel() { TabHeader = "Tab2", Content = "Content For Tab2" });
tabs.Add(new TabViewModel() { TabHeader = "Tab3", Content = "Content For Tab3" });
tabs.Add(new TabViewModel() { TabHeader = "Tab4", Content = "Content For Tab4" });
Tabs = tabs;
}
}
}
TabViewModel.cs
using System.Windows.Input;
using System.Windows;
namespace TabBinding.ViewModels
{
class TabViewModel : ViewModelBase
{
RelayCommand _CloseTabCommand;
private string _TabHeader;
public string TabHeader
{
get { return _TabHeader; }
set
{
_TabHeader = value;
OnPropertyChanged(this, "TabHeader");
}
}
private string _Content;
public string Content
{
get { return _Content; }
set
{
_Content = value;
OnPropertyChanged(this, "Content");
}
}
public ICommand CloseTabCommand
{
get
{
if (_CloseTabCommand == null)
{
_CloseTabCommand = new RelayCommand(
param => this.CloseTab(),
param => this.CanCloseTab
);
}
return _CloseTabCommand;
}
}
public void CloseTab()
{
MessageBox.Show("Close Me!");
}
bool CanCloseTab
{
get { return (TabHeader == "Tab2" || TabHeader == "Tab4"); }
}
}
}
ViewModelBase.cs
using System.ComponentModel;
namespace TabBinding.ViewModels
{
class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(object sender, string propertyName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
}
}
}
RelayCommand.cs
using System;
using System.Diagnostics;
using System.Windows.Input;
namespace TabBinding
{
/// <summary>
/// A command whose sole purpose is to
/// relay its functionality to other
/// objects by invoking delegates. The
/// default return value for the CanExecute
/// method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
}
MainWindow.xaml
<Window x:Class="TabBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:TabBinding.ViewModels"
Title="MainWindow" Height="360" Width="550">
<Window.Resources>
<vm:MainViewModel x:Key="Data" />
</Window.Resources>
<Grid DataContext="{StaticResource Data}">
<TabControl
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10,10,10,10"
Width="500"
Height="300"
ItemsSource="{Binding Tabs}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="X" Margin="0,0,10,0" Command="{Binding CloseTabCommand}" />
<TextBlock Text="{Binding TabHeader}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Content" Value="{Binding Content}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Grid>
</Window>
App.xaml
<Application x:Class="TabBinding.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
关于WPF 数据模板命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2117136/