2016-02-12 3 views
3

Я выяснил способ динамического связывания элементов управления внутри древовидного представления с помощью ReactiveUI.Как использовать ReactiveUI с иерархическим источником данных (вид дерева)

Но ... Верхний уровень связывания с HierachicalDataSource находится в XAML не код позади, и мне нужно установить ItemsSource напрямую, а не использовать this.OneWayBind в общей схеме для связывания ReactiveUI.

Итак, мой вопрос: ли я что-то пропустил в рамках ReactiveUI, которая позволит мне связать с this.OneWayBind и переместить HierachicalDataTemplete в код позади или пользовательского элемента управления пользователя?

В частности Есть ли еще одна перегрузка OneWayBind, поддерживающая иерархические шаблоны данных, или способ подавления генерации шаблона данных для вызова при его использовании?

Update Я добавил выбранный элемент и programatic поддержку Расширить и Selected в мой тестовый проект, но я должен был добавить стиль в XAML. Я бы хотел заменить это простым RxUI Bind. Обновлены примеры.

Вот ключевые детали:

управления Дерево в главном представлении

<TreeView Name="FamilyTree" > 
       <TreeView.Resources> 
        <Style TargetType="{x:Type TreeViewItem}"> 
         <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/> 
         <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/> 
        </Style> 
        <HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Children}"> 
         <reactiveUi:ViewModelViewHost ViewModel="{Binding ViewModel}"/> 
        </HierarchicalDataTemplate> 
       </TreeView.Resources> 
      </TreeView> 

основной код вид сзади

 public partial class MainWindow : Window, IViewFor<MainVM> 
     { 
      public MainWindow() 
      { 
       InitializeComponent(); 
       //build viewmodel 
       ViewModel = new MainVM(); 
       //Register views 
       Locator.CurrentMutable.Register(() => new PersonView(), typeof(IViewFor<Person>)); 
       Locator.CurrentMutable.Register(() => new PetView(), typeof(IViewFor<Pet>)); 
       //NB. ! Do not use 'this.OneWayBind ... ' for the top level binding to the tree view 
       //this.OneWayBind(ViewModel, vm => vm.Family, v => v.FamilyTree.ItemsSource); 
       FamilyTree.ItemsSource = ViewModel.Family; 
    } 
... 
} 

MainViewModel

public class MainVM : ReactiveObject 
     {  
      public MainVM() 
      { 
       var bobbyJoe = new Person("Bobby Joe", new[] { new Pet("Fluffy") }); 
       var bob = new Person("Bob", new[] { bobbyJoe }); 
       var littleJoe = new Person("Little Joe"); 
       var joe = new Person("Joe", new[] { littleJoe }); 
       Family = new ReactiveList<TreeItem> { bob, joe };         
      _addPerson = ReactiveCommand.Create(); 
      _addPerson.Subscribe(_ => 
      { 
       if (SelectedItem == null) return; 
       var p = new Person(NewName); 
       SelectedItem.AddChild(p); 
       p.IsSelected = true; 
       p.ExpandPath(); 
      }); 
    } 
    public ReactiveList<TreeItem> Family { get; } 
    ... 
    } 

TreeItem базового класса

public abstract class TreeItem : ReactiveObject 
{ 
    private readonly Type _viewModelType; 

    bool _isExpanded; 
    public bool IsExpanded 
    { 
     get { return _isExpanded; } 
     set { this.RaiseAndSetIfChanged(ref _isExpanded, value); } 
    } 

    bool _isSelected; 
    public bool IsSelected 
    { 
     get { return _isSelected; } 
     set { this.RaiseAndSetIfChanged(ref _isSelected, value); } 
    } 

    private TreeItem _parent; 

    protected TreeItem(IEnumerable<TreeItem> children = null) 
    { 

     Children = new ReactiveList<TreeItem>(); 
     if (children == null) return; 
     foreach (var child in children) 
     { 
      AddChild(child); 
     } 
    } 

    public abstract object ViewModel { get; } 
    public ReactiveList<TreeItem> Children { get; } 

    public void AddChild(TreeItem child) 
    { 
     child._parent = this; 
     Children.Add(child); 
    } 

    public void ExpandPath() 
    { 
     IsExpanded = true; 
     _parent?.ExpandPath(); 
    } 
    public void CollapsePath() 
    { 
     IsExpanded = false; 
     _parent?.CollapsePath(); 
    } 
} 

Person Класс

public class Person : TreeItem 
    { 
     public string Name { get; set; } 
     public Person(string name, IEnumerable<TreeItem> children = null) 
      : base(children) 
     { 
      Name = name; 
     } 
     public override object ViewModel => this; 
    } 

вид человек пользовательский элемент управления

<UserControl x:Class="TreeViewInheritedItem.PersonView"... >     
    <StackPanel> 
     <TextBlock Name="PersonName"/> 
    </StackPanel> 
</UserControl> 

Person вид кода за

public partial class PersonView : UserControl, IViewFor<Person> 
    { 
     public PersonView() 
     { 
      InitializeComponent(); 
      this.OneWayBind(ViewModel, vm => vm.Name, v => v.PersonName.Text); 
     } 
     ... 
    } 

Pet работают так же, как человек.

И полный проект здесь ReactiveUI Tree view Sample

ответ

0

Я рассмотрел источник ReactiveUI и это единственный способ сделать это. Методы помощника Bind всегда используют DataTemplate, а не HierarchicalDataTemplate.

Таким образом, этот подход будет использовать привязку XAML для самого верхнего уровня, а затем позволит вам использовать привязку ReactiveUI для всех элементов TreeView.

Я посмотрю на создание запроса на растяжение для обработки этого края.

Thanks, Chris

Смежные вопросы