2009-11-12 5 views
8

J'ai un ViewModel au-dessus d'un contrôle WPF TreeView. Je veux que ViewModel soit en mesure de définir et lire le SelectedItem à partir de TreeView. Toutefois, la propriété SelectedItem de TreeView n'est pas lisible.TreeView Sync à SelectedItem dans View Model

Je suis en mesure de définir et obtenir l'élément sélectionné dans le code derrière (en utilisant ItemContainerGenerator et TreeViewItem.IsSelected = true), mais cela conduit à une communication laide entre le code derrière et le ViewModel.

Quelqu'un at-il une solution propre pour cela?

+1

Avez-vous déjà résolu cela? J'ai exactement ce problème. – BrettRobi

+3

Je pense que cette question est en double http://stackoverflow.com/questions/1000040/selecteditem-in-a-wpf-treeview –

Répondre

0

Vous pouvez utiliser une sorte de classe proxy pour lier la propriété SelectedItem In propriété et lient la propriété à vos ViewModel:

public class Proxy : FrameworkElement 
    { 
    public static readonly DependencyProperty InProperty; 
    public static readonly DependencyProperty OutProperty; 

    public Proxy() 
    { 
     Visibility = Visibility.Collapsed; 
    } 

    static Proxy() 
    { 
     var inMetadata = new FrameworkPropertyMetadata(
      delegate(DependencyObject p, DependencyPropertyChangedEventArgs args) 
       { 
        if (null != BindingOperations.GetBinding(p, OutProperty)) 
        { 
         var proxy = p as Proxy; 
         if (proxy != null) 
          proxy.Out = args.NewValue; 
        } 
       }); 

     inMetadata.BindsTwoWayByDefault = false; 
     inMetadata.DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 

     InProperty = DependencyProperty.Register("In", 
               typeof (object), 
               typeof (Proxy), 
               inMetadata); 

     var outMetadata = new FrameworkPropertyMetadata(
      delegate(DependencyObject p, DependencyPropertyChangedEventArgs args) 
       { 
        ValueSource source = DependencyPropertyHelper.GetValueSource(p, args.Property); 

        if (source.BaseValueSource != BaseValueSource.Local) 
        { 
         var proxy = p as Proxy; 
         if (proxy != null) 
         { 
          var expected = proxy.In; 
          if (!ReferenceEquals(args.NewValue, expected)) 
          { 
           Dispatcher.CurrentDispatcher.BeginInvoke(
            DispatcherPriority.DataBind, new Action(delegate 
                       { 
                        proxy.Out = proxy.In; 
                       })); 
          } 
         } 
        } 
       }); 

     outMetadata.BindsTwoWayByDefault = true; 
     outMetadata.DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 

     OutProperty = DependencyProperty.Register("Out", 
                typeof (object), 
                typeof (Proxy), 
                outMetadata); 
    } 

    public object In 
    { 
     get { return GetValue(InProperty); } 
     set { SetValue(InProperty, value); } 
    } 

    public object Out 
    { 
     get { return GetValue(OutProperty); } 
     set { SetValue(OutProperty, value); } 
    } 
} 
<Proxy In="{Binding ElementName=Tree, Path=SelectedItem}" Out="{Binding SelectedItem, UpdateSourceTrigger=PropertyChanged}"/> 
<TreeView x:Name="Tree" ItemsSource="{Binding Path=Items}"/> 
1

Je peux donner un exemple. Ce que je fais est de définir la propriété IsSelected d'un TreeViewItem (pas le TreeView lui-même) dans le modèle de vue, car vous pouvez lier à cela.

Dans mon modèle de vue, j'ai une propriété ElementInViewModel qui est une structure de données qui forme un arbre lui-même. J'utilise un HierarchicalDataTemplate dans mon Xaml pour l'afficher. L'objet de données lui-même est de type YourDomainType et ses éléments enfants (du même type) se trouvent dans sa propriété ChildElements. Dans le modèle de vue, j'ai défini la propriété IsExpanded et IsSelected de ma classe YourDomainType. En raison du style défini ci-dessous, ils transmettent ce paramètre au .

Est-ce que cela fonctionne pour vous?

<UserControl> 

    <UserControl.Resources>   
     <CollectionViewSource Source="{Binding Path=ElementInViewModel}" x:Key="Cvs"> 
     </CollectionViewSource> 

     <HierarchicalDataTemplate DataType="{x:Type DomainModel:YourDomainType}" 
            ItemsSource="{Binding Path=ChildElements}"> 
      <TextBlock Text="{Binding Path=Name}"/>    
     </HierarchicalDataTemplate>   

     <Style TargetType="{x:Type TreeViewItem}"> 
      <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> 
      </Setter> 
      <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> 
      </Setter>    
     </Style> 

    </UserControl.Resources> 


    <DockPanel> 
     <TreeView ItemsSource="{Binding Source={StaticResource Cvs}}"/> 
    </DockPanel> 

</UserControl> 
Questions connexes