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,
I am just checking if you still require any assistance or clarification on the matter.
That did it, thank you.
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.