使用小型编辑器项目学习WPF并考虑MVVM进行设计。
以下代码抛出"在System.Windows.Data.Binding'上提供价值。抛出异常。"在运行时首次解析XAML。没有构建错误。
如何最好地将我的ICommands绑定到应用程序命令关闭,保存,另存为,打开,新建等。
目前我只有关闭和新设置。
XAML代码:
<Window x:Class="Editor.Views.EditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Editor.Views"
xmlns:vm="clr-namespace:Editor.ViewModels"
xmlns:userControls="clr-namespace:Editor.UserControls"
mc:Ignorable="d"
Title="EditorView" Height="600" Width="800" WindowStartupLocation="CenterScreen">
<Window.Resources>
<DataTemplate DataType="{x:Type vm:DocumentViewModel}">
<ContentControl Content="{Binding DocTextBox}" />
</DataTemplate>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Close"
Executed="{Binding ExitCommand}" />
<CommandBinding Command="ApplicationCommands.New"
Executed="{Binding NewDocumentCommand}" />
<!--<CommandBinding Command="ApplicationCommands.Open"
Executed="OpenDocument" />
<CommandBinding Command="ApplicationCommands.Save"
CanExecute="SaveDocument_CanExecute"
Executed="SaveDocument" />
<CommandBinding Command="ApplicationCommands.SaveAs"
Executed="SaveDocumentAs" />-->
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Key="N" Modifiers="Control" Command="{Binding NewDocumentCommand}" />
<KeyBinding Key="F4" Modifiers="Control" Command="{Binding CloseDocumentCommand}" />
</Window.InputBindings>
<DockPanel>
<userControls:Menu x:Name="menu"
DockPanel.Dock="Top" />
<TabControl ItemsSource="{Binding Documents}" SelectedIndex="{Binding SelectedIndex}">
<TabControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding FileName}" />
<Button Command="{Binding CloseCommand}" Content="X" Margin="4,0,0,0" FontFamily="Courier New" Width="17" Height="17" VerticalContentAlignment="Center" />
</WrapPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
</DockPanel>
</Window>
ViewModel代码:
public class EditorViewModel : ViewModelBase
{
private static int _count = 0;
public EditorViewModel()
{
Documents = new ObservableCollection<DocumentViewModel>();
Documents.CollectionChanged += Documents_CollectionChanged;
}
#region Event Handlers
void Documents_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null && e.NewItems.Count != 0)
foreach (DocumentViewModel document in e.NewItems)
document.RequestClose += this.OnDocumentRequestClose;
if (e.OldItems != null && e.OldItems.Count != 0)
foreach (DocumentViewModel document in e.OldItems)
document.RequestClose -= this.OnDocumentRequestClose;
}
private void OnDocumentRequestClose(object sender, EventArgs e)
{
CloseDocument();
}
#endregion
#region Commands
private RelayCommand _exitCommand;
public ICommand ExitCommand
{
get { return _exitCommand ?? (_exitCommand = new RelayCommand(() => Application.Current.Shutdown())); }
}
private RelayCommand _newDocumentCommand;
public ICommand NewDocumentCommand
{
get { return _newDocumentCommand ?? (_newDocumentCommand = new RelayCommand(NewDocument)); }
}
private void NewDocument()
{
_count++;
var document = new DocumentViewModel { FileName = "New " + _count, DocTextBox = new RichTextBox() };
Documents.Add(document);
SelectedIndex = Documents.IndexOf(document);
}
private RelayCommand _closeDocumentCommand;
public ICommand CloseDocumentCommand
{
get { return _closeDocumentCommand ?? (_closeDocumentCommand = new RelayCommand(CloseDocument, param => Documents.Count > 0)); }
}
private void CloseDocument()
{
Documents.RemoveAt(SelectedIndex);
SelectedIndex = 0;
}
#endregion
#region Public Members
public ObservableCollection<DocumentViewModel> Documents { get; set; }
private int _selectedIndex = 0;
public int SelectedIndex
{
get { return _selectedIndex; }
set
{
_selectedIndex = value;
OnPropertyChanged();
}
}
#endregion
}
答案 0 :(得分:0)
当您使用CommandBinding
时,可以说您正在配置视图应处理的命令。因此,我不清楚在视图模型中实现命令是否有意义。相反,如果视图模型应该拥有该命令,则使用其命令,而不是预定义的命令。
要求将ICommand
对象绑定到应用程序命令是没有意义的。 ApplicationCommands
个对象本身就是ICommand
个实现! (RoutedUICommand
,具体而言。)
如果您的视图模型已经为标准命令实现了ICommand
,那么只需绑定到那些:
<CommandBinding Command="{Binding ExitCommand}"/>
如果您确实想使用ApplicationCommands
命令,那么您需要为Executed
和CanExecute
事件订阅事件处理程序方法,然后将这些事件委托给查看模型。例如:
<CommandBinding Command="ApplicationCommands.Close"
Executed="Close_Executed" />
然后在代码隐藏中,这样的事情:
void Close_Executed(object sender, ExecutedRoutedEventArgs e)
{
ICommand command = (ICommand)e.Parameter;
command.Execute(null);
}
请注意,在这种情况下,您必须确保在命令源本身设置CommandParameter
。即在您调用命令的CommandParameter={Binding ExitCommand}
和InputBinding
中包含Button
。这可能会变得乏味。
或者,您可以假设DataContext
对象的Source
是您的视图模型并直接从该命令获取命令:
void Close_Executed(object sender, ExecutedRoutedEventArgs e)
{
EditorViewModel viewModel = (EditorViewModel)((FrameworkElement)e.Source).DataContext;
ICommand command = viewModel.ExitCommand;
command.Execute(e.Parameter);
}