How to bind xml to wpf treeview? I am using Prism mvvm pattern. I will prefer an IList for holding the data for looping.
I have tried http://geeklyeverafter.blogspot.com/2010/03/wpf-treeview-bound-to-xml-file.html and
http://www.blogs.intuidev.com/post/2009/12/28/xml_to_treeview.aspx
but nothing worked.
OK. It is The question is quite old now, but I think there is a simple way to bind XML to a TreeView. Maybe it is helpful for someone.
XAML:
<Window.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Elements}" x:Key="NodeTemplate">
<Grid>
<TextBlock Text="{Binding Path=Name}"/>
</Grid>
</HierarchicalDataTemplate>
</Window.Resources>
...
<TreeView x:Name="myTreeView" Grid.Column="0"
ItemsSource="{Binding Path=Root.Elements}"
ItemTemplate="{StaticResource ResourceKey=NodeTemplate}"
/>
In the code behind I just create a XDocument (System.Xml.linq) and bind this one to the DataContext of the TreeView. For example like this:
private XDocument _theXML;
public XDocument TheXML {
get => _theXML;
set => _theXML = value;
}
public MainWindow()
{
...
InitializeComponent();
DataContext = this;
TheXML = XDocument.Load(#"c:\file.xml");
myTreeView.DataContext = TheXML;
myTreeView.UpdateLayout();
}
That's it. The content of the XML file will be shown as a TreeView. If you like to see some more Details (Attributes, ...) you can refine the Template in the XAML code.
The way I've done it is to create a method that builds the tree view to a treeview property. Set the WPF treeview items binding to the items property of the treeview property in your class. Of course implementing INotifyPropertyChanged in your ViewModelBase is essential.
I would be happy to give an example, but I do not have access to the internet on my PC at the moment
I did see in the post and do agree that this is not the most proficient way . However since you are already using xml serialization, the parsing of xml is done, now you just have to use the data.
I think that if you were not going to serialize, then the links you posted would hold more validity in the methodology you are you are trying to achieve. But that is just IMO. I will update with some working code when I get the chance tomorrow, the idea of data binding directly to xml sounds fun.
In the meantime check this link out. It looks pretty strait forward.
http://social.msdn.microsoft.com/Forums/vstudio/en-US/cbdb2420-1403-436f-aa7f-b1e3b1acb398/binding-any-xml-document-to-wpf-treeview?forum=wpf
Related
I am using PRISM to auto-wire my Views & ViewModels, however I have encountered a problem I cannot solve.
I am using a calendar control, which enables users to create new appointments via opening new modal window & saving it to calendar.
This window, is styled via a ControlTemplate, where I have the following item:
<telerik:RadComboBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Margin="3"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.EmployeeList}">
Items Source of this combobox is the ViewModels DataContext.EmployeeList - ObservableCollection<Employee>.
This would work like a charm as long as it would not be a new pop-out window. That way, I believe it is a userControl as well and therefore my regular code does not recognize any EmployeeList.
There might be 2 ways how to solve it (I don't have direct access to the modal window as it is being automatically generated by the control itself - I am using Telerik suite).
1) Make sure that the ItemsSource will dig deeper than the very first UserControl that it finds. Maybe by slightly changing the code, it will be able to do so? (Maybe using something like AncestorLevel...?).
2) Telerik has shown an example of how to achieve that by the following line:
<local:ViewModel x:Key="ViewModel" /> -- define key first
ItemsSource="{Binding Source={StaticResource ViewModel}, Path=EmployeesSource}"...
BUT the issue with my ViewModel is that under constructor I am passing several interfaces like following:
private readonly IEmployeeRepository _employeeRepository;
public EmployeeView_HolidaysViewModel(IEmployeeRepository employeeRepository)
{
_employeeRepository = employeeRepository;
InitializeCollections();
InitializeCommands();
}
and therefore I can't make the above solution to work at all.
Any help with my problem would be highly appreciated. I simply need to get that list to that modal window's combobox.
In the end I managed to solve the problem by creating additional constructor to my class which looks like following:
public EmployeeView_HolidaysViewModel()
{
_employeeRepository = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<IEmployeeRepository>();
InitializeCollections();
}
This way I can easily adopt Solution Nr 2 from the OP.
I would like to add pure XAML code into my xaml elements during runtime. Does anyone know how to do that? thank you.
I would like to do something like this: myGrid.innerXAML = stringXAMLcode
that would result to <grid name="myGrid">newgeneratedcodehere</grid>
in PHP you can print verbatim HTML code directly into the HTML file. Is this possible with c#?
if not, can anyone suggest a work-around?
thanks!
There are ways to do what you're asking here, as explained in this CodeProject Article:
Creating WPF Data Templates in Code: The Right Way
However, most of the time you really don't need that for daily operations.
If you're working with WPF, you really need to leave behind the traditional approach from other frameworks and embrace The WPF Mentality.
HTML (4, 5 or whatever) looks like a ridiculous joke when compared to the WPF implementation of XAML, therefore all the horrendous hacks you might be used to in HTML are completely unneeded in WPF, because the latter has a lot of built-in features that help you implement advanced UI capabilities in a really clean way.
WPF is heavily based on DataBinding and promotes a clear and well-defined separation between UI and Data.
For example, this would be what you would do to when you want to "show different pieces of UI" depending on the Data, by using a WPF feature called DataTemplates:
XAML:
<Window x:Class="MyWindow"
...
xmlns:local="clr-namespace:MyNamespace">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Person}">
<!-- this is the UI that will be used for Person -->
<TextBox Text="{Binding LastName}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Product}">
<!-- this is the UI that will be used for Product -->
<Grid Background="Red">
<TextBox Text="{Binding ProductName}"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<!-- the UI defined above will be placed here, inside the ContentPresenter -->
<ContentPresenter Content="{Binding Data}"/>
</Grid>
</Window>
Code Behind:
public class MyWindow
{
public MyWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
ViewModel:
public class MyViewModel
{
public DataObjectBase Data {get;set;} //INotifyPropertyChanged is required
}
Data Model:
public class DataObjectBase
{
//.. Whatever members you want to have in the base class for entities.
}
public class Person: DataObjectBase
{
public string LastName {get;set;}
}
public class Product: DataObjectBase
{
public string ProductName {get;set;}
}
Notice how I'm talking about my Data and Business Objects rather than worried about any hacks to manipulate the UI.
Also notice how defining the DataTemplates in XAML files that will get compiled by Visual Studio gives me compile-time checking of my XAML as opposed to putting it together in a string in procedural code, which of course doesn't have any kind of consistency checks.
I strongly suggest you read up on Rachel's answer (linked above) and related blog posts.
WPF Rocks
Why don't you add exactly the elements you want? Something like:
StackPanel p = new StackPanel();
Grid g = new Grid();
TextBlock bl = new TextBlock();
bl.Text = "This is a test";
g.addChildren(bl);
p.addChildren(g);
You can do this for all the elements that exist in the XAML.
Regards
You can use XamlReader to create the UIElement that you can set as child of content control or layout containers:
string myXamlString = "YOUR XAML THAT NEEDED TO BE INSERTED";
XmlReader myXmlReader = XmlReader.Create(myXamlString);
UIElement myElement = (UIElement)XamlReader.Load(myXmlReader);
myGrid.Children.Add(myElement );
To date every ListView I've had I just set ItemSource={Binding} in my Xaml and then in the .CS file I say listview.datacontext = myobject and the view loads just fine. But now I need to have a list that updates as the data updates as well. So after some research I discovered ObservableCollections and rewrote my code to use that. But I can't get my data to display when setting the listview to my dataobject.
My Xaml:
<ListView ItemsSource="{Binding Tests}" Name="DataCompareTests" Margin="0,0,5,0" Grid.Column="0">
<ListView.View>
<GridView>
<GridViewColumn Header="TestCase" Width="200" DisplayMemberBinding="{Binding name}" />
</GridView>
</ListView.View>
</ListView>
My Xaml.cs:
readonly DataCompare dataCompare = new DataCompare();
public void Execute_Click(object sender, RoutedEventArgs e)
{
var Tests = new ObservableCollection<TestCases>();
Tests = dataCompare.LoadTestCases(); //located in another class file
//DataCompareTests.DataContext = Tests;
}
If I remove the "Tests" part of the binding in my Xaml and remove the comments from the .DataContext line above, the view displays the correct information. However it's my assumption that if I want my view to update as the data does I need to specify my object in the binding. How do I properly set that? I can't seem to find the correct answer.
Thanks,
Jason
I think you need to familiarize yourself a little better with bindings and object oriented programming in general.
If you set your datacontext to your model object, ".Tests" should be a public property of that model object. Also, don't do this:
var someVariable = new SomeClassThatTakesWorkToConstruct();
someVarialbe = someOtherVariable.SomeMethod();
What you meant to do was this:
var someVariable = someOtherVariable.SomeMethod();
This is for 2 good reasons 1) You are not wasting the construction of an ObservableCollection. 2) Your code will be easier to refactor (the type returned by SomeMethod can change without you having to alter your declaration of someVariable).
Edit, additional resources:
Databinding Overview
You've got a path specified but no source for the binding specified.
MVVM Article
Great article on using the common MVVM WPF pattern, helps you keep your code object oriented, clean, etc. even with complex UI interaction.
It would appear my concerns were pointless and I WAS doing this the proper way in the first place.
According to MSDN:
"However, if you are binding to an object that has already been created, you need to set > the DataContext in code, as in the following example.
...
myListBox.DataContext = myDataSet;"
My object was already created, and I did set the DataContext in the code. All I had to do was leave the ListView ItemSource as {Binding} and each time I added to the Tests object, the list updated..
I can't believe I spent an entire day doubting I was doing this correctly without moving forward to check. :-)
i've been banging my head on this for the last hours...
I have a User Control called "DayItem", and i want to show it 48 times in another UserControl called "DayPanel".
Let me mention this is done in MVVM style, but i'm only experiencing, and a straight way would by fine for an answer.
I have an ObservableCollection<DayItem> in the DayPanel model, and in the Xaml there's an <ItemsPresenter />.
if i do
this.ItemsSource = DayItems;
everything show up fine.
but, i wanna be able to use those DayItems in the UI like a list... to support multi-select etc.
so i tried using a ContentControl, and set it's content to the ObservableCollection.
but it just shows the ObservableCollection object's ToString text.
so i guess i need a DataTemplete there...
but why do i need a DataTemple to show a Control?
it's already styled in it's own Xaml, i don't wanna repeat it's styling again.
or maybe i'm totally wrong, anyway i need help :x
Edit:
I got this to work, saying what DataType wasn't necessary or even possible.
and in the code behind i told the listbox, that it's ItemSource was the ObservableCollection.
now i've ran into other problems... ListBox related...
There are Gaps between each control in the ListBox, which messes up the layout
and also i need to figure out a way to select multiple items by dragging...
thanks for the help so fat
First, you need a view model for you DayItem user control. Lets call it DayItemViewModel. Also I suppose you DayPanel also has a view model called something like DayPanelViewModel. Then, you DayPanelViewModel would expose a collection of DayItemViewModel instances:
public class DayPanelViewModel
{
public ObservableCollection<DayItemViewModel> DayItems { get; set; }
}
Then, in your DayPanel.xaml:
<UserControl x:Class="DayPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<DataTemplate x:Key="DayItemTemplate"
DataType="{x:Type my:DayItemViewModel}">
<my:DayItem />
</DataTemplate>
</UserControl.Resources>
<Grid>
<ListBox ItemsSource="{Binding DayItems}"
ItemTemplate="{StaticResource DayItemTemplate}" />
</Grid>
</UserControl>
Try using ListBox, since that implements multiselect...
Also it might be wise (for MVVM) if you do not contain DayItems, but DayItemModel's in your DayPanelModel, and set the ListBox's ItemTemplate to present each DayItemModel with a DayItem.
I have a databound Silverlight DataGrid control that I am trying to sort. I am using RIA services (beta) for my data source, if that makes any difference.
I am quite new to databinding in Silverlight, so this might be something really obvious that I've missed, but I can't seem to find any info on it. I want to be able to set the binding of the ItemSource to a collection in xaml using binding syntax, and have it sorted on one column.
I realize I could set the ItemsSource in code and use LINQ to .OrderBy(). But I don't get a binding that way. It seems like there should be a simple way to do this but I can't find one. How can I keep the binding yet order my collection?
have a look at using a CollectionViewSource. You basically use one as a 'middleman' between your actual collection of data and you data-bound control.
rough example:
<Window.Resources>
<CollectionViewSource
Source="{Binding <<<bind to your collection here >>> }"
x:Key="myDataView" />
</Window.Resources>
...
<ListBox Name="lsyFoo"
ItemsSource="{Binding Source={StaticResource myDataView}}">
...
then in your code behind:
myDataView.SortDescriptions.Add(
new SortDescription("<<<insert property to sort by>>>", ListSortDirection.Ascending));
(ps. you can also add grouping using PropertyGroupDescription)
As you are using RIA Services, you can use the DomainDataSource in your XAML. This will allow you to add SortDescriptors which will do your ordering. See my example below:
<riaControls:DomainDataSource.SortDescriptors>
<riaData:SortDescriptor Direction="Ascending"
PropertyPath="Name" />
</riaControls:DomainDataSource.SortDescriptors>