2012-06-17 19 views
8

मेरे पास एक विंडो के बाईं तरफ एक WPF TreeView के साथ एमवीवीएम एप्लिकेशन है। सही पर एक विवरण पैनल चयनित पेड़ नोड के आधार पर सामग्री को बदलता है।माउस या कुंजी द्वारा चुने जाने पर कैसे पता लगाएं?

यदि उपयोगकर्ता नोड का चयन करता है, तो विवरण पैनल की सामग्री तुरंत बदल जाती है। यह वांछित है यदि उपयोगकर्ता नोड पर क्लिक करता है, लेकिन यदि मैं कुंजी डाउन/अप का उपयोग करके पेड़ पर नेविगेट करता है तो मैं बदलती सामग्री में देरी करना चाहता हूं। (कम से कम विन XP के तहत विंडोज एक्सप्लोरर के समान व्यवहार) मुझे लगता है कि अगर मुझे माउस या कीबोर्ड के माध्यम से नोड चुना गया है तो मुझे अपने व्यू मॉडेल में पता होना चाहिए।

मैं इसे कैसे प्राप्त कर सकता हूं?

अद्यतन:

यह मेरी पहली पोस्ट इसलिए मुझे यकीन है कि अगर यह सही जगह है नहीं कर रहा हूँ, लेकिन मैं समुदाय पता है कि मैं इस बीच में किया जाने चाहते हैं। मेरा अपना समाधान यहाँ है। मैं एक विशेषज्ञ नहीं हूं इसलिए मुझे नहीं पता कि यह एक अच्छा समाधान है या नहीं। लेकिन यह मेरे लिए काम करता है और अगर मैं दूसरों की मदद करता हूं तो मैं खुश रहूंगा। बगफिक्स, सुधार या बेहतर समाधान की अत्यधिक सराहना की जाती है।

मैं HasMouseFocus ...
जुड़ी संपत्ति नीचे बनाया (पहले मैं MouseEnterEvent थे, लेकिन यह अच्छी तरह से काम नहीं करता है उपयोगकर्ता कुंजी ऊपर/नीचे के साथ पेड़ नेविगेट करता है और माउस सूचक किसी भी navigated पेड़ से अधिक बेतरतीब ढंग से है अगर आइटम, क्योंकि उस मामले में विवरण तत्काल अद्यतन हो जाता है।)

public static bool GetHasMouseFocus(TreeViewItem treeViewItem) 
{ 
    return (bool)treeViewItem.GetValue(HasMouseFocusProperty); 
} 

public static void SetHasMouseFocus(TreeViewItem treeViewItem, bool value) 
{ 
    treeViewItem.SetValue(HasMouseFocusProperty, value); 
} 

public static readonly DependencyProperty HasMouseFocusProperty = 
    DependencyProperty.RegisterAttached(
    "HasMouseFocus", 
    typeof(bool), 
    typeof(TreeViewItemProperties), 
    new UIPropertyMetadata(false, OnHasMouseFocusChanged) 
); 

static void OnHasMouseFocusChanged(
    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.MouseDown += OnMouseDown; 
    item.MouseLeave += OnMouseLeave; 
    } 
    else 
    { 
    item.MouseDown -= OnMouseDown; 
    item.MouseLeave -= OnMouseLeave; 
    } 
} 

/// <summary> 
/// Set HasMouseFocusProperty on model of associated element. 
/// </summary> 
/// <param name="sender"></param> 
/// <param name="e"></param> 
static void OnMouseDown(object sender, MouseEventArgs e) 
{ 
    if (sender != e.OriginalSource) 
    return; 

    TreeViewItem item = sender as TreeViewItem; 
    if ((item != null) & (item.HasHeader)) 
    { 
    // get the underlying model of current tree item 
    TreeItemViewModel header = item.Header as TreeItemViewModel; 
    if (header != null) 
    { 
     header.HasMouseFocus = true; 
    } 
    } 
} 

/// <summary> 
/// Clear HasMouseFocusProperty on model of associated element. 
/// </summary> 
/// <param name="sender"></param> 
/// <param name="e"></param> 
static void OnMouseLeave(object sender, MouseEventArgs e) 
{ 
    if (sender != e.OriginalSource) 
    return; 

    TreeViewItem item = sender as TreeViewItem; 
    if ((item != null) & (item.HasHeader)) 
    { 
    // get the underlying model of current tree item 
    TreeItemViewModel header = item.Header as TreeItemViewModel; 
    if (header != null) 
    { 
     header.HasMouseFocus = false; 
    } 
    } 
} 

... और TreeView.ItemContainerStyle

<TreeView.ItemContainerStyle> 
     <Style TargetType="{x:Type TreeViewItem}" > 
     <!-- These Setters binds some properties of a TreeViewItem to the TreeViewItemViewModel. --> 
     <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
     <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
     <Setter Property="ToolTip" Value="{Binding Path=CognosBaseClass.ToolTip}"/> 
     <!-- These Setters applies attached behaviors to all TreeViewItems. --> 
     <Setter Property="properties:TreeViewItemProperties.PreviewMouseRightButtonDown" Value="True" /> 
     <Setter Property="properties:TreeViewItemProperties.BringIntoViewWhenSelected" Value="True" /> 
     <Setter Property="properties:TreeViewItemProperties.HasMouseFocus" Value="True" /> 
     </Style> 
    </TreeView.ItemContainerStyle> 
पर लागू कर

जहां गुण मेरी संलग्न संपत्ति का मार्ग है।

xmlns:properties="clr-namespace:WPF.MVVM.AttachedProperties;assembly=WPF.MVVM" 
मेरी ViewModel में

तो फिर, अगर HasMousefocusProperty सच है, मैं उसके विवरण फलक (GridView) तुरंत अपडेट। यदि झूठी है तो मैं बस एक डिस्पैचर टाइमर शुरू करता हूं और वर्तमान में चयनित आइटम को टैग के रूप में लागू करता हूं। 500ms के अंतराल के बाद टिक-इवेंट विवरण लागू करता है, लेकिन केवल तभी चयनित आइटम टैग के समान ही होता है।

/// <summary> 
/// This property is beeing set when the selected item of the tree has changed. 
/// </summary> 
public TreeItemViewModel SelectedTreeItem 
{ 
    get { return Property(() => SelectedTreeItem); } 
    set 
    { 
    Property(() => SelectedTreeItem, value); 
    if (this.SelectedTreeItem.HasMouseFocus) 
    { 
     // show details for selected node immediately 
     ShowGridItems(value); 
    } 
    else 
    { 
     // delay showing details 
     this._selctedNodeChangedTimer.Stop(); 
     this._selctedNodeChangedTimer.Tag = value; 
     this._selctedNodeChangedTimer.Start(); 
    } 
    } 
} 
+0

निम्न एसओ प्रश्न में शीर्ष दो उत्तरों कीबाइंडिंग समस्या के साथ सौदा: http://stackoverflow.com/a/7086853/1416258 और http://stackoverflow.com/a/918062/1416258 जहां तक ​​आपका व्यक्तिगत स्थिति, या तो चारों ओर खेलते हैं या किसी के लिए आपको मछली देने का इंतजार करते हैं। –

+0

बहुत धन्यवाद @ जीओइस्ट। जैसे ही उपयोगकर्ता निर्दिष्ट कुंजी दबाता है, मैं एक कैमैंड बाइंडिंग का उपयोग करके अपने व्यू मॉडेल में एक झंडा सेट कर सकता हूं। लेकिन मुझे इस ध्वज को फिर से साफ़ करना होगा जब (या पहले) तो उपयोगकर्ता एक और पेड़ नोड का चयन करता है। कोई विचार? – AelanY

+0

@ एलेनवाई हाँ, आप सही हैं कि आपको इस ध्वज को रीसेट करने की देखभाल करनी होगी, सबसे अच्छी जगह यह तर्क हो सकता है कि आप अपने विवरण पैनल को रीफ्रेश शुरू कर रहे हैं। – akjoshi

उत्तर

2

आप अपने ViewModel में एक ध्वज अपने TreeView (या उपयोगकर्ता नियंत्रण यह वाले) के लिए OnPreviewKeyDown संभाल कर सकते हैं और प्रोग्राम के रूप में स्थापना की और इस बात पर विचार करते हुए ताज़ा विवरण फलक -

protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e) 
{ 
    switch(e.Key) 
    { 
     case Key.Up: 
     case Key.Down: 
      MyViewModel.IsUserNavigating = true; 
      break; 
    } 
} 

ऐसा ही एक approch और अन्य समाधान इस तो सवाल में उल्लेख कर रहे -

How can I programmatically navigate (not select, but navigate) a WPF TreeView?

अद्यतन: [एलानवाई की टिप्पणी के जवाब में]

मुझे नहीं लगता कि दृश्यों में कुछ कोड-पीछे होने में कोई समस्या है, जो एमवीवीएम को तोड़ नहीं देता है।

लेख, WPF Apps With The Model-View-ViewModel Design Pattern में, लेखक जो जोश स्मिथ है कहते हैं:

एक अच्छी तरह से डिजाइन MVVM वास्तुकला में, सबसे दृश्य के लिए codebehind खाली होना चाहिए, या, अधिक से अधिक, केवल कोड होता है जो उस दृश्य में निहित नियंत्रण और संसाधनों का उपयोग करता है। कभी कभी यह इस तरह की घटना hooking या एक विधि कि अन्यथा ViewModel से ही लागू करने की काफी मुश्किल होगा बुला के रूप में एक दृश्य के codebehind में कोड है कि एक ViewModel वस्तु के साथ सूचना का आदान प्रदान , लिखने के भी जरूरी है।

मेरे अनुभव में यह किसी भी कोड-पीछे बिना (काफी आकार के) आवेदन एक उद्यम के निर्माण के लिए असंभव है, तो आप TreeView, डेटा ग्रिड या 3'rd पक्ष नियंत्रण की तरह जटिल नियंत्रण का उपयोग करने के लिए है खास तौर पर जब।

+0

आपके उत्तर @akjoshi के लिए धन्यवाद, लेकिन मैं एमवीवीएम पैटर्न का उपयोग कर रहा हूं और मैं पीछे कोई कोड नहीं चाहता हूं। – AelanY

+0

धन्यवाद फिर से @ कोजोशी, मैंने जोश स्मिथ के इस महान लेख को पहले ही पढ़ लिया है और निश्चित रूप से आप सही हैं। मेरे समाधान के बारे में आप क्या सोचते हैं? कृपया ऊपर मेरा अपडेट देखें ... – AelanY

+0

@AelanY आपका समाधान अच्छा दिखता है क्योंकि इसे एक्सएएमएल में एक वृक्षदृश्य से जोड़ा जा सकता है और इसमें पुन: प्रयोज्यता के तत्व हैं; इसके अलावा यह इवेंट हैंडलर का उपयोग करने और व्यूमोडेल ध्वज को अद्यतन करने के समान ही है। – akjoshi

संबंधित मुद्दे