2010-03-11 19 views
1

我是否可以將事件如擊鍵傳遞給另一個控件Silverlight我是否可以將事件如擊鍵傳遞給Silverlight中的另一個控件?

想象一下,我處於一個包含TextboxTreeview的自定義控件中。

我正在收聽TextBoxKey事件。當用戶按下向上箭頭向下箭頭鍵時,我想Treeview的行爲就好像它本身接收到該事件,即它應該向上或向下移動當前選擇。用戶不應該將注意力集中在TextBox上,以便他們可以繼續打字。

這可能嗎?我不想在Treeview上手動設置選擇,因爲它沒有簡單的方法MoveSelectionUp()MoveSelectionDown()方法,所以我將不得不復制那些不那麼微不足道的功能,特別是當樹是數據綁定時並按需加載節點。

回答

1

也許你可以考慮使用Mediator Design Pattern來實現這一目標?

+0

謝謝你的回答。儘管我沒有體系結構問題,但我想知道的是,如果我可以在Silverlight控件中觸發一些我無法訪問的功能,因爲它隱藏在私有方法中。當事件觸發時,它會被執行,所以我的問題是,如果在DependencyObject框架中有一種神奇的方式,可以讓我將一個事件從一個控件轉發到另一個控件。就像'myTextBox.KeyUp + =(sender,e)=> TreeView.KeyUpEvent.Trigger(myTreeView,e)'。 – herzmeister 2010-03-12 15:19:39

0

與此同時,我通過在TreeView上創建了MoveSelectionUp()MoveSelectionDown()擴展方法來解決我的特殊情況。我從Toolkit的控制代碼中的一些私有方法中複製了實現,並在私有或受保護的方法被訪問時做了輕微的修改。感謝工具包中提供的所有擴展方法,現在它不再那麼困難了。

因爲它主要不是我的,所以如果未來的訪問者偶然發現同一問題,我在此提供以下代碼。

但是我仍然打開這個問題,因爲我仍然想以更普通的方式知道事件是否可以在DependencyObject框架中轉發。

TreeViewExtensions

using System; 
using System.Diagnostics.Contracts; 
using System.Linq; 
using System.Windows; 
using System.Windows.Controls; 

static public class TreeViewExtensions 
{ 
    static public void SetSelectedContainerIfValid(this TreeView self, TreeViewItem itm) 
    { 
     Contract.Requires(self != null); 

     if (itm != null) 
     { 
      self.SetSelectedContainer(itm); 
     } 
    } 

    static public void MoveSelectionUp(this TreeView self) 
    { 
     Contract.Requires(self != null); 

     var itm = self.GetSelectedContainer(); 
     if (itm == null) 
     { 
      self.SetSelectedContainerIfValid(self.GetContainers().LastOrDefault()); 
     } 
     else 
     { 
      self.SetSelectedContainerIfValid(itm.GetContainerAbove()); 
     } 
    } 

    static public void MoveSelectionDown(this TreeView self) 
    { 
     Contract.Requires(self != null); 

     var itm = self.GetSelectedContainer(); 
     if (itm == null) 
     { 
      self.SetSelectedContainerIfValid(self.GetContainers().FirstOrDefault()); 
     } 
     else 
     { 
      self.SetSelectedContainerIfValid(itm.GetContainerBelow()); 
     } 
    } 
} 

TreeViewItemExtensions

using System; 
using System.Diagnostics.Contracts; 
using System.Windows; 
using System.Windows.Controls; 

static public class TreeViewItemExtensions 
{ 
    static public TreeViewItem GetContainerBelow(this TreeViewItem self) 
    { 
     return TreeViewItemExtensions.GetContainerBelow(self, true); 
    } 

    /// <summary> 
    /// Find the next focusable TreeViewItem below this item. 
    /// </summary> 
    /// <param name="recurse"> 
    /// A value indicating whether the item should recurse into its child 
    /// items when searching for the next focusable TreeViewItem. 
    /// </param> 
    /// <returns>The next focusable TreeViewItem below this item.</returns> 
    static public TreeViewItem GetContainerBelow(this TreeViewItem self, bool recurse) 
    { 
     Contract.Requires(self != null); 

     // Look for the next item in the children of this item (if allowed) 
     if (recurse && self.IsExpanded && self.HasItems) 
     { 
      TreeViewItem item = self.ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem; 
      if (item != null) 
      { 
       return item.IsEnabled ? 
        item : 
        item.GetContainerBelow(false); 
      } 
     } 

     // Look for the next item in the siblings of this item 
     ItemsControl parent = self.GetParentTreeViewItem() as ItemsControl ?? self.GetParentTreeView(); 
     if (parent != null) 
     { 
      // Get the index of this item relative to its siblings 
      TreeViewItem item = null; 
      int index = parent.ItemContainerGenerator.IndexFromContainer(self); 
      int count = parent.Items.Count; 

      // Check for any siblings below this item 
      while (index++ < count) 
      { 
       item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; 
       if (item != null && item.IsEnabled) 
       { 
        return item; 
       } 
      } 

      // If nothing else was found, try to find the next sibling below 
      // the parent of this item 
      TreeViewItem parentItem = self.GetParentTreeViewItem(); 
      if (parentItem != null) 
      { 
       return parentItem.GetContainerBelow(false); 
      } 
     } 

     return null; 
    } 

    /// <summary> 
    /// Find the last focusable TreeViewItem contained by this item. 
    /// </summary> 
    /// <returns> 
    /// The last focusable TreeViewItem contained by this item. 
    /// </returns> 
    static public TreeViewItem GetLastContainer(this TreeViewItem self) 
    { 
     Contract.Requires(self != null); 

     TreeViewItem item = self; 
     TreeViewItem lastItem = null; 
     int index = -1; 

     // Walk the children of the current item 
     while (item != null) 
     { 
      // Ignore any disabled items 
      if (item.IsEnabled) 
      { 
       // If the item has no children, it must be the last 
       if (!item.IsExpanded || !item.HasItems) 
       { 
        return item; 
       } 

       // If the item has children, mark it as the last known 
       // focusable item so far and walk into its child items, 
       // starting from the last item and moving toward the first 
       lastItem = item; 
       index = item.Items.Count - 1; 
      } 
      else if (index > 0) 
      { 
       // Try searching for the previous item's sibling 
       index--; 
      } 
      else 
      { 
       // Stop searching if we've run out of children 
       break; 
      } 

      // Move to the item's previous sibling 
      item = lastItem.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; 
     } 

     return lastItem; 
    } 

    /// <summary> 
    /// Find the previous focusable TreeViewItem above this item. 
    /// </summary> 
    /// <returns> 
    /// The previous focusable TreeViewItem above this item. 
    /// </returns> 
    static public TreeViewItem GetContainerAbove(this TreeViewItem self) 
    { 
     Contract.Requires(self != null); 

     ItemsControl parent = self.GetParentTreeViewItem() as ItemsControl ?? self.GetParentTreeView(); 
     if (parent == null) 
     { 
      return null; 
     } 

     // Get the index of the current item relative to its siblings 
     int index = parent.ItemContainerGenerator.IndexFromContainer(self); 

     // Walk the previous siblings of the item to find a focusable item 
     while (index-- > 0) 
     { 
      // Get the sibling 
      TreeViewItem item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; 
      if (item != null && item.IsEnabled) 
      { 
       // Get the last focusable descendent of the sibling 
       TreeViewItem last = item.GetLastContainer(); 
       if (last != null) 
       { 
        return last; 
       } 
      } 
     } 

     return parent as TreeViewItem; 
    } 
} 
1

我只能想到兩個辦法 「前進」 關鍵事件:

你的道:註冊鍵事件處理程序和進程事件在你自己的代碼中,並對狀態進行操作目標控制通過properties,methods,extensions(以及任何API由目標控制提供)。 這是有效的,但它基本上是重新實現別人已經寫過的內容 - 在目標控件中 - 並且你總是冒着忘記角落案例的風險。

從目標控制

繼承和你輸入文本框添加到ControlTemplate: 當你的控制實在是相當類似於現有的控制,所以你可以老老實實地說「MyFoo IS_A SomeTargetControl」(然後反正機會,你會想爲進一步定製提供DependencyProperties,它們只是目標控件類中已有內容的副本),則應完全使用繼承。 您的TextBox將不會將ArrowUpArrowDown重要事件設置爲handled,因此繼承的密鑰處理代碼將負責處理它們,並且會正確操縱選擇。

相關問題