当前位置: 首页 > news >正文

青州网站谷歌优化seo

青州网站,谷歌优化seo,企业建站划算吗,做网站开发学什么内容在设计良好的Windows应用程序中#xff0c;应用程序逻辑不应位于事件处理程序中#xff0c;而应在更高层的方法中编写代码。其中的每个方法都代表单独的应用程序任务。每个任务可能依赖其他库。 使用这种设计最明显的方式是在需要的地方添加事件处理程序#xff0c;并使用各…在设计良好的Windows应用程序中应用程序逻辑不应位于事件处理程序中而应在更高层的方法中编写代码。其中的每个方法都代表单独的应用程序任务。每个任务可能依赖其他库。 使用这种设计最明显的方式是在需要的地方添加事件处理程序并使用各个事件处理程序调用恰当的应用程序方法。本质上窗口代码变成了一个精简的交换台可以响应输入并将请求转发到应用程序。 尽管这种设计非常合理但却没有减少任何工作。许多应用程序任务可通过各种不同的路由触发所以经常需要编写多个时间处理程序来调用相同的应用程序方法。就其本身而言这并不是什么问题因为交换台代码非常简单但当需要处理用户界面的状态时问题就变复杂了。 设想有一个程序该程序包含方法 PrintDocument()。使用4中方式触发该方法通过主菜单选择File|Print菜单项通过上下文菜单在某处右击并选择Print菜单项通过键盘快捷键CtrlP以及通过工具栏。在应用程序生命周期的特定时刻需要暂时禁用PrintDocument() 任务。这意味着需要禁用两个菜单选项和一个工具栏按钮使他们不能被单击并需要忽略 CtrlP快捷键。编写代码完成这些工作并在后面添加代码以启用这些控件是很麻烦的更糟的是如果没有正确完成这项工作可能会使不同状态的代码块不正确的相互重叠从而导致某个控件在可应该可用时而被启用。编写和调试这类代码是Windows开发中最枯燥的内容之一。 幸运的是WPF使用新的命令模型帮助解决这些问题。它增加了两个重要特性 1、将事件委托到适当的命令 2、使控件的启用状态和相应的命令状态保持同步 命令模型 WPF命令模型由许多可变的部分组成。总之它们都具有如下4个重要元素 命令 命令表示应用程序任务并且跟踪任务是否能够被执行。然而命令实际上不包含执行应用程序任务的代码。 命令绑定 每个命令绑定针对用户界面的具体区域将命令连接到相关的应用程序逻辑。这种分解的设计是非常重要的因为单个命令可用于应用程序中的多个地方并且在每个地方具有不同的意义。为处理这一问题需要将同一命令与不同的命令源绑定。 命令源 命令源触发命令。例如MenuItem和Button都是命令源。单击它们都会执行绑定命令。 命令目标 命令目标是在其中执行命令的元素。例如Paste命令可在TextBox 控件中插入文本而OpenFile 命令可在DocumentViewer中打开文档。根据命令的本质目标可能很重要也可能不重要。 ICommand接口 WPF命令模型的核心是 System.Windows.Input.ICommand 接口该接口定义了命令的工作原理。 public interface ICommand{event EventHandler? CanExecuteChanged;bool CanExecute(object? parameter);void Execute(object? parameter);} 在一个简单实现中Execute()方法将包含应用程序任务逻辑。然而WPF的实现更复杂它使用Execute()方法引发一个更复杂的过程该过程最终触发在应用程序其他地方处理的事件。通过这种方式可以使用预先准备好的命令类并插入自己的逻辑。还可以灵活地在几个不同的地方使用同一个命令。 CanExecute()方法返回命令的状态——如果命令可用就返回true如果不可以就返回false。Execute() 和 CanExecute()方法都接受一个附加的参数对象可使用该对象传递所需的任何附加信息。 最后当命令状态改变时引发CanExecuteChanged事件。对于使用命令的任何控件这是指示信号表示他们应当调用CanExecute()方法检查命令的状态。通过使用该事件当命令可用时命令源可自动启用自身当命令不可用是禁用自身。 RoutedCommand 当创建自己的命令时不会直接实现ICommand接口而是使用System.Windows.Input.RoutedCommand类该类自动实现ICommand接口。RoutedCommand类是WPF中唯一实现了ICommand接口的类。换句话说所有WPF命令都是RoutedCommand类及其派生类的实例。 RoutedCommand类不包含任何应用程序逻辑而只代表命令这意味着各个RoutedCommand对象具有相同的功能。 RoutedCommand类为事件冒泡和隧道添加了一些额外的基础结构。鉴于ICommand接口封装了命令的思想——可被触发的动作并可被启用或禁用——RoutedCommand类对命令进行的了修改使命令可在WPF元素层次结构中冒泡以便获得正确的事件处理程序。 为支持路由时间RoutedCommand类私有的实现了ICommand接口并添加了RoutedCommand接口方法的一些不同版本。最明显的变化是Execute() 和 CanExecute() 方法使用了一个额外参数。 public bool CanExecute(object parameter, IInputElement target); public void Execute(object parameter, IInputElement target); 参数target是开始处理事件的元素。事件从target元素开始然后冒泡至高层的容器知道应用程序为了执行合适的任务而处理了事件为了处理Executed事件元素还需要借助于另一个类——CommandBinding类的帮助。 除上面的修改外RoutedCommand类还引入了三个属性命令名称Name、包含命令的类OwnerType以及任何可用于触发命令的按键或鼠标操作位于InputGestures集合中。 RoutedUICommand 在程序中处理的大部分命令不是RoutedCommand对象而是RoutedUICommand类的实例RoutedUICommand类继承自RoutedCommand类实际上WPF提供的所有预先构建好的命令都是RoutedUICommand对象。 RoutedUICommand类用于具有文本的命令这些文本显示在用户界面中的某些地方。RoutedUICommand类只增加了Text属性该属性是为命令显示的文本。 为命令定义命令文本而不是在控件上定义文本的优点是可以在某个位置执行本地化。但如果命令文本永远不会在用户界面的任何地方显示那么RoutedUICommand类和RoutedCommand类是等效的。 命令库 WPF设计者认识到每个应用程序可能有大量的命令并且对于许多不用的应用程序很多命令是通用的。为减少创建这些命令所需的工作WPF提供了基本命令库基本命令库中保存的命令超过100条。这些命令通过以下5个专门的静态类的静态属性提供 ApplicationCommands 该类提供通用命令包括剪贴板命令如Copy、Cut和Paste以及文档命令如New、Open、Save、SaveAs和Print等。 NavigationCommands 该类提供了用于导航的命令包括基于页面的应用程序设计的一些命名如BrowseBack、BrowseForward和NextPage以及其他适合于基于文档的应用程序的命令如IncreaseZoom和Refresh。 EditingCommands 该类提供了许多重要的文档编辑命令包括用于移动的命令MoveToLineEnd、MoveLeftByWord和MoveUpByPage等选择内容的命令SelectToLineEnd、SelectLeftByWord以及改变格式的命令ToggleBold和ToggleUnderline。 ComponentCommands 该类提供了由用户界面组件使用的命令包括用于移动和选择内容的命令这些命令和EditingCommands类中的一些命令类似。 MediaCommands 该类提供了一组用于处理多媒体的命令如Play、Pause、NextTrack以及IncreaseVolume。 这些单独的命令对象仅是一些标志器不具有实际功能。然而许多命令都有一个额外的特征默认输入绑定。例如ApplicationCommands.Open 命令被映射到CtrlO快捷键。只要将命令绑定到命令源并未窗口添加命令源这个快捷键就会被激活即使没有在用户界面的任何地方显示该命令也同样如此。 命令源 命令库中的命令始终可用。触发他们最简单的方法是将他们关联到实现了ICommandSource接口的控件其中包括继承自ButtonBase类的控件Button和CheckBox等、单独的ListBoxItemduix 、Hyperlink 以及MenuItem。 ICommandSource接口定义了三个属性 public interface ICommandSource{ICommand Command { get; }object CommandParameter { get; }IInputElement CommandTarget { get; }} Command 指向连接的命令这是唯一必需的细节 CommandParameter 提供其他希望随命令发送的数据 CommandTarget 确定将在其中执行命令的元素 命令绑定 将命令关联到命令源时会看到命令源会被自动禁用。这是因为命令源已经查询到命令的状态而且由于命令还没有与其关联的绑定所以命令源被认为是禁用的 Button CommandApplicationCommands.New ContentNew / 为改变这种状态需要为命令创建绑定以明确以下三件事情 1、当命令被触发时执行什么操作 2、如何确定命令是否能够被执行这是可选的。如果未提供这一细节只要提供了关联的事件处理程序命令总是可用的。 3、命令在何处起作用。例如命令可被限制在单个按钮中使用或在整个窗口中使用这种情况更常见。 通过代码为命令创建绑定 CommandBinding binding new CommandBinding(ApplicationCommands.New); binding.Executed NewCommandExecuted; this.CommandBindings.Add(binding); 这里创建的CommandBinding对象被添加到包含窗口的CommandBindings集合中这通过事件冒泡进行工作。实际上当单击按钮时CommandBinding.Executed 事件从按钮冒泡到包含元素。 通过XAML标记创建命令绑定 Window.CommandBindingsCommandBinding CommandOpen ExecutedOpenCommandExecuted / /Window.CommandBindings 尽管习惯上为窗口添加所有绑定单CommandBindings属性实际是在 UIElement基类中定义的。这意味着任何元素都支持该属性例如如果将命令绑定到使用它的按钮中。为得到最大的灵活性命令绑定通常被添加到顶级窗口。如果希望在多个窗口中使用相同的命令需要在这些窗口中分别创建命令绑定。 也可以处理CommandBinding.PreviewExecuted事件首先在最高层次的容器中引发该事件然后隧道路由至按钮。在事件完成前可通过事件隧道拦截和停止事件。如果将 RoutedEventArgs.Handled 属性设置为true将永远不会发生Executed事件。 使用多命令源 在按钮中触发事件看起不那么直接然而当添加相同的命令的更多控件时额外命令层的意义就会体现出来。 MenuMenuItem HeaderFileMenuItem CommandNew //MenuItem /Menu 这里并没有为MenuItem设置Header属性。这是因为MenuItem类足够智能如果没有设置Header属性它将从命令中提取文件Button控件不具有这一特性。虽然该特性带来的便利看起来不大但如果计划使用不同的语言本地化应用程序这一特性就很重要了。在这一情况下只需要在一个地方修改文本即可通过设置命令的Text属性这比在整个窗口中进行跟踪更容易。 MenuItem类还有一项功能能自动提取 Command.InputBindings 集合中的第一个快捷键如果存在的话。对于ApplicationCommands.New 命令对象这意味着在菜单文本旁边会显示CtrlN 快捷键。 需要注意的是不需要为菜单项另外创建命令绑定。前面在窗口下创建的命令绑定现在被两个不同的控件使用每个控件都将它们的工作传递给同一个命令事件处理程序。 微调命令文本 前面看到菜单具有自动提取命令的文本的功能它实际获取的 RoutedUICommand 的 Text属性那么其他的实现ICommandSource的控件应该也能提取相应Command的Text属性。我们可以通过数据绑定来获取 Button CommandApplicationCommands.New Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text} / 直接调用命令 并非只能使用实现了ICommandSource 接口的类来触发希望执行的命令。也可以用Execute() 方法直接调用来自任何事件处理程序的方法。这是需传递参数值或null引用和对目标元素的引用。 ApplicationCommands.New.Execute(null, target); 也可以在关联的CommandBinding对象中调用Execute()方法。在这种情况下不需要提供目标元素因为会自动将公开正在使用CommandBindings集合的元素设置为目标元素 this.CommandBindings[0].Command.Execute(null); 这种方法只是用了半个命令模型虽然也可触发命令但不能响应命令的状态变化。 禁用命令 如果想要创建状态在启用和禁用之间变化的命令您将体会到命令模型的真正优势。命令的启用与禁用通过CommandBinding的 CanExecute 事件控制可通过如下方式为该事件关联事件处理程序 CommandBinding CommandSave ExecutedSaveCommand_Executed CanExecuteSaveCommand_CanExecute/ 在事件处理程序中只需相应的设置 CanExecuteRoutedEventArgs.CanExecute 属性 private void SaveCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e) {e.CanExecute isDirty; } 在这里当isDirty为false时就禁用命令当isDirty为true时启用命令。 当使用 CanExecute 事件时还需要理解一个问题。由WPF负责调用 RoutedCommandCanExecute () 方法来触发事件处理程序并确定命令的状态。当WPF命令管理器探测到某个确信十分重要的变化时——例如当焦点从一个控件移到另一控件上时或执行了某个命令后WPF命令管理器就会完成该工作。控件还能引发 CanExecuteChanged 事件以通知WPF重新评估命令——例如当用户在文本框中按下一个键时会发生该事件。总之CanExecute事件会被频繁地触发不应该在该事件处理程序中使用耗时的代码。 具有内置命令的控件 一些输入控件可以自行处理命令事件。例如TextBox类处理Cut、Copy、Paste命令等。当控件具有自己的硬编码命令逻辑时为使命令工作不需要做其他任何事情。例如对于TextBox控件添加以下工具栏按钮就会自动获得对剪切、复制、和粘贴文本的支持 ToolBarButton CommandCut Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandCopy Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandPaste Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/ /ToolBar 现在单击这些按钮中的任意一个当文本框具有焦点时就可以复制、剪切或从剪贴板粘贴文本。有趣的是文本框还处理CanExecute事件。如果当前未在文本框中选中任何内容就会禁用剪切和复制命令。当焦点移动到其它不支持这些命令的控件时会自动禁用所有者三个命令除非关联自己的CanExecute事件处理程序以启用这些命令。 这里有一个有趣的细节。Cut、Copy、Paste命令被具有焦点的文本框处理。然而有工具栏上的按钮触发的命令是完全独立的元素。这个过程之所以能够无缝工作是因为按钮被放到工具栏上ToolBar提供了一些内置逻辑可将其子元素的CommandTarget属性动态设置为当前具有焦点的控件从技术角度看ToolBar控件一直在关注着其父元素及窗口并在上下文中查找最近具有焦点的控件即文本框。ToolBar控件有单独的焦点范围focus scope并且在其上下文中按钮时具有焦点的。 如果是在不同容器不是ToolBar或Menu控件中放置按钮就不会获得这项优势。这意味着除非手动设置CommandTarget 属性否则按钮不能工作。为此必须使用命名目标元素的绑定表达式。例如如果文本框被命名为 txt就应该向下面这样定义按钮 Button CommandCut CommandTarget{Binding ElementNametxt} Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/ 另一个较简单的选择是使用附加属性FocusManager.IsFocusScope 创建新的焦点范围。当触发命令时改焦点范围会通知WPF在父元素范围内查找元素 StackPanelStackPanel OrientationHorizontal FocusManager.IsFocusScopeTrueButton CommandCut Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandCopy Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandPaste Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}//StackPanelTextBox TextWrappingWrap AcceptsReturnTrue/TextBox /StackPanel 该方法还有一个附加优点即相同的命令可应用于多个控件不像上面那样对CommandTarget进行硬编码。此外Menu和ToolBar 控件默认将FocusManager.IsFocusScope属性设置为true但如果希望简化命令路由行为不在父元素上下文中查找具有焦点的元素也可以将该属性设为false。 在极少数情况下控件支持内置命令但并不需要这种情况下可以采用三种方式禁用命令 1、理想情况下控件会提供用于关闭命令支持的属性从而确保控件移除这些特性并连贯地调整自身。例如TextBox控件提供了IsUndoEnabled 属性为阻止Undo特性可将该属性设置为false如果IsUndoEnabled属性为trueCtrlZ组合键将触发Undo命令。 2、可为希望禁用的命令添加新的命令绑定。然后该命令绑定可提供新的 CanExecute 事件处理程序并总是响应 false并注意还要设置Handled 标志以阻止文本框自我执行计算而文本框可能将CanExecute 属性设置为true。 3、使用InputBinding集合删除触发命令的输入。 TextBox IsUndoEnabledFalse TextHelloTextBox.CommandBindingsCommandBinding CommandCut CanExecuteCommandBinding_CanExecute//TextBox.CommandBindingsTextBox.InputBindingsKeyBinding CommandNotACommand KeyC ModifiersCtrl//TextBox.InputBindings /TextBox private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e){e.CanExecute false;e.Handled true;} 这样一个文本框将会阻止撤销、剪切以及CtrlC键的复制。 自定义命令 RoutedUICommand 类提供了几个构造函数。虽然可创建没有任何附加信息的RoutedUICommand对象但几乎总是希望提供命令名、命令文本以及所属类型。此外可能希望为InputGestures 集合提供快捷键。 最佳设计是遵循WPF库中的范例并通过静态属性提供自定义命令。 public class CustomCommands {private static RoutedUICommand requery;public static RoutedUICommand Requery { get requery; }static CustomCommands(){InputGestureCollection inputs new InputGestureCollection();inputs.Add(new KeyGesture(Key.R, ModifierKeys.Control, CtrlR));requery new RoutedUICommand(Requery, Requery, typeof(CustomCommands), inputs);} } 一旦定义了命令就可以在命令绑定中使用它就像使用WPF提供的所有预先构建好的命令那样。如果希望在XAML中使用自定义命令注意需要带上名称空间映射。 StackPanelStackPanel.CommandBindingsCommandBinding Commandlocal:DataCommands.Requery ExecutedCommandBinding_Executed//StackPanel.CommandBindingsButton Commandlocal:DataCommands.Requery ContentRequery/ /StackPanel 在不同的位置使用相同的命令 在WPF命令模型中一个重要概念是范围。尽管每个命令仅有一份副本但使用命令的效果却会根据触发命令的位置而异。例如有两个文本框它们都支持Cut、Copy和Paste命令操作只会在当前具有焦点的文本框中发生但是对于需要自己实现的命令——New、Open、Save情况就不同了。问题在于当为这些命令的某个命令触发Executed事件时不知道该事件是属于第一个文本框还是第二个文本框。尽管ExecuteRoutedEventArgs对象提供了Source属性但该属性反映的是具有命令绑定的元素像sender引用而所有命令都被绑定到容器级。 解决这个问题的方法是使用文本框的CommandBindings集合分别为每个文本框绑定命令。这里需要为两个TextBox创建两个相同的CommandBindings实际上只需要一个。可以向两个TextBox添加同一个命令绑定如果使用XAML需要将命令绑定添加到资源中然后在TextBox的CommandBindings集合中使用StaticResource标记扩展并提供键名。 StackPanelStackPanel.ResourcesCommandBinding x:KeysaveCommandBinding CommandSave ExecutedTwoTextBox_SaveCommand_Executed CanExecuteTwoTextBox_SaveCommand_CanExecute//StackPanel.ResourcesToolBarTray ToolBarButton CommandSave Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}//ToolBar/ToolBarTrayTextBox TextWrappingWrap AcceptsReturnTrue TextChangedTwoTextBox_TextChangedTextBox.CommandBindingsStaticResource ResourceKeysaveCommandBinding//TextBox.CommandBindings/TextBoxTextBox TextWrappingWrap AcceptsReturnTrue TextChangedTwoTextBox_TextChangedTextBox.CommandBindingsStaticResource ResourceKeysaveCommandBinding//TextBox.CommandBindings/TextBox /StackPanel 使用命令参数 有些命令需要一些额外信息例如NavigationCommands.Zoom命令需要用于缩放的百分数或者前面说到的两个文本框使用Save命令时需要知道使用的是哪个文件。 解决方法是设置CommandParameter 属性。可直接为 ICommandSource 控件设置该属性。 StackPanelStackPanel.Resourceslocal:FontStringValueConverter x:KeyStringConverterResource//StackPanel.ResourcesTextBox NametxtValue BackgroundAliceBlue Margin55/TextBoxButton Command{x:Static local:DataCommands.Requery} CommandTarget{Binding ElementNametxtBoxTarget}CommandParameter{Binding ElementNametxtValue, PathText, Converter{StaticResource StringConverterResource}} ContentUpdateFontSize/ TextBox NametxtBoxTarget Height100 Margin3TextBox.CommandBindingsCommandBinding Command{x:Static local:DataCommands.Requery} ExecutedFontSizeCommandBinding_Executed//TextBox.CommandBindingsHello/TextBox /StackPanel private void FontSizeCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e){TextBox? source sender as TextBox;if(source ! null){if(e.Parameter ! null){try{if ((int)e.Parameter 0 (int)e.Parameter 60){source.FontSize (int)e.Parameter;}}catch{MessageBox.Show(in Command \n Parameter: e.Parameter);}}}} 跟踪和翻转命令 WPF命令模型缺少的一个特性是翻转命令。尽管提供了ApplicationCommands.Undo命令但该命令通常用于编辑控件如TextBox以维护他们自己的Undo历史。如果希望支持应用程序范围内的Undo特性需要在内部跟踪以前的状态。 遗憾的是扩展WPF命令系统并不容易。相对来说没几个入口点可用于连接自定义逻辑并且对于可用的几个入口点也没有提供说明文档。为创建通用的、可重用的Undo特性需要创建一组全新的“能够撤销的”命令类以及一个特定的命令绑定。本质上必须使用自己创建的新命令系统替换WPF命令系统。 更好的解决方案是设计自己的用于跟踪和翻转命令的系统但使用CommandManager类保存命令历史。 第一个细节是用于跟踪命令历史的类。为构建保存最近命令历史的撤销系统可能需要用到这样的类比如创建派生的ReversibleCommand类提供诸如Unexecute的方法来翻转以前的任务。但该系统不能工作因为所有WPF命令都是唯一的。这意味着在应用程序中每个命令只有一个实例。 为理解该问题假设提供EditingCommands.Backspace 命令而且用户在一行中回退了几个空格。可通过向最近命令堆栈中添加Backspace命令来记录这一操作但实际上每次添加的是相同的命令对象。因此没有简单的方法用于存储命令的其它信息例如刚刚删除的字符。如果希望存储该状态需要构建自己的数据结构。该结构跟踪以下几部分信息 1、命令名称。 2、执行命令的元素。在这里有两个文本框所以可以是其中任意一个 3、在目标元素中被改变了的属性。在这里是TextBox类的Text属性 4、可用于保存受影响元素以前状态的对象。 CommandHistoryItem类还提供了通用的Undo方法该方法使用反射为修改过的属性应用以前的值用于恢复TextBox控件中的文本。但对于更复杂的应用程序需要使用CommandHistoryItem 类的层次结构每个类都可以使用不同方式翻转不同类型的操作。 public class CommandHistoryItem {public string CommandName { get; set; }public UIElement? ElementActedOn { get; set; }public string PropertyActedOn { get; set; }public object? PreviousState { get; set; }public CommandHistoryItem(string commandName): this(commandName, null, , null){}public CommandHistoryItem(string commandName, UIElement? elementActedOn, string propertyActedOn, object? previousState){CommandName commandName;ElementActedOn elementActedOn;PropertyActedOn propertyActedOn;PreviousState previousState;}public bool CanUndo{get { return (ElementActedOn ! null PropertyActedOn ! ); }}public void Undo(){Type? elementType ElementActedOn?.GetType();PropertyInfo? property elementType?.GetProperty(PropertyActedOn);property?.SetValue(ElementActedOn, PreviousState, null);} } 这一设计非常巧妙可以为元素存储状态。如果存储整个窗口状态的快照那么会显著增加内存的使用量。然而如果有大量数据比如文本框有几十行文本Undo操作的负担就很大了。解决方法是限制在历史中存储的项的数量或使用更加智能的方法只存储被改变的数据的信息而不是存储所有数据。 需要的下一个操作要素是执行应用程序范围内Undo操作的命令。ApplicationCommands.Undo命令是不合适的原因是为了达到不同的目的它已经被用于单独的文本框控件翻转最后的编辑变化。相反需要创建一个新命令CustomCommands.ApplicationUndo public class CustomCommands {private static RoutedUICommand requery;public static RoutedUICommand Requery { get requery; }private static RoutedUICommand applicationUndo;public static RoutedUICommand ApplicationUndo { get applicationUndo; }static CustomCommands(){InputGestureCollection inputs new InputGestureCollection();inputs.Add(new KeyGesture(Key.R, ModifierKeys.Control, CtrlR));requery new RoutedUICommand(Requery, Requery, typeof(CustomCommands), inputs);applicationUndo new RoutedUICommand(ApplicationUndo, Application Undo, typeof(CustomCommands));} } 响应特定命令非常简单但当执行任何命令时如何进行响应并记录呢技巧是使用CommandManager类该类提供了几个静态事件: public static readonly RoutedEvent CanExecuteEvent;public static readonly RoutedEvent ExecutedEvent;public static readonly RoutedEvent PreviewCanExecuteEvent;public static readonly RoutedEvent PreviewExecutedEvent; 这里我们主要关注ExecutedEvent 和 PreviewExecutedEvent 事件因为每当执行任何一个命令时都会引发它们。 尽管CommandManager类挂起了Executed事件但仍可使用UIElement.AddHandler()方法关联事件处理程序并未可选的第三个参数传递true值。这样将允许接收事件即使事件已经被处理过也同样如此。然而Executed事件是在命令执行完成之后被触发的这时已经来不及在命令历史中保存被影响的控件的状态了。相反需要响应PreviewExecuted事件该事件在命令执行前一刻被触发。 public partial class MainWindow : Window {public MainWindow(){InitializeComponent();AddCommandBinding();this.AddHandler(CommandManager.PreviewExecutedEvent, new ExecutedRoutedEventHandler(CommandExecuted));}private void NewCommandExecuted(object sender, ExecutedRoutedEventArgs e){MessageBox.Show(New command triggered by e.Source.ToString());if(e.Source ! null){var target e.Source as Control;if (target ! null){if (target.Background Brushes.Blue){target.Background Brushes.Red;}else{target.Background Brushes.Blue;}}}}private void ApplicationUndoCommand_Executed(object sender, ExecutedRoutedEventArgs e){CommandHistoryItem historyItem (CommandHistoryItem)lstHistory.Items[^1];if (historyItem.CanUndo)historyItem.Undo();lstHistory.Items.Remove(historyItem);}private void ApplicationUndoCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e){if (lstHistory null || lstHistory.Items.Count 0)e.CanExecute false;elsee.CanExecute true;} } StackPanelStackPanel.CommandBindingsCommandBinding Commandlocal:CustomCommands.ApplicationUndo ExecutedApplicationUndoCommand_Executed CanExecuteApplicationUndoCommand_CanExecute/CommandBinding/StackPanel.CommandBindingsToolBarTrayToolBarButton CommandApplicationCommands.CutCut/ButtonButton CommandApplicationCommands.CopyCopy/ButtonButton CommandApplicationCommands.PastePaste/ButtonButton CommandApplicationCommands.UndoUndo/Button/ToolBarToolBarButton Commandlocal:CustomCommands.ApplicationUndoReverseLastCommand/Button/ToolBar/ToolBarTrayTextBox Margin5 TextWrappingWrap AcceptsReturnTrue/TextBox Margin5 TextWrappingWrap AcceptsReturnTrue/ListBox Grid.Row3 NamelstHistory Margin5 DisplayMemberPathCommandName/ListBox /StackPanel 要在实际应用程序中使用这一方法还需要进行许多改进。例如需要耗费大量时间改进 CommandManager.PreviewExecutedEvent 事件处理程序以忽略那些明显不需要跟踪的命令诸如使用键盘选择文本的事件、单击空格键引发的命令等。类似地可能希望为那些不是由命令表示的但应当被翻转的操作添加CommandHistoryItem 对象。例如输入一些文本然后导航到其它控件。最后可能希望将Undo历史限制在最近执行的命令范围之内。 测试代码展示 MainWindow.xaml Window x:ClassTestCommand.MainWindowxmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentationxmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:localclr-namespace:TestCommandmc:IgnorabledTitleMainWindow Height450 Width800StackPanel NamestackPanelStackPanel NamestackPanel1StackPanel.CommandBindingsCommandBinding CommandOpen ExecutedOpenCommandExecuted //StackPanel.CommandBindingsMenu FocusManager.IsFocusScopeFalseMenuItem HeaderFileMenuItem CommandNew //MenuItem/MenuButton CommandApplicationCommands.New Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text} /Button ClickcmdDoCommand_ClickDoCommand/Button/StackPanelStackPanelStackPanel.CommandBindingsCommandBinding CommandNew ExecutedNewCommand_Executed/CommandBinding CommandOpen ExecutedOpenCommand_Executed/CommandBinding CommandSave ExecutedSaveCommand_Executed CanExecuteSaveCommand_CanExecute//StackPanel.CommandBindingsMenuMenuItem HeaderFileMenuItem CommandNew/MenuItemMenuItem CommandOpen/MenuItemMenuItem CommandSave/MenuItemMenuItem CommandSaveAs/MenuItemSeparator/SeparatorMenuItem CommandClose/MenuItem/MenuItem/MenuToolBarTray ToolBarButton CommandNew Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandOpen Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandSave Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/ /ToolBarToolBarButton CommandCut Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandCopy Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandPaste Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}//ToolBar/ToolBarTrayTextBox TextWrappingWrap AcceptsReturnTrue TextChangedTextBox_TextChanged/TextBox/StackPanelStackPanelStackPanel OrientationHorizontalButton CommandCut CommandTarget{Binding ElementNametxt} Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandCopy Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandPaste Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}//StackPanelTextBox Nametxt TextWrappingWrap AcceptsReturnTrue/TextBox/StackPanelStackPanelStackPanel OrientationHorizontal FocusManager.IsFocusScopeTrueButton CommandCut Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandCopy Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}/Button CommandPaste Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}//StackPanelTextBox TextWrappingWrap AcceptsReturnTrue/TextBox/StackPanelStackPanel TextBox IsUndoEnabledFalse TextHelloTextBox.CommandBindingsCommandBinding CommandCut CanExecuteCommandBinding_CanExecute//TextBox.CommandBindingsTextBox.InputBindingsKeyBinding CommandNotACommand KeyC ModifiersCtrl//TextBox.InputBindings/TextBox/StackPanelStackPanelStackPanel.CommandBindingsCommandBinding Commandlocal:CustomCommands.Requery ExecutedCommandBinding_Executed//StackPanel.CommandBindingsButton Commandlocal:CustomCommands.Requery ContentRequery//StackPanelStackPanelStackPanel.ResourcesCommandBinding x:KeysaveCommandBinding CommandSave ExecutedTwoTextBox_SaveCommand_Executed CanExecuteTwoTextBox_SaveCommand_CanExecute//StackPanel.ResourcesToolBarTray ToolBarButton CommandSave Content{Binding RelativeSource{RelativeSource ModeSelf}, PathCommand.Text}//ToolBar/ToolBarTrayTextBox TextWrappingWrap AcceptsReturnTrue TextChangedTwoTextBox_TextChangedTextBox.CommandBindingsStaticResource ResourceKeysaveCommandBinding//TextBox.CommandBindings/TextBoxTextBox TextWrappingWrap AcceptsReturnTrue TextChangedTwoTextBox_TextChangedTextBox.CommandBindingsStaticResource ResourceKeysaveCommandBinding//TextBox.CommandBindings/TextBox/StackPanelStackPanelStackPanel.Resourceslocal:FontStringValueConverter x:KeyStringConverterResource//StackPanel.ResourcesTextBox NametxtValue BackgroundAliceBlue Margin55/TextBoxButton Command{x:Static local:CustomCommands.Requery} CommandTarget{Binding ElementNametxtBoxTarget}CommandParameter{Binding ElementNametxtValue, PathText, Converter{StaticResource StringConverterResource}} ContentUpdateFontSize/ TextBox NametxtBoxTarget Height100 Margin3TextBox.CommandBindingsCommandBinding Command{x:Static local:CustomCommands.Requery} ExecutedFontSizeCommandBinding_Executed//TextBox.CommandBindingsHello/TextBox/StackPanelStackPanelStackPanel.CommandBindingsCommandBinding Commandlocal:CustomCommands.ApplicationUndo ExecutedApplicationUndoCommand_Executed CanExecuteApplicationUndoCommand_CanExecute/CommandBinding/StackPanel.CommandBindingsToolBarTrayToolBarButton CommandApplicationCommands.CutCut/ButtonButton CommandApplicationCommands.CopyCopy/ButtonButton CommandApplicationCommands.PastePaste/ButtonButton CommandApplicationCommands.UndoUndo/Button/ToolBarToolBarButton Commandlocal:CustomCommands.ApplicationUndoReverseLastCommand/Button/ToolBar/ToolBarTrayTextBox Margin5 TextWrappingWrap AcceptsReturnTrue/TextBox Margin5 TextWrappingWrap AcceptsReturnTrue/ListBox Grid.Row3 NamelstHistory Margin5 DisplayMemberPathCommandName/ListBox/StackPanel/StackPanel /WindowMainWindow.xaml.cs using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes;namespace TestCommand;[ValueConversion(typeof(string), typeof(int))] public class FontStringValueConverter : IValueConverter {public object Convert(object value, Type targetType, object parameter, CultureInfo culture){string fontSize (string)value;int intFont;try{intFont int.Parse(fontSize);return intFont;}catch{return 0;}}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){return 0;} } public class CustomCommands {private static RoutedUICommand requery;public static RoutedUICommand Requery { get requery; }private static RoutedUICommand applicationUndo;public static RoutedUICommand ApplicationUndo { get applicationUndo; }static CustomCommands(){InputGestureCollection inputs new InputGestureCollection();inputs.Add(new KeyGesture(Key.R, ModifierKeys.Control, CtrlR));requery new RoutedUICommand(Requery, Requery, typeof(CustomCommands), inputs);applicationUndo new RoutedUICommand(ApplicationUndo, Application Undo, typeof(CustomCommands));} }public class CommandHistoryItem {public string CommandName { get; set; }public UIElement? ElementActedOn { get; set; }public string PropertyActedOn { get; set; }public object? PreviousState { get; set; }public CommandHistoryItem(string commandName): this(commandName, null, , null){}public CommandHistoryItem(string commandName, UIElement? elementActedOn, string propertyActedOn, object? previousState){CommandName commandName;ElementActedOn elementActedOn;PropertyActedOn propertyActedOn;PreviousState previousState;}public bool CanUndo{get { return (ElementActedOn ! null PropertyActedOn ! ); }}public void Undo(){Type? elementType ElementActedOn?.GetType();PropertyInfo? property elementType?.GetProperty(PropertyActedOn);property?.SetValue(ElementActedOn, PreviousState, null);} }public partial class MainWindow : Window {public MainWindow(){InitializeComponent();AddCommandBinding();this.AddHandler(CommandManager.PreviewExecutedEvent, new ExecutedRoutedEventHandler(CommandExecuted));}private void AddCommandBinding(){CommandBinding binding new CommandBinding(ApplicationCommands.New);binding.Executed NewCommandExecuted;stackPanel1.CommandBindings.Add(binding);}private void NewCommandExecuted(object sender, ExecutedRoutedEventArgs e){MessageBox.Show(New command triggered by e.Source.ToString());if(e.Source ! null){var target e.Source as Control;if (target ! null){if (target.Background Brushes.Blue){target.Background Brushes.Red;}else{target.Background Brushes.Blue;}}}}private void OpenCommandExecuted(object sender, ExecutedRoutedEventArgs e){MessageBox.Show(Open command triggered by e.Source.ToString());}private void cmdDoCommand_Click(object sender, RoutedEventArgs e){ApplicationCommands.New.Execute(null, null);//stackPanel1.CommandBindings[0].Command.Execute(null);}private bool isDirty false;private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e){MessageBox.Show(New command triggered with e.Source.ToString());isDirty false;}private void OpenCommand_Executed(object sender, ExecutedRoutedEventArgs e){isDirty false;}private void SaveCommand_Executed(object sender, ExecutedRoutedEventArgs e){MessageBox.Show(Save command triggered with e.Source.ToString());isDirty false;}private void SaveCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e){e.CanExecute isDirty;}private void TextBox_TextChanged(object sender, TextChangedEventArgs e){isDirty true;}private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e){e.CanExecute false;e.Handled true;}private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e){MessageBox.Show(Command triggered by e.Source.ToString());}private DictionaryObject, bool isDirtys new DictionaryObject, bool();private void TwoTextBox_TextChanged(object sender, TextChangedEventArgs e){isDirtys[sender] true;}private void TwoTextBox_SaveCommand_Executed(object sender, ExecutedRoutedEventArgs e){string text ((TextBox)sender).Text;MessageBox.Show(About to save: text);isDirtys[sender] false;}private void TwoTextBox_SaveCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e){if (isDirtys.ContainsKey(sender) isDirtys[sender] true){e.CanExecute true;}else{e.CanExecute false;}}private void FontSizeCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e){TextBox? source sender as TextBox;if(source ! null){if(e.Parameter ! null){try{if ((int)e.Parameter 0 (int)e.Parameter 60){source.FontSize (int)e.Parameter;}}catch{MessageBox.Show(in Command \n Parameter: e.Parameter);}}}}private void CommandExecuted(object sender, ExecutedRoutedEventArgs e){// Ignore menu button source.if (e.Source is ICommandSource)return;// Ignore the ApplicationUndo command.if (e.Command CustomCommands.ApplicationUndo)return;// Could filter for commands you want to add to the stack// (for example, not selection events).TextBox? txt e.Source as TextBox;if (txt ! null){RoutedCommand cmd (RoutedCommand)e.Command;CommandHistoryItem historyItem new CommandHistoryItem(cmd.Name, txt, Text, txt.Text);ListBoxItem item new ListBoxItem();item.Content historyItem;lstHistory.Items.Add(historyItem);// CommandManager.InvalidateRequerySuggested();}}private void ApplicationUndoCommand_Executed(object sender, ExecutedRoutedEventArgs e){CommandHistoryItem historyItem (CommandHistoryItem)lstHistory.Items[^1];if (historyItem.CanUndo)historyItem.Undo();lstHistory.Items.Remove(historyItem);}private void ApplicationUndoCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e){if (lstHistory null || lstHistory.Items.Count 0)e.CanExecute false;elsee.CanExecute true;} }
http://www.dnsts.com.cn/news/112422.html

相关文章:

  • 站长工具seo综合查询网四川建设厅官方网站
  • 网站的制作建站人班级网站的规划与建设
  • 网站由哪些部分组成部分组成wordpress怎么让图全屏显示
  • 网站建设需要那些人才网络营销专业好就业吗
  • 网站建设情况的汇报建立网站后怎么维护
  • php网站开发实例电子版建网站相关知识
  • 成都私人做公司网站的哪个网站帮别人做ppt
  • 炫酷网站首页网页设计代码为什么没有颜色
  • 公司做网站需要给百度交钱吗北京网络安全大会
  • 丹东商城网站建设企业门户网站作用
  • 杭州网站制作公司网站邯郸做网站推广多少钱
  • 网站两侧广告代码箱包 东莞网站建设
  • 学校网站建设合同网站 建设 方案
  • 网站的数据库在哪里品牌建设
  • 查看网站国际联网备案号建设一个网站需要什么技术人员
  • 郑州贸网站建设公司wordpress twenty twelve修改
  • 网站设计风格分类永嘉网站建设工作室
  • 乐都网站建设哪家好网站集约化建设讲话稿
  • 静态网页有哪些网站wordpress建立数据库连接时出错
  • 立方米网站泰安房价网二手房出售信息
  • 网站怎么做显得简洁美观wordpress 调用tag标签云
  • 公司网站设计广州创业计划书
  • 网站建设课程设计百度文库800元五合一建站
  • 天津市建设与管理网站网站开发方案目录
  • 福永医院网站建设wordpress主题 笑话
  • 社交网站上的商城怎么做沈阳网站建设开发维护
  • 企业建站一条龙电商中seo是什么意思
  • 西安网站公司企业年报网上申报流程
  • 做信息发布网站要多少钱完整网页开发
  • 网站排名如何上升网页游戏制作需要多少钱