I have created a DataTemplate as part of a resource of a user control with the following XAML:
<UserControl x:Class="XamDataTreeApp.SystemSettingsView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <UserControl.Resources> <ResourceDictionary> <DataTemplate x:Key="AppSettingsProviderDataTemplate"> <StackPanel Orientation="Horizontal"> <ContentPresenter Grid.Column="1" Content="{Binding Icon}" Margin="4,1,0,1" /> <TextBlock Grid.Column="2" Margin="4,1,0,1" FontWeight="Normal" Text="{Binding Alias, Mode=OneWay}" VerticalAlignment="Center" /> </StackPanel> </DataTemplate> </ResourceDictionary> </UserControl.Resources><Border><ContentPresenter TreeViewContainer/></Border></UserControl>
and code behind.
public partial class SystemSettingsView { public SystemSettingsView(ITreeViewFactory treeViewFactory) { InitializeComponent();
Loaded += (sender, args) => { if (TreeView == null) { var treeCreationCtx = new TreeViewCreationContext { Name = "SystemSettingsView", DataContext = DataContext, ItemSourceBinding = new Binding("SettingProviders"), ItemDataTemplate = (DataTemplate)Resources["AppSettingsProviderDataTemplate"], OnSelectionChanged = (selectedItem) => { var systemSettingsViewModel = DataContext as SystemSettingsViewModel; if (systemSettingsViewModel != null) systemSettingsViewModel.SelectedSettingsProvider = (IAppSettingsProvider) selectedItem; } };
TreeView = treeViewFactory.GetTreeView(treeCreationCtx); } }; }
public FrameworkElement TreeView { get { return TreeViewContainer.Child as FrameworkElement; } set { TreeViewContainer.Child = value; } } }}
When I attempt to programmatically create an instance of xamDataTree that users this template with the following constructs:
public FrameworkElement GetTreeView(TreeViewCreationContext creationContext) { if (creationContext == null) throw new ArgumentNullException("creationContext"); if (creationContext.IsInvalid()) throw new InvalidDataException("creation context is not valid");
var tree = new XamDataTree() { Name = creationContext.Name, NodeLineVisibility = Visibility.Visible, DataContext = creationContext.DataContext }; tree.SetBinding(XamDataTree.ItemsSourceProperty, creationContext.ItemSourceBinding);
if (creationContext.SelectedItemBinding != null) tree.SetBinding(XamDataTree.SelectedDataItemsProperty, creationContext.SelectedItemBinding);
if (creationContext.ItemDataTemplate != null) { var nodeLayout = new NodeLayout(); nodeLayout.ItemTemplate = creationContext.ItemDataTemplate; tree.GlobalNodeLayouts.Add(nodeLayout); }
if (creationContext.OnSelectionChanged != null) { tree.SelectedNodesCollectionChanged += (sender, args) => creationContext.OnSelectionChanged.Invoke(tree.SelectedDataItems.First()); } return tree; }
public class TreeViewCreationContext { public string Name { get; set; } public object DataContext { get; set; } public Binding ItemSourceBinding { get; set; } public DataTemplate ItemDataTemplate { get; set; } public Action<object> OnSelectionChanged { get; set; } public Binding SelectedItemBinding { get; set; }
public bool IsValid() { return !IsInvalid(); }
public bool IsInvalid() { if (DataContext == null) return true; if (ItemSourceBinding == null) return true; if (ItemDataTemplate == null) return true;
return false; } }
I get the following exception: "A NodeLayout with this key is already in this collection."
If I do the same thing using WPF native treeview as follows:
var tv = new TreeView { Name = creationContext.Name, DataContext = creationContext.DataContext }; tv.SetBinding(ItemsControl.ItemsSourceProperty, creationContext.ItemSourceBinding);
if (creationContext.ItemDataTemplate != null) tv.ItemTemplate = creationContext.ItemDataTemplate;
if (creationContext.SelectedItemBinding != null) tv.SetBinding(BindableSelectedItemBehavior.SelectedItemProperty, creationContext.SelectedItemBinding);
if (creationContext.OnSelectionChanged != null) { tv.SelectedItemChanged += (sender, args) => creationContext.OnSelectionChanged.Invoke(tv.SelectedItem); }
var behaviors = Interaction.GetBehaviors(tv); behaviors.Add(new BindableSelectedItemBehavior()); return tv; }
I do not have this problem.
Any tips?
Hello Klaus,
Thank you for your feedback. I am glad that you resolved your issue and I believe that other community members may benefit from this as well.
Thanks again.
That did it, thank you.
Hello,
I am just checking if you still require any assistance or clarification on the matter.
Thank you for your post. I have been looking into it and I can suggest you set the Key Property of the NodeLayout. Please let me know if this helps you or you have further questions on this matter.
Looking forward for your reply.