这是我用来获取过去类似的问题 - 我希望它(这个一般的逻辑可应用于广泛的阿瓦隆编辑器相关的问题)有用的人......
实际发生的可能是阿瓦隆的过错(与ListItem
等组合)。它打乱了鼠标操作和我猜测的焦点(这应该是在TextArea
命令和CanExecute
工作
的mouse handling
是问题 - 因为如果你只需按windows context menu
键它会弹出一个使用启用命令的常规菜单 Avalon编辑器具有复杂的鼠标/键处理功能(它很难编辑为 ) - 并且在键盘上,它在TextArea上执行了明确的'focus
'。您还可以通过将方法(Editing/EditingCommandHandler.cs
,下载 Avalon源)上的断点,其中实际ly处理 ApplicationCommands.Copy
。对于'键盘'菜单,它首先在 那里,然后弹出。对于“鼠标”,它弹出 - 然后在 退出它检查CanExecute
(进入该方法)。那是全部 错!
而勘误表...
你自己的命令没有问题,只是正常暴露你的命令,一切都应该工作。
对于ApplicationCommands
(即RoutedCommand
)不连线正确 - 和Execute
,CanExecute
不走它应该,即TextArea
。为了解决这个问题,你需要将这些命令写入你自己的包装中 - 并且基本上调用TextArea处理 - 这只是几行代码,但这是必要的步骤(我认为没有更好的解决方案这不足以修复Avalon的代码 - 这可能是一种痛苦,但我从未想过)。
(全部是基于你的榜样 - 填写在我离开了空格) 您的XAML:
<Window.Resources>
<DataTemplate DataType="{x:Type my:myClass}">
<StackPanel>
<my:AvalonTextEditor x:Name="xmlMessage" SyntaxHighlighting="XML" ShowLineNumbers="True" EditText="{Binding text}" >
<my:AvalonTextEditor.ContextMenu>
<ContextMenu x:Name="mymenu1">
<ContextMenu.Resources>
<Style TargetType="MenuItem">
<Setter Property="CommandParameter" Value="{Binding Path=., RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"/>
</Style>
</ContextMenu.Resources>
<MenuItem Header="My Copy" Command="{Binding CopyCommand}" />
<MenuItem Header="My Paste" Command="{Binding PasteCommand}" />
<MenuItem Header="My Cut" Command="{Binding CutCommand}" />
<MenuItem Header="My Undo" Command="{Binding UndoCommand}" />
<MenuItem Header="My Redo" Command="{Binding RedoCommand}" />
<Separator />
<MenuItem Command="Undo" />
<MenuItem Command="Redo" />
<Separator/>
<MenuItem Command="Cut" />
<MenuItem Command="Copy" />
<MenuItem Command="Paste" />
</ContextMenu>
</my:AvalonTextEditor.ContextMenu>
</my:AvalonTextEditor>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel>
<DockPanel>
<ListView ItemsSource="{Binding collection}" />
<ContentControl Content="{Binding mc}" />
</DockPanel>
</StackPanel>
背后的代码 - 视图模型:
(注:我离开了命名为您并把它 - 但请不要使用小型大写道具:)
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MyViewModel()
{
collection = new ObservableCollection<myClass>(new[]
{
new myClass{ text = "some more test - some more test - some more test - some more test - some more test - some more test - some more test - some more test - some more test - " },
new myClass{ text = "test me test me = test me test me = test me test me = test me test me = test me test me = test me test me = " },
new myClass{ text = "test again - test again - test again - test again - test again - " },
new myClass{ text = "test again - test again - " },
new myClass{ text = "test again - " },
new myClass{ text = "test" },
});
mc = new myClass();
}
public ObservableCollection<myClass> collection { get; set; }
public myClass mc { get; set; }
}
public class myClass
{
public string text { get; set; }
AvalonRelayCommand _copyCommand;
public AvalonRelayCommand CopyCommand
{ get { return _copyCommand ?? (_copyCommand = new AvalonRelayCommand(ApplicationCommands.Copy) { Text = "My Copy" }); } }
AvalonRelayCommand _pasteCommand;
public AvalonRelayCommand PasteCommand
{ get { return _pasteCommand ?? (_pasteCommand = new AvalonRelayCommand(ApplicationCommands.Paste) { Text = "My Paste" }); } }
AvalonRelayCommand _cutCommand;
public AvalonRelayCommand CutCommand
{ get { return _cutCommand ?? (_cutCommand = new AvalonRelayCommand(ApplicationCommands.Cut) { Text = "My Cut" }); } }
AvalonRelayCommand _undoCommand;
public AvalonRelayCommand UndoCommand
{ get { return _undoCommand ?? (_undoCommand = new AvalonRelayCommand(ApplicationCommands.Undo) { Text = "My Undo" }); } }
AvalonRelayCommand _redoCommand;
public AvalonRelayCommand RedoCommand
{ get { return _redoCommand ?? (_redoCommand = new AvalonRelayCommand(ApplicationCommands.Redo) { Text = "My Redo" }); } }
}
(注:刚丝了Window.DataContext
查看模型,像你一样)
这需要包装两个自定义类。
public class AvalonTextEditor : TextEditor
{
#region EditText Dependency Property
public static readonly DependencyProperty EditTextProperty =
DependencyProperty.Register(
"EditText",
typeof(string),
typeof(AvalonTextEditor),
new UIPropertyMetadata(string.Empty, EditTextPropertyChanged));
private static void EditTextPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
AvalonTextEditor editor = (AvalonTextEditor)sender;
editor.Text = (string)e.NewValue;
}
public string EditText
{
get { return (string)GetValue(EditTextProperty); }
set { SetValue(EditTextProperty, value); }
}
#endregion
#region TextEditor Property
public static TextEditor GetTextEditor(ContextMenu menu) { return (TextEditor)menu.GetValue(TextEditorProperty); }
public static void SetTextEditor(ContextMenu menu, TextEditor value) { menu.SetValue(TextEditorProperty, value); }
public static readonly DependencyProperty TextEditorProperty =
DependencyProperty.RegisterAttached("TextEditor", typeof(TextEditor), typeof(AvalonTextEditor), new UIPropertyMetadata(null, OnTextEditorChanged));
static void OnTextEditorChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
ContextMenu menu = depObj as ContextMenu;
if (menu == null || e.NewValue is DependencyObject == false)
return;
TextEditor editor = (TextEditor)e.NewValue;
NameScope.SetNameScope(menu, NameScope.GetNameScope(editor));
}
#endregion
public AvalonTextEditor()
{
this.Loaded += new RoutedEventHandler(AvalonTextEditor_Loaded);
}
void AvalonTextEditor_Loaded(object sender, RoutedEventArgs e)
{
this.ContextMenu.SetValue(AvalonTextEditor.TextEditorProperty, this);
}
}
public class AvalonRelayCommand : ICommand
{
readonly RoutedCommand _routedCommand;
public string Text { get; set; }
public AvalonRelayCommand(RoutedCommand routedCommand) { _routedCommand = routedCommand; }
public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } }
public bool CanExecute(object parameter) { return _routedCommand.CanExecute(parameter, GetTextArea(GetEditor(parameter))); }
public void Execute(object parameter) { _routedCommand.Execute(parameter, GetTextArea(GetEditor(parameter))); }
private AvalonTextEditor GetEditor(object param)
{
var contextMenu = param as ContextMenu;
if (contextMenu == null) return null;
var editor = contextMenu.GetValue(AvalonTextEditor.TextEditorProperty) as AvalonTextEditor;
return editor;
}
private static TextArea GetTextArea(AvalonTextEditor editor)
{
return editor == null ? null : editor.TextArea;
}
}
注:
EditText
仅仅是一个依赖属性 - 能够为bind
文本(你text
) - 这是一个Avalon缺点。这里只是为了好玩,但你可能需要它,所以我把它留下了。
使用AvalonRelayCommand
重新连接应用程序路由命令 - 对于其他的东西使用你自己的命令实现。这两类是核心。
您需要使用AvalonTextEditor
而不是文本编辑 - 这只是一个很小的包装 - 挂钩ContextMenu
与其他问题TextEditor
(分开,菜单项suffering
由于缺乏visual tree
- 你不能得到任何控制从它很容易)。我们需要从CommandParameter
(设置为ContextMenu
)获得TextEditor
的编号。这可以通过一些附件属性来完成(无需重写TextEditor),但是这种方式看起来更清晰。在XAML方面 - 只需进行一些小的修改 - 使用包装编辑器 - 并且您有一个MenuItem
样式,其中injects
是每个命令的正确参数(您可以通过其他方式更好地实现)。
这不是一个hack
- 我们只是shortcutting的 鼠标操作的缺点 - 通过手动调用TextArea
命令处理。 这就是它。
Enjoy!
我试过你的代码,它工作得很好!我使用了[This CodeProject article](http://www.codeproject。com/Articles/42490/Using-AvalonEdit-WPF-Text-Editor),并将代码放入xaml中。 – 2013-02-17 12:57:53
问题可能来自您省略的'avalonedit:TextEditor'的其他属性。 – 2013-02-17 12:59:34
@ MD.Unicorn:感谢您的评论。该文章使用的是Text属性的控件的内容属性来显示文本,但我使用依赖属性来使用绑定来显示控件内容,根据[这篇文章](http://stackoverflow.com/questions/14855304)/two-way-binding-in-avalonedit-doesnt-work),所以我必须缺少一些破坏命令绑定的东西。你有什么主意吗? – 2013-02-17 13:50:22