{"id":63,"date":"2011-11-29T20:20:00","date_gmt":"2011-11-29T20:20:00","guid":{"rendered":"http:\/\/tpodolak.com.hostingasp.pl\/blog\/2011\/11\/29\/prism-commandbehaviors\/"},"modified":"2016-01-31T00:32:48","modified_gmt":"2016-01-31T00:32:48","slug":"prism-commandbehaviors","status":"publish","type":"post","link":"https:\/\/tpodolak.com\/blog\/2011\/11\/29\/prism-commandbehaviors\/","title":{"rendered":"Prism &#8211; CommandBehaviors"},"content":{"rendered":"<p>Analizuj\u0105c wcze\u015bniejsze przyk\u0142ady pokazuj\u0105ce u\u017cycie <span style=\"font-style: italic;\">DelegateCommand <\/span> mo\u017cna odnie\u015b\u0107 wra\u017cenie, \u017ce mimo tego i\u017c s\u0105 one bardzo u\u017cyteczne,ich u\u017cycie jest niestety bardzo ograniczone.<br \/>\nJedynie niekt\u00f3re komponenty WPF-a i Silverlight-a maj\u0105 w\u0142a\u015bciwo\u015b\u0107 <span style=\"font-style: italic;\">Command<\/span> do kt\u00f3rej mo\u017cna zbindowa\u0107 nasz obiekt <span style=\"font-style: italic;\">DelegateCommand<\/span>.Ponadto w\u0142a\u015bciwo\u015b\u0107 ta reaguje jedynie na wybrane zahardcodowane w kontrolce zdarzenie (zdarzenie <span style=\"font-style: italic;\">Click<\/span>). Co w przypadku gdyby\u015bmy chcieli zareagowa\u0107 np. na zdarzenie MouseMove za pomoc\u0105 komendy? Nasz problem mo\u017cemy rozwi\u0105za\u0107 poprzez:<\/p>\n<ul>\n<li><span style=\"font-style: italic;\">Interactivity<\/span><\/li>\n<li><span style=\"font-style: italic;\">Interactions<\/span><\/li>\n<li><span style=\"font-style: italic;\">CommandBehaviors<\/span><\/li>\n<\/ul>\n<p>W tym po\u015bcie zostanie przedstawione rozwi\u0105zanie trzecie &#8211; <span style=\"font-style: italic;\">CommandBehaviors<\/span><\/p>\n<p>Pierwsz\u0105 rzecz\u0105 jak\u0105 nale\u017cy zrobi\u0107 w celu stworzenia komendy reaguj\u0105cej na inne zdarzenie ni\u017c <span style=\"font-style: italic;\">Click <\/span>jest stworzenie klasy dziedzicz\u0105cej po <span style=\"font-style: italic;\">CommandBehaviorBase<\/span>. Za\u0142\u00f3\u017cmy, \u017ce zrobimy komend\u0119 reaguj\u0105c\u0105 na zdarzenie <span style=\"font-style: italic;\">MouseMove<\/span><\/p>\n<pre lang=\"csharp\">\r\npublic class MouseMoveCommandBehavior : CommandBehaviorBase<Control>\r\n{\r\n    private MouseOutCommandBehavior(Control control) : base(control)\r\n    {\r\n        control.MouseMove += (sender, args) => \r\n        {\r\n            this.ExecuteCommand();\r\n        };\r\n    }\r\n}\r\n<\/pre>\n<p>Piersza cz\u0119\u015b\u0107 ju\u017c za nami, ale pojawia si\u0119 teraz pytanie jak z tego skorzysta\u0107. \u017beby mie\u0107 mo\u017cliwo\u015b\u0107 u\u017cycia powy\u017cej klasy wykorzytamy <span style=\"font-style: italic;\">attached dependency property<\/span>. Musimy sobie stworzy\u0107 pomocnicz\u0105 statyczn\u0105 klas\u0119, w kt\u00f3rej to zarejestrujemy nasze w\u0142a\u015bciwo\u015bci. Zacznijmy od zarejestrowania dependency property o nazwie <span style=\"font-style: italic;\">Command <\/span>&#8211; do tego obiektu b\u0119dziemy bindowali komendy z ViewModelu (komendy reaguj\u0105ce na zdarzenie <span style=\"font-style: italic;\">MouseMove<\/span>)<\/p>\n<pre lang=\"csharp\">\r\npublic static class MouseMove \r\n{\r\n    public static ICommand GetCommand(DependencyObject obj)\r\n    {\r\n        return (ICommand)obj.GetValue(CommandProperty);\r\n    }\r\n\r\n    public static void SetCommand(DependencyObject obj, ICommand value)\r\n    {\r\n        obj.SetValue(CommandProperty, value);\r\n    }\r\n\r\n    public static readonly DependencyProperty CommandProperty =\r\n            DependencyProperty.RegisterAttached(\"Command\", typeof(ICommand), typeof(MouseMove), new PropertyMetadata(OnSetCustomCommandCallback));\r\n}\r\n<\/pre>\n<p>zauwa\u017cmy, \u017ce pod\u0142\u0105czyli\u015bmy event handlera reaguj\u0105cego na zmian\u0119 naszej nowo stworzonej w\u0142a\u015bciwo\u015bci <span style=\"font-style: italic;\">Command<\/span>. Funkcja <span style=\"font-style: italic;\">OnSetCustomCommandCallback <\/span>wygl\u0105da nast\u0119puj\u0105co:<\/p>\n<pre lang=\"csharp\">\r\nprivate static void OnSetCustomCommandCallback(DependencyObject dep, DependencyPropertyChangedEventArgs e)\r\n{\r\n    var control = dep as Control;\r\n    if (control != null)\r\n    {\r\n        MouseMoveCommandBehavior behavior = GetorCreateMouseMoveBehavior(control);\r\n        behavior.Command = e.NewValue as ICommand;\r\n    }\r\n}\r\n<\/pre>\n<p>Funkcja ta po prostu w razie potrzeby tworzy nowy obiekt typu <span style=\"font-style: italic;\">MouseMoveCommandBehavior <\/span>(gdy kto\u015b zbinduje komende) i dopina go do naszej kontrolki. Pomocnicza funkcja <span style=\"font-style: italic;\">GetorCreateMouseMoveBehavior<\/span> wygl\u0105da tak:<\/p>\n<pre lang=\"csharp\">\r\nprivate static MouseMoveCommandBehavior GetorCreateMouseMoveBehavior(Control listBox)\r\n{\r\n    var behavior = listBox.GetValue(MouseMoveBehaviorProperty) as\r\n        MouseMoveCommandBehavior;\r\n    if (behavior == null)\r\n    {\r\n        behavior = new MouseMoveCommandBehavior(listBox);\r\n        listBox.SetValue(MouseMoveBehaviorProperty, behavior);\r\n    }\r\n    return behavior;\r\n}\r\n<\/pre>\n<p>Obiekt rejestrowany poprzez funkcj\u0119 <span style=\"font-style: italic;\">GetorCreateMouseMoveBehavior <\/span>jest dopinany do kolejnej attached property, kt\u00f3ra r\u00f3wnie\u017c zosta\u0142a zadeklarowana w tym pliku<\/p>\n<pre lang=\"csharp\">\r\npublic static MouseMoveCommandBehavior GetMouseMoveBehavior(DependencyObject obj)\r\n{\r\n    return (MouseMoveCommandBehavior)obj.GetValue(MouseMoveBehaviorProperty);\r\n}\r\n\r\npublic static void SetMouseMoveBehavior(DependencyObject obj, MouseMoveCommandBehavior value)\r\n{\r\n    obj.SetValue(MouseMoveBehaviorProperty, value);\r\n}\r\n\r\npublic static readonly DependencyProperty MouseMoveBehaviorProperty =\r\n    DependencyProperty.RegisterAttached(\"MouseMoveBehavior\", typeof(MouseMoveCommandBehavior), typeof(MouseMove), null );\r\n<\/pre>\n<p>Maj\u0105c zdefiniowane wszystkie powy\u017csze w\u0142a\u015bciwo\u015bci mo\u017cemy ju\u017c wykorzysta\u0107 nasz\u0105 komend\u0119. Jednak\u017ce przyda\u0142oby si\u0119 doda\u0107 jeszcze jedn\u0105 w\u0142a\u015bciwo\u015b\u0107 (opcjonalnie), mianowicie w\u0142a\u015bciwo\u015b\u0107 <span style=\"font-style: italic;\">CommandParameters<\/span><\/p>\n<pre lang=\"csharp\">\r\npublic static object GetCommandParametr(DependencyObject obj)\r\n{\r\n    return (object)obj.GetValue(CommandParametrProperty);\r\n}\r\n\r\npublic static void SetCommandParametr(DependencyObject obj, object value)\r\n{\r\n    obj.SetValue(CommandParametrProperty, value);\r\n}\r\n\r\npublic static readonly DependencyProperty CommandParametrProperty =\r\n    DependencyProperty.RegisterAttached(\"CommandParametr\", typeof(object), typeof(MouseMove), new PropertyMetadata(OnSetCustomCommandParameterCallback));\r\n<\/pre>\n<p>W tym propertisie r\u00f3wnie\u017c reagujemy na przypisnie obiektu.Handler <span style=\"font-style: italic;\">OnSetCustomCommandParameterCallback<\/span> wygl\u0105da nast\u0119puj\u0105co<\/p>\n<pre lang=\"csharp\">\r\nprivate static void OnSetCustomCommandParameterCallback(DependencyObject dep,DependencyPropertyChangedEventArgs e)\r\n{\r\n    var listBox = dep as Control;\r\n    if (listBox != null)\r\n    {\r\n        MouseMoveCommandBehavior behavior = GetorCreateMouseMoveBehavior(listBox); ;\r\n            behavior.CommandParameter = e.NewValue;\r\n    }\r\n}\r\n<\/pre>\n<p>Maj\u0105c ju\u017c zdefiniowane wszystkie niezb\u0119dne w\u0142a\u015bciwo\u015bci mo\u017cemy u\u017cy\u0107 ich w XAML-u. Po pierwsze musimy doda\u0107 alias do namespaca gdzie znajduje si\u0119 nasza statycza klasa <span style=\"font-style: italic;\">MouseMove<\/span>. W moim przypadku wygl\u0105da to nast\u0119puj\u0105co:<\/p>\n<pre lang=\"xml\">\r\nxmlns:AttachedCommands=\"clr-namespace:MainModule.Commands\"\r\n<\/pre>\n<p>Nast\u0119pnie bindujemy jak\u0105\u015b kontrolk\u0119 do naszego attached property <span style=\"font-style: italic;\">Command<\/span>. Wygl\u0105da to w nast\u0119puj\u0105cy spos\u00f3b:<\/p>\n<pre lang=\"xml\">\r\n<Button Name=\"txtButton\" Grid.Column=\"2\" AttachedCommands:MouseMove.Command=\"{Binding SomeCommandFromViewModel}\"><\/Button>\r\n<\/pre>\n<p>Od teraz za ka\u017cdym razem jak najedziemy na <span style=\"font-style: italic;\">txtButton <\/span>wywo\u0142a si\u0119 komenda <span style=\"font-style: italic;\">SomeCommandFromViewModel<\/span>.<br \/>\nPodsumowuj\u0105c trzeba si\u0119 ca\u0142kiem sporo napisa\u0107 \u017ceby zmusi\u0107 do dzia\u0142ania <span style=\"font-style: italic;\">CommandBehaviors <\/span>. W nast\u0119pnym po\u015bcie przedstawi\u0119 dwa sposoby na osi\u0105gni\u0119cie tego samego efektu mniejszym kosztem.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Analizuj\u0105c wcze\u015bniejsze przyk\u0142ady pokazuj\u0105ce u\u017cycie DelegateCommand mo\u017cna odnie\u015b\u0107 wra\u017cenie, \u017ce mimo tego i\u017c s\u0105 one bardzo u\u017cyteczne,ich u\u017cycie jest niestety bardzo ograniczone. Jedynie niekt\u00f3re komponenty WPF-a i Silverlight-a maj\u0105 w\u0142a\u015bciwo\u015b\u0107 Command do kt\u00f3rej mo\u017cna zbindowa\u0107 nasz obiekt DelegateCommand.Ponadto w\u0142a\u015bciwo\u015b\u0107 ta reaguje jedynie na wybrane zahardcodowane w kontrolce zdarzenie (zdarzenie Click). Co w przypadku gdyby\u015bmy chcieli [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[136,134,44,45],"tags":[263,262,190,191],"class_list":["post-63","post","type-post","status-publish","format-standard","hentry","category-commandbehaviors","category-prism","category-silverlight","category-wpf","tag-commandbehaviors","tag-prism","tag-silverlight","tag-wpf"],"_links":{"self":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/63","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/comments?post=63"}],"version-history":[{"count":3,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/63\/revisions"}],"predecessor-version":[{"id":566,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/posts\/63\/revisions\/566"}],"wp:attachment":[{"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/media?parent=63"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/categories?post=63"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tpodolak.com\/blog\/wp-json\/wp\/v2\/tags?post=63"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}