2014-04-26 1 views
6

소리가 충분히 간단합니까? TreeView 있고 노드 중 하나가 확장 될 때 뭔가를 싶습니다. MVVM을 사용하고 있는데, '뭔가'는 ViewModel의 명령입니다.TreeViewItem이 확장 될 때 호출 명령

글쎄, 나는 결국 그렇게 간단하지 않다는 것을 알게되었다. 나는 주변을 둘러 보았고 몇 가지 것을 시도했다. (아무것도 불을 작동하지 않습니다 (thisthis 기준)

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="TreeViewItem.Expanded"> 
     <cmd:EventToCommand Command="{Binding Path=FolderNodeToggledCommand}" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

이 코드; 명령이 뷰 모델에 바인딩되지만 노드가있을 때 대응하는 방법은 발사되지 않습니다 예를 들어, MVVM 빛의 EventToCommand를 사용하여 퍼지는). 또한 cmd:EventToCommandi:InvokeCommandAction으로 바꾸려고했지만 그 결과는 같습니다. 두 번째 링크의 '솔루션'은 분명히 잔인한 것이므로 ToggleButton이있는 WPF TreeView WinForms Style을 사용하고자하므로 ToggleButton을 변경하고 싶지 않습니다. 두 번째 링크의 보조 응답은 존재하지 않는 TreeView에서 이벤트를 사용하려고 시도했을 수도 있음을 나타냅니다.

또 다른 possible solution은 TreeViewItem의 IsExpanded 속성을 바인딩 할 수 있습니다. 그러나 내가 묶는 개체를 깨끗한 DTOs으로 유지하고 바인딩되는 개체가 아니라 ViewModel에서 작업을 수행하고 싶습니다.

그래서 TreeViewItem이 확장 될 때 ViewModel에서 명령을 호출하는 데 어떤 것이 필요합니까?

+0

예, 꼭 답을 보내주십시오. 나는 프리즘을 사용하지 않았지만 그것이 효과를 낼 수 있는지를 보게 될 것이다. – Gigi

+0

좋아, 내가 단계별로 제공하는 답변을 게시하고, 우리는 그것이 어떤 용도로 사용되는지 볼 수 있습니다. –

+0

참고 : 명령이 동작에 바인딩되어 있으므로 ' –

답변

7

이 기능을 사용하려면 첨부 된 동작을 사용할 수 있으며 깨끗한 MVVM 전략임을 알 수 있습니다.

WPF 응용 프로그램을 작성하고이 XAML을 추가 ...

<Grid> 
    <TreeView> 
     <TreeView.Resources> 
      <Style TargetType="TreeViewItem"> 
       <Setter Property="bindTreeViewExpand:Behaviours.ExpandingBehaviour" Value="{Binding ExpandingCommand}"/> 
      </Style> 
     </TreeView.Resources> 
     <TreeViewItem Header="this" > 
      <TreeViewItem Header="1"/> 
      <TreeViewItem Header="2"><TreeViewItem Header="Nested"></TreeViewItem></TreeViewItem> 
      <TreeViewItem Header="2"/> 
      <TreeViewItem Header="2"/> 
      <TreeViewItem Header="2"/> 
     </TreeViewItem> 
     <TreeViewItem Header="that" > 
      <TreeViewItem Header="1"/> 
      <TreeViewItem Header="2"/> 
      <TreeViewItem Header="2"/> 
      <TreeViewItem Header="2"/> 
      <TreeViewItem Header="2"/> 
     </TreeViewItem>   
    </TreeView> 
</Grid> 

는 다음과 같은보기 모델을 만들 ...
public class ViewModel : INotifyPropertyChanged 
{ 
    public ICommand ExpandingCommand { get; set; } 
    public ViewModel() 
    { 
     ExpandingCommand = new RelayCommand(ExecuteExpandingCommand, CanExecuteExpandingCommand); 
    } 
    private void ExecuteExpandingCommand(object obj) 
    { 
     Console.WriteLine(@"Expanded"); 
    } 
    private bool CanExecuteExpandingCommand(object obj) 
    { 
     return true; 
    } 
    #region INotifyPropertyChanged Implementation 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected virtual void OnPropertyChanged(string name) 
    { 
     var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null); 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 
    #endregion 
} 

내가 릴레이 명령 사용하지만, 당신은을 사용할 수 있습니다 대리 명령 교환. 릴레이 명령의 소스는 ... http://msdn.microsoft.com/en-us/magazine/dd419663.aspx에서

은 다음과 같습니다 별도의 클래스 ...

public static class Behaviours 
{ 
    #region ExpandingBehaviour (Attached DependencyProperty) 
    public static readonly DependencyProperty ExpandingBehaviourProperty = 
     DependencyProperty.RegisterAttached("ExpandingBehaviour", typeof(ICommand), typeof(Behaviours), 
      new PropertyMetadata(OnExpandingBehaviourChanged)); 
    public static void SetExpandingBehaviour(DependencyObject o, ICommand value) 
    { 
     o.SetValue(ExpandingBehaviourProperty, value); 
    } 
    public static ICommand GetExpandingBehaviour(DependencyObject o) 
    { 
     return (ICommand) o.GetValue(ExpandingBehaviourProperty); 
    } 
    private static void OnExpandingBehaviourChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     TreeViewItem tvi = d as TreeViewItem; 
     if (tvi != null) 
     { 
      ICommand ic = e.NewValue as ICommand; 
      if (ic != null) 
      { 
       tvi.Expanded += (s, a) => 
       { 
        if (ic.CanExecute(a)) 
        { 
         ic.Execute(a); 

        } 
        a.Handled = true; 
       }; 
      } 
     } 
    } 
    #endregion 
} 

이 그런 다음 XAML에이 클래스의 이름 공간을 가져올를 만드는 것입니다

xmlns : bindTreeViewExpand = "clr-namespace : BindTreeViewExpand"(이름 공간이 달라집니다!)

Resharper가 이것을 수행하거나 intellesense 프롬프트를 표시합니다.

마지막으로보기 모델을 연결합니다. 이름 공간이 해결 및 배선이 올바른지 후

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = new ViewModel(); 
    } 

그런 다음,이 작업을 시작합니다 ...이처럼 신속하고 더러운 방법을 사용합니다. Execute 메서드에서 디버거를 앵커 및 RoutedEvent 인수를 관찰하십시오. 이 트리를 파싱하여 어떤 트리 뷰 항목이 확장되었는지 확인할 수 있습니다.

이 솔루션의 핵심은 STYLE! 그래서 그것은 각각의 모든 TreeViewItem에 적용됩니다. 둘 중 하나 뒤에 코드가 없습니다 (동작 이외).

위에 나열된 동작은 이벤트를 처리 된 것으로 표시합니다. 이후의 행동에 따라 변경하고 싶을 수도 있습니다.

+1

나는 그것을 시도하고 꽤 잘 작동합니다. 틀림없이 너무 단순해야만하는 뭔가에 대해서는 상당한 노력을 기울이지 만 실제로 잘 수행됩니다. – Gigi

+0

그냥 getter를 인라인하지 말아라. –

+1

괜찮아! 이 솔루션 – peter70