I currently have a URL request the brings back XML data. I store that data in a document that is read and finds the information between certain attributes, and assigns those values to the my assigned variables. my wpf DataGrid is called Movie_DataGrid. Any help would be great on how to get this data to the DataGrid.
-- EDIT --
I updated my code with a new way i am trying to get my results. When stepping through each step of the code, the XML is storing fine, and all tag attributes between the Retrivalinfo class and the Retrievalinfo convertedMovie = new Retrievalinfo() are the same, but application errors out at this method.
My new issue is, the values within the attributes is not being grabbed and stored. I have also put a sample of what XML I would get back.
<root response="True">
<movie title="Up in the Air" year="2009" rated="R" released="23 Dec 2009" runtime="109
min" genre="Drama, Romance" director="Jason Reitman" writer="Walter Kirn (novel), Jason
Reitman (screenplay), Sheldon Turner (screenplay)" actors="George Clooney, Vera Farmiga,
Anna Kendrick, Jason Bateman" plot="With a job that has him traveling around the country
firing people, Ryan Bingham leads an empty life out of a suitcase, until his company
does the unexpected: ground him." language="English" country="USA" awards="Nominated for
6 Oscars. Another 64 wins & 66 nominations."poster="http://ia.mediaimdb.com/images/M/MV5BMTI3MzYxMTA4NF5BMl5BanBnXkFtZTcwMD
E4ODg3Mg##._V1_SX300.jpg" metascore="83" imdbRating="7.5" imdbVotes="215,961" imdbID="tt1193138" type="movie"/>
</root>
// This action will seach the IMDb API for the associated infromation for the IMDBID that is tagged with the title you chose in the ListBox.
private void Movie_List_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ // Grabs the IMDBID associated to the movie title selected to be used with the second API request.
var p = Movie_List.SelectedIndex;
string titleID = structholder[p].IMDBID;
// Prepares 2nd API URL request to get data for chosen title.
// Creates a XML Document to store the xml data that was sent back by the API.
XmlDocument doc = new XmlDocument();
doc.Load("http://www.omdbapi.com/?i=" + titleID + "&r=XML");
// Creates a XML Noedlist to store the values that are going to be associated with the given attribute tag.
XmlNodeList movieList = doc.GetElementsByTagName("movie");
var movie = movieList.Item(0);
Retrievalinfo convertedMovie = new Retrievalinfo()
{
title = movie.Attributes["title"].ToString(),
actors = movie.Attributes["actors"].ToString().Split(',').ToList(),
genre = movie.Attributes["genre"].ToString(),
rated = movie.Attributes["rated"].ToString(),
imdbRating = movie.Attributes["imbdRating"].ToString(),
released = movie.Attributes["released"].ToString(),
runtime = movie.Attributes["runtime"].ToString(),
};
List<Retrievalinfo> gridInfo = new List<Retrievalinfo>();
Movie_DataGrid.ItemsSource = gridInfo;
Here is the class where each variable is stored that I want to display in the DataGrid.
namespace WpfApplication3
{
public class Retrievalinfo
{
public Retrievalinfo()
{
actors = new List<string>();
}
//Creating a list of info objects that will store all returned data for selected title.
public string title;
public List<string> actors;
public string genre;
public string rated;
public string imdbRating;
public string released;
public string runtime;
}
}
I though of writing a lengthy aswer but instead, here's a quick sample for you that you can use as reference and figure out the details yourself. MVVM not included :D
Hope it helps.
Codebehind
namespace MyMovies
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
Movies = new ObservableCollection<Movie>()
{
new Movie("Lock, Stock and Two Smoking Barrels", 4),
new Movie("Life of Brian", 5),
};
var addMovieCommand = new RoutedUICommand();
CommandManager.RegisterClassCommandBinding(typeof(Window),
new CommandBinding(
addMovieCommand,
(sender, args) => AddMovie(),
(sender, args) => args.CanExecute = true));
AddMovieCommand = addMovieCommand;
}
public ObservableCollection<Movie> Movies { get; set; }
public ICommand AddMovieCommand { get; set; }
private void AddMovie()
{
Movies.Add(new Movie(Guid.NewGuid().ToString(), 3));
}
}
public class Movie
{
public Movie(string name, int stars)
{
Name = name;
Stars = stars;
}
public string Name { get; set; }
public int Stars { get; set; }
}
}
XAML
<Window x:Class="MyMovies.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<DataGrid
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Movies}">
</DataGrid>
<Button Content="Add movie" Command="{Binding AddMovieCommand}" />
</StackPanel>
</Grid>
</Window>
Which gives you
If I am understanding your question correctly, you need a few pieces:
An ObservableCollection<RetrievalInfo> in your view model to store the retrieved data
A Datagrid (or perhaps a grid view) in your XAML that has its item source bound to the above property
Columns in the above control to represent each of your data pieces.
The retrieval code should modify the observable collection so they appear on your UI
I would be happy to provide samples for any or all of those pieces that you aren't sure how to implement.
You can read the xml to List of object using the code snippet provided in the following Blog
Blog Link:
http://danielwylie.me/blog/2010/04/c-convert-xml-to-an-object-or-list-of-an-object
You can assign the ItemSource of dataGrid by using the following code snippet
Movie_DataGrid.ItemsSource = list;
//here list object from public static List<T> XmlToObjectList<T>(string xml, string nodePath) method
Related
I'm new in WPF and C# so go easy on me :)
My goal is to plot data to graph using LiveCharts2 with WPF help and add data live.
I followed the example of LiveCharts2 added the class ViewModel with and the XAML and everything worked fine:
public partial class ViewModel
{
public ISeries[] Series { get; set; } =
{
new LineSeries<double>
{
Values = new double[] { 1, 2 },
Fill = null
}
};
This is static data .. how do I bind it to a variable that changes at any given time? or how should I change the code for that purpose?
I tried to write only XAML code (view code) and took the example from LiveCharts2 to add data to the "Values" but couldn't make it.
I want something like this and just fire and forget & wish that the data plot will update automatically.
new LineSeries<double>
{
Values = new double[] { myChangedata },
Fill = null
}
You need to use an ObservableCollection instead of an array so the chart can receive updates.
public partial class ViewModel
{
private ObservableCollection<double> myChangedData = new();
public ViewModel()
{
Series.Add(new LineSeries<double>
{
Values = myChangedData,
Fill = null,
});
}
public object Sync { get; } = new();
public List<ISeries> Series { get; set; } = new();
}
Then to add data
lock (Sync)
{
// Any changes including adding, clearing, etc must be synced.
myChangedData.Add(1D);
myChangedData.Add(2D);
}
When doing live data be sure you set the SyncContext property on the chart and always lock it before any changes.
<lc:CartesianChart Series="{Binding Series}" SyncContext="{Binding Sync}"/>
I'm relatively new to WPF and the MVVM architecture, as such I'm having issues with this data binding scenario.
I'm currently creating an application that allows users to create new People via a TabControl. When a user creates a new tab, it auto-populates with custom data fields such as First Name, Last Name, Age, etc. I then need to take this information, insert it into an ObservableCollection and use it to populate a WPF report (which I'm not having any issues with). I'm using a tab control so the user can go back and forth and edit the data as needed.
My issues is that only the first item in the tab control actually populates into the ObservableCollection. I have a button that creates a new tab, populates the content with a UserControl. I used the SelectedPerson so that I can go back in the list and access the Person that corresponds with the TabIndex that's currently being viewed so I can change/add/update the string information.
Here is my XAML code:
<TextBox ... Text="{Binding SelectedPerson.FirstName}"/>
<TabControl ... SelectedIndex="{Binding PersonIndex} ... />
My Caregiver class is as follows:
public class Person{
public string FirstName { get; set; }
public string LastName { get; set; }
}
And my C# code looks like:
private int _PersonIndex;
private Person _SelectedPerson;
private ObservableCollection<Person> Persons = new ObservableCollection<Persons>();
public void AddPerson (Person p){
SelectedPerson = p;
Persons.Add(p);
PersonIndex = Persons.Count - 1;
}
public Person SelectedPerson {
get {
return _SelectedPerson;
}
set {
_SelectedPerson = value;
OnPropertyChanged("SelectedPerson");
}
}
public int PersonIndex{
get {
return _PersonIndex;
}
set {
SelectedPerson = Persons[value];
OnPropertyChanged("PersonIndex");
}
}
Any help would be greatly appreciated!!
My program gets two lists of custom types. The first list is the master and contain a schedule, the second list is the detail and contains the actions taken against the master list.
I am trying to apply these binding lists to a DevExpress Grid Control in a Windows Form with the above mentioned relationship (Master-detail), but I am stumped by how to do this. The examples and walk-troughs I have read use ADO datasets.
I imagine I would have to take the two lists and program a relationship in some kind of dataset file and link this to the grid, but I must admit I haven't a clue. Any guidance welcome.
Thanks :)
P.S. I should mention, I have successfully bound the master view to a list, but my trouble comes when I try to bind the detail view to a data source. It seems to me that the data source will only accept one binding source and the binding source will only accept one binding list.
The GridControl is smart enough to detect a master-detail relation based directly on data-type:
gridControl1.DataSource = new List<Blog> {
new Blog {
Url = "http://blogs.msdn.com/adonet",
Posts = new List<Post>{
new Post() { Title = "The First" },
new Post() { Title = "The Second" }
}
}
};
The relation is defined onto the Blog class level via List-property:
public class Blog {
public string Url { get; set; }
public List<Post> Posts { get; set; } // <<<
}
public class Post {
public string Title { get; set; }
public string Content { get; set; }
}
I have a TypeOfContact model that is made up of an ID, and Text. For example, one type would be Telephone and the ID would be 1. Another type would be Email and the ID 2.
What I would like to do is add the text of the TypeOfContact as an item and the ID as a tag. I imagine it would look something like this, however this isn't working;
contactTypeComboBox.Items.Clear();
foreach (TypeOfContact c in ContactTypes)
{
contactTypeComboBox.Items.Add(c.ContactTypeText);
foreach (ComboBoxItem item in contactTypeComboBox.Items)
{
item.Tag = c.ContactTypeID;
}
}
The reason I want to do this is that when someone selects one of the ComboBox items I want to store the text and the ID. I could do this all through XAML but ContactTypes is a list that is populated by the user, so I cannot hard code the values into the ComboBox as maintaining it and adding new TypesOfContact would be difficult.
I fixed this issue myself by first adding;
DisplayMemberPath="ContactTypeText" SelectedValuePath="ContactTypeID"
to the XAML of the ComboBox then accessing the ID like;
contactTypeComboBox.SelectedValue
In your situation i would bind the list of your TypeOfContacts as ItemsSource to the ComboBox. After that you could set the tag, but i think you don't will need it, because when you also bind the SelectedItem you got back the whole item (ID, type, ...) and can work with it in other parts of your code.
Example for simplifying without a ViewModel (but you should use one):
Codebehind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
FillListWithSomeExamples();
}
private void FillListWithSomeExamples()
{
TypesOfContacts.Add(new TypesOfContact {Id = 1, Type = "Email"});
TypesOfContacts.Add(new TypesOfContact { Id = 2, Type = "Telephone" });
}
public TypesOfContact SelectedTypesOfContact { get; set; }
public ObservableCollection<TypesOfContact> TypesOfContacts { get; set; } = new ObservableCollection<TypesOfContact>();
}
TheTestmodel:
public class TypesOfContact
{
public int Id { get; set; }
public string Type { get; set; }
}
XAML
<Grid>
<ComboBox ItemsSource="{Binding TypesOfContacts}" SelectedItem="{Binding SelectedTypesOfContact}" DisplayMemberPath="Type"/>
</Grid>
Now you can read the selected item in any other method of the MainWindow by looking at SelectedTypesOfContact.
I have the LongListSelector that's working as it should, I want only to enable the grouping now. Like it is in the PeopleHub and the JumpList too. How do I do that ? I have checked an example on MSDN but it's complicated and it didn't work for me, maybe I don't understand it right.
I don't fill the LongListSelector with xaml or C# code, but with xml parsing.
First I parse the xml:
XDocument xml = XDocument.Load("xmlfile.xml");
var data = from query in xml.Descendants("country")
select new Country
{
Name = (string)query.Element("name"),};
and set the itemsSource:
countriesList.ItemsSource = data.ToList();
// Set the data context of the listbox control to the sample data
DataContext = App.ViewModel;
}
I have the Country class:
public class Country
{
string name;
public string Name
{
get { return name; }
set { name = value; }
}}
Now I would like to group this countries by name. How can I do that ?
Thanks for your help.
In the sample they create a fancy-pants helper class called AlphaKeyGroup<T>. Really though, you just need a class to contain each grouping:
public class CountryGrouping : List<Country>
{
public CountryGrouping(IEnumerable<Country> items) : base(items) { }
public string Key { get; set; }
}
Bind the ItemsSource to this:
countriesList.ItemsSource = data
.GroupBy(country => country.Name)
.Select(grp => new CountryGrouping(grp.ToArray()) { Key = grp.Key })
.ToList();
I'm guessing that the LongListSelector looks for a property called "Key" as the group header (magic strings!).
Also, don't forget to set IsGroupingEnabled="true" on the control.
Take a look at this wiki about the LongListSelector on Nokia Developer site: http://developer.nokia.com/Community/Wiki/LongListSelector_with_bindable_SelectedItem_and_better_scrolling
Because it contains a nice example you can use, but also talks about other things you may be needing if you go further with the LongListSelector ( like getting the selecteditem and other stuff )