Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to replace a static XmlDataProvider in a WPF Usercontrol with a dynamic dataset?

Question may need to be edited since I don't think I necessarily know the best way to do this.

Current config of my WPF usercontrol. I have a XmlDataProvider that contains some static XML Elements that I use to populate a TreeView control. I currently use a HierarchicalDataTemplate to bind to a TreeViewItem

    <HierarchicalDataTemplate x:Key="SiteTemplate" ItemsSource="{Binding XPath=pci}">
        <TextBlock Text="{Binding XPath=@Name}"/>
    </HierarchicalDataTemplate>
    <Style TargetType="TreeViewItem">
        <Setter Property="IsExpanded" Value="True"/>
    </Style>

TreeView control

 <TreeView ItemsSource="{Binding Source={StaticResource SharePointSites}}" 
                              ItemTemplate="{StaticResource SiteTemplate}" 

I would like to replace the current static resource with data that is loaded from a xml file at runtime. Additionally I want the user to be able to modify the nodes of the treeview at runtime and have those values written back to the same xml file. I have been reading up about using the MVVM pattern and creating an IObservable class. Can someone point me in the right direction?

Edit: Perhaps I've asked this question in a sub-optimal way. Can anyone recommend improvements or make edits to improve the quality of the question in anyway?

like image 951
Anonymous Type Avatar asked Oct 25 '22 15:10

Anonymous Type


1 Answers

I have no access to my Visual Studio environment so the code below will be full of compilation errors... So please treate this as a pseudo code...

Assuming your Xml structure is something like this....

<MyItem Name="Root"> 
    <MyItem Name="ABC"/> 
    <MyItem Name="PQR"> 
        <MyItem Name="IJK"/> 
    </MyItem> 
    <MyItem Name="XYZ"/> 
</MyItem> 
  1. Bind your ItemsSource thru a converter , say MyXmlToObjectDataSourceConverter.

    <TreeView ItemsSource="{Binding Source={StaticResource SharePointSites},
           Converter={StaticResource MyXmlToObjectDataSourceConverter}}" ... />
    
  2. In MyXmlToObjectDataSourceConverter.Convert() method return this...

    public object Convert(...) 
    { 
        return new ObservableCollection<XmlNodeWrapper>(
            ((XmlDataProvider)value).Document.SelectNodes("MyItem").Select( 
                d => new XmlNodeWrapper(d)).ToList()) 
    }
    
  3. XmlNodeWrapper class will maintain the 'node' internally so that when updates take place thru property Setters, you can update the node based attribute back... like this...

    public class XmlNodeWrapper : INotifyPropertyChanged
    { 
        private XmlNode node; 
        private ObservableCollection<XmlNodeWrapper> children; 
    
        public XmlNodeWrapper(XmlNode node) 
        { 
            this.node = node; 
        } 
    
        public ObservaleCollection<XmlNodeWrapper> Children 
        { 
            get 
            { 
                if (children == null) 
                { 
                    this.children 
                        = new ObservableCollection<XmlNodeWrapper>( 
                            this.node.ChildNodes.Select( 
                                d => new XmlNodeWrapper(d)).ToList()); 
                } 
    
                return children; 
            } 
        } 
    
        public string Name 
        { 
            get 
            { 
                return node.Attributes["Name"]; 
            } 
    
            set 
            { 
                node.Attributes["Name"] = value; 
                this.PropertyChanged["Name"]; 
            } 
        } 
    
        public event PropertyChangedEventHandler PropertyChanged; 
    
        private void PropertyChanged(String info) 
        { 
            if (PropertyChanged != null) 
            { 
                PropertyChanged(this, new PropertyChangedEventArgs(info)); 
            } 
        }
    } 
    
  4. Then replace all XPath attributes in your XAML with standard Path.

    <HierarchicalDataTemplate x:Key="SiteTemplate"
        ItemsSource="{Binding Path=Children}"> 
            <TextBlock Text="{Binding Path=Name}"/> 
    </HierarchicalDataTemplate>
    
like image 56
WPF-it Avatar answered Jan 04 '23 18:01

WPF-it