主頁 > .NET開發 > 【翻譯】WPF 中附加行為的介紹 Introduction to Attached Behaviors in WPF

【翻譯】WPF 中附加行為的介紹 Introduction to Attached Behaviors in WPF

2021-04-03 06:07:23 .NET開發

【翻譯】WPF 中附加行為的介紹 Introduction to Attached Behaviors in WPF

目錄  隱藏  引言 [Introduction] 背景 [Background] 附加行為 [Attached Behaviors] 論證 [Demonstration] 結論 [Conclusion] 參考 [References] 版本歷史 [Revision History] 許可證 [License]

作者:Josh Smith 2008.08.30

翻譯:獨立觀察員 2021.03.17

原文地址:https://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF

 

Explains the concept of attached behaviors and shows how to use them in the context of the MVVM pattern.

 

 

解釋附加行為的概念并展示如何在 MVVM 模式背景關系中使用它們,

 

[Demo 下載] Download demo project (requires Visual Studio 2008) - 21.3 KB

AttachedBehavior.jpg

 

 

引言 [Introduction]

This article explains what an attached behavior is, and how you can implement them in a WPF application. Readers of this article should be somewhat familiar with WPF, XAML, attached properties, and the Model-View-ViewModel (MVVM) pattern. I highly recommend that you also read my ‘Simplifying the WPF TreeView by Using the ViewModel Pattern’ article, because the material here is an extension of the material presented in it.

 

本文解釋了什么是附加行為,以及您如何在 WPF 應用程式中實作它們,本文的讀者需要稍微熟悉 WPF、XAML、附加屬性、以及 MVVM 模式,我強烈建議您也閱讀下我的文章《Simplifying the WPF TreeView by Using the ViewModel Pattern(通過使用 MVVM 模式來簡化 WPF 的 TreeView)》,因為這里的素材就是對其中提及的素材的一個拓展,

 

背景 [Background]

Back in May of 2008, I published an article called ‘Simplifying the WPF TreeView by Using the ViewModel Pattern’. That article focused on the MVVM pattern. This morning, I woke up to find that a fellow by the name of Pascal Binggeli had asked an excellent question on that article’s message board.

 

回想 2008 年 5 月,我發布了一篇文章叫作《Simplifying the WPF TreeView by Using the ViewModel Pattern(通過使用 MVVM 模式來簡化 WPF 的 TreeView)》的,那篇文章關注的是 MVVM 模式,今天早上,我醒來時發現一個叫 Pascal Binggeli 的家伙在那篇文章的留言板問了 一個極好的問題 ,

 

Pascal wanted to know how to scroll a TreeViewItem into the viewable area of the TreeView control when its associated ViewModel object selects it. That seems simple enough, but upon further examination, it is not quite as straightforward as one might initially expect. The objective, and problem, is to find the proper place to put code that calls BringIntoView() on the selected TreeViewItem, such that the principles of the MVVM pattern are not violated.

 

Pascal 想知道怎樣讓一個 TreeViewItem 在與它關聯的 ViewModel 物件中選中它時將它滾動到 TreeView 的可視區,這似乎足夠簡單,但在進一步檢查之后,它似乎不像最初的期望那么簡單,目標和問題是找到合適的地方放置代碼來對選中的 TreeViewItem  呼叫 BringIntoView() ,同時不違反 MVVM 模式的理念,

 

For example, suppose that the user searches through a TreeView for an item whose display text matches a user-defined search string. When the search logic finds a matching item, the matching ViewModel object will have its IsSelected property set to true. Then, via the magic of data binding, the TreeViewItem associated with that ViewModel object enters into the selected state (i.e., its IsSelected property is set to true, too). However, that TreeViewItem will not necessarily be in view, which means the user will not see the item that matches their search string. Pascal wanted a TreeViewItem brought into view when the ViewModel determines that it is in the selected state.

 

例如,假設用戶從一個 TreeView 中搜索顯示文本匹配用戶自定義搜索字符的一項,當搜索邏輯找到一個匹配項,ViewModel 中的匹配物件會將其 IsSelected 屬性設定為 true ,然后,通過神奇的資料系結,和這個 ViewModel 中的物件關聯的 TreeViewItem 進入被選中的狀態(比如,它的 IsSelected 屬性也被設為 true ),然而,這個 TreeViewItem 不一定在視野中,這意味著用戶將看不到匹配他搜索字串的項,Pascal 想要 TreeViewItem 在 ViewModel 設定它為被選中狀態時被帶到視野中,

 

The ViewModel objects have no idea that a TreeViewItem exists, and is bound to them, so it does not make sense to expect the ViewModel objects to bring TreeViewItems into view. The question becomes, now, who is responsible for bringing a TreeViewItem into view when the ViewModel forces it to be selected?

 

ViewModel 物件不知道 TreeViewItem 的存在,也不能約束他們,所以期望 ViewModel 物件把 TreeViewItem 帶到視野中是沒有意義的,現在問題就變成了,當 ViewModel 設定一個 TreeViewItem 為被選中時誰負責將其帶到視野中,

 

We certainly do not want to put that code into the ViewModel because it introduces an artificial, and unnecessary, coupling between a ViewModel object and a visual element. We do not want to put that code in the code-behind of every place a TreeView is bound to a ViewModel, because it reintroduces some of the problems that we avoid by using a ViewModel in the first place. We could create a TreeViewItem subclass that has built-in support for bringing itself into view when selected, but, in the WPF world, that is definitely a heavy-handed solution to a lightweight problem.

 

我們當然不想將代碼放到 ViewModel 里,因為這將在 ViewModel 物件和視覺元素之間引入人工的不必要的耦合,我們也不想把代碼放在每個放置了受 ViewModel 約束的 TreeView 的后置代碼中,因為這將重新引入一些我們起初通過使用 ViewModel 避免了的問題,我們可以創建一個 TreeViewItem 子類,該類擁有當被選中時將自己帶到視野中的內建支持,但是,在 WPF 的世界中,這肯定就是殺雞用牛刀了,

 

How can we elegantly solve this problem in a lightweight and reusable way?

 

我們怎樣通過一個輕量的、可復用的方式優雅地解決這個問題呢?

 

附加行為 [Attached Behaviors]

The solution to the problem explained above is to use an attached behavior. Attaching a behavior to an object simply means making the object do something that it would not do on its own. Here is the explanation of attached behaviors that I wrote in my ‘Working with CheckBoxes in the WPF TreeView’ article:

The idea is that you set an attached property on an element so that you can gain access to the element from the class that exposes the attached property. Once that class has access to the element, it can hook events on it and, in response to those events firing, make the element do things that it normally would not do. It is a very convenient alternative to creating and using subclasses, and is very XAML-friendly.

 

上面闡述的問題的解決方案就是使用 附加行為,附加行為到一個物件簡單來說就是讓一個物件做一些它之前自己不會做的事情,我把對附加行為的解釋寫在了我的文章《Working with CheckBoxes in the WPF TreeView(在 WPF 的 TreeView 中使用 CheckBoxes)》中:

這個點子就是,你在一個元素上設定一個附加屬性,那么你就可以從暴露這個附加屬性的類中獲得該元素的訪問,一旦那個類有權限訪問那個元素,它就能在其上掛鉤事件,回應這些事件的觸發,使該元素做出它通常不會做的事情,創建和使用子類是個非常方便的選擇,并且對 XAML 是非常友好的,

 

In that article, the demo application uses attached behaviors in complicated ways, but in this article, we will keep it simple. Enough with the background and theory, let’s see how to create an attached behavior that solves the problem posed by our friend Pascal.

 

在那篇文章中,Demo 程式以一種復雜的方式使用附加行為,但在這篇文章中,我們會讓其簡單,背景和理論足夠了,讓我們看看怎樣創建一個附加行為來解決我們的朋友 Pascal 發布的問題吧,

 

論證 [Demonstration]

 

This article’s demo app, which is available for download at the top of this page, uses the Text Search demo provided by the ‘Simplifying the WPF TreeView by Using the ViewModel Pattern’ article. I made a few changes, such as adding more items to the TreeView, increasing the font size, and adding an attached behavior. The attached behavior is in a new static class called TreeViewItemBehavior. That class exposes a Boolean attached property that can be set on a TreeViewItem, called IsBroughtIntoViewWhenSelected. Here is the TreeViewItemBehavior class:

 

這篇文章的 Demo 程式(在本頁頂部可供下載)使用了文章《Simplifying the WPF TreeView by Using the ViewModel Pattern》中提供的 “Text Search” 示例程式,我做了些修改,例如,往 TreeView 中添加了更多的項,增大了字體大小,添加了附加行為,附加行為在一個叫做 TreeViewItemBehavior 的新的靜態類中,這個類暴露了一個可以被設定到 TreeViewItem 的 Boolean 型別的附加屬性,叫作 IsBroughtIntoViewWhenSelected  ,這就是 TreeViewItemBehavior 類:

/// <summary>
/// Exposes attached behaviors that can be applied to TreeViewItem objects.
/// 暴露可被應用到 TreeViewItem 物件的附加行為,
/// </summary>
public static class TreeViewItemBehavior
{
    #region IsBroughtIntoViewWhenSelected

    public static bool GetIsBroughtIntoViewWhenSelected(TreeViewItem treeViewItem)
    {
        return (bool)treeViewItem.GetValue(IsBroughtIntoViewWhenSelectedProperty);
    }

    public static void SetIsBroughtIntoViewWhenSelected(TreeViewItem treeViewItem, bool value)
    {
        treeViewItem.SetValue(IsBroughtIntoViewWhenSelectedProperty, value);
    }

    public static readonly DependencyProperty IsBroughtIntoViewWhenSelectedProperty =
        DependencyProperty.RegisterAttached(
        "IsBroughtIntoViewWhenSelected",
        typeof(bool),
        typeof(TreeViewItemBehavior),
        new UIPropertyMetadata(false, OnIsBroughtIntoViewWhenSelectedChanged));

    static void OnIsBroughtIntoViewWhenSelectedChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        TreeViewItem item = depObj as TreeViewItem;
        if (item == null)
            return;

        if (e.NewValue is bool == false)
            return;

        if ((bool)e.NewValue)
            item.Selected += OnTreeViewItemSelected;
        else
            item.Selected -= OnTreeViewItemSelected;
    }

    static void OnTreeViewItemSelected(object sender, RoutedEventArgs e)
    {
        // Only react to the Selected event raised by the TreeViewItem whose IsSelected property was modified. 
        // Ignore all ancestors who are merely reporting that a descendant's Selected fired.
        // 只對 IsSelected 屬性被修改的 TreeViewItem 觸發的 Selected 事件作出反應,
        // 忽略所有只是報告子孫的 Selected 被觸發的祖先,
        if (!Object.ReferenceEquals(sender, e.OriginalSource))
            return;

        TreeViewItem item = e.OriginalSource as TreeViewItem;
        if (item != null)
            item.BringIntoView();
    }

    #endregion // IsBroughtIntoViewWhenSelected
}

 

The attached behavior seen above is basically just a fancy way of hooking the Selected property of a TreeViewItem and, when the event is raised, calling BringIntoView() on the item. The final piece of this puzzle is seeing how the TreeViewItemBehavior class gets a reference to every TreeViewItem in the TreeView. We accomplish that by adding a Setter to the Style applied to every item in the TreeView, as seen below:

 

上述附加行為從根本上來說只是一種掛鉤 TreeViewItem 的  Selected 屬性的一種有趣的方式,當事件被觸發,就在該項上呼叫 BringIntoView() ,這個披薩的最后一塊就是看看 TreeViewItemBehavior 類如何獲得 TreeView 中的每個 TreeViewItem ,我們通過給應用到 TreeView 中的每一項的 Style 添加一個 Setter 來達成,如下所示:

 <TreeView.ItemContainerStyle>
  <Style TargetType="{x:Type TreeViewItem}">
    <!-- This Setter applies an attached behavior to all TreeViewItems. -->
    <!-- 這個 Setter 給所有 TreeViewItems 應用附加行為 -->
    <Setter Property="local:TreeViewItemBehavior.IsBroughtIntoViewWhenSelected" Value=https://www.cnblogs.com/weiliuhong/p/"True"/>

    <!-- These Setters bind a TreeViewItem to a PersonViewModel. -->
    <Setter Property="IsExpanded" Value=https://www.cnblogs.com/weiliuhong/p/"{Binding IsExpanded, Mode=TwoWay}" />
    <Setter Property="IsSelected" Value=https://www.cnblogs.com/weiliuhong/p/"{Binding IsSelected, Mode=TwoWay}" />
    <Setter Property="FontWeight" Value=https://www.cnblogs.com/weiliuhong/p/"Normal" />
    <Style.Triggers>
      <Trigger Property="IsSelected" Value=https://www.cnblogs.com/weiliuhong/p/"True">
        <Setter Property="FontWeight" Value=https://www.cnblogs.com/weiliuhong/p/"Bold" />
      </Trigger>
    </Style.Triggers>
  </Style>
</TreeView.ItemContainerStyle>

 

When the demo application loads up, the search text will be set to the letter Y automatically. Click the Find button a few times, and you will see that each time an item is selected, it will contain the letter Y and will scroll into view. The fact that it scrolls into view upon being selected means that the attached behavior is working properly.

 

當示例程式載入后,搜索文本會被自動設定為字母 Y,點擊 Find 按鈕幾次,你會看到每次選中了一項,它包含了字母 Y 并且會滾動到視野中,一旦被選中就會滾動到視野中這個事實意味著附加行為作業正常,

 

結論 [Conclusion]

Hooking an event on an object and doing something when it fires is certainly not a breakthrough innovation, by any stretch of the imagination. In that sense, attached behaviors are just another way to do the same old thing. However, the importance of this technique is that it has a name, which is probably the most important aspect of any design pattern. In addition, you can create attached behaviors and apply them to any element without having to modify any other part of the system. It is a clean solution to the problem raised by Pascal Binggeli, and many, many other problems. It\'s a very useful tool to have in your toolbox.

 

無論你怎么想,在物件上掛鉤事件并且在觸發時做些事情當然不是一個突破性的創新,從這個層面來說,附加行為只是做相同舊事的另一種方式,然而,這個技術的重要之處就是它有個名稱,這可能是任何設計模式的重要層面,而且,你可以創建附加行為并將它們應用到任何元素而無需修改系統的任何部分,它是對 Pascal Binggeli 提出的問題以及其它很多很多問題的一個清爽的解決方案,是您工具箱中非常有用的工具,

 

參考 [References]

  • The Attached Behavior Pattern – John Gossman
  • Simplifying the WPF TreeView by Using the ViewModel Pattern – Josh Smith
  • Working with CheckBoxes in the WPF TreeView - Josh Smith

 

版本歷史 [Revision History]

  • August 30, 2008 – Created the article.
 

許可證 [License]

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

 

這篇文章,包括任何附帶的原始碼和檔案,在 The Code Project Open License (CPOL) 下被許可,

 

[dlgcy] 原始碼下載:https://download.csdn.net/download/w19921004/15873706  [dlgcy] 效果演示(動圖):

【翻譯】WPF 中附加行為的介紹 Introduction to Attached Behaviors in WPF插圖1

 

 

原創文章,轉載請注明: 轉載自 獨立觀察員?博客

本文鏈接地址: 【翻譯】WPF 中附加行為的介紹 Introduction to Attached Behaviors in WPF [http://dlgcy.com/introduction-to-attached-behaviors-in-wpf/]

微信訂閱號

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/271807.html

標籤:WPF

上一篇:WPF教程三:學習Data Binding把思想由事件驅動轉變為資料驅動

下一篇:WPF原始碼閱讀 -- InkCanvas選擇模式

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more