I am reading data from XML like this:
(Contacts.xml)
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--LINQ to XML Contacts XML Example-->
<?MyApp 123-44-4444?>
<contacts>
<contact>
<name>Patrick Hines</name>
<phone type="home">206-555-0144</phone>
<phone type="work">425-555-0145</phone>
<address>
<street1>123 Main St</street1>
<city>Mercer Island</city>
<state>WA</state>
<postal>68042</postal>
</address>
</contact>
<contact>
<name>Gretchen Rivas</name>
<phone type="mobile">206-555-0163</phone>
<address>
<street1>123 Main St</street1>
<city>Mercer Island</city>
<state>WA</state>
<postal>68042</postal>
</address>
</contact>
</contacts>
My code for getting data from XML file:
(contacts.cs)
public class Contact
{
//static members
public static string fLocation;
//private members
private string name;
private List<PhoneNumber> pNumber;
private Adress cAdress;
//public members
public Adress CAdress
{
get { return cAdress; }
}
public List<PhoneNumber> PNumber
{
get { return pNumber; }
}
public string Name
{
get { return name; }
}
//Constructor
public Contact(string _name, List<PhoneNumber> _pNumber,Adress _cAdress)
{
name = _name;
pNumber = _pNumber;
cAdress = _cAdress;
}
public static List<Contact> Get()
{
List<Contact> output = new List<Contact>();
XDocument data = XDocument.Load(fLocation);
var query = from c in data.Descendants("contact")
orderby c.Element("name").Value
select c;
foreach (var item in query)
{
List<PhoneNumber> pNumber = new List<PhoneNumber>();
foreach (var PhoneNumbers in item.Elements("phone"))
{
pNumber.Add(new PhoneNumber(PhoneNumbers.Value,PhoneNumbers.Attribute("type").Value));
}
Adress cAdress = new Adress(item.Element("address").Element("street1").Value,
item.Element("address").Element("city").Value,
item.Element("address").Element("state").Value,
item.Element("address").Element("postal").Value);
output.Add(new Contact(item.Element("name").Value,pNumber,cAdress));
}
return output;
}
//subclasses
public class Adress
{
private string street;
private string city;
private string state;
private string postal;
public string Postal
{
get { return postal; }
}
public string State
{
get { return state; }
}
public string City
{
get { return city; }
}
public string Street
{
get { return street; }
}
public Adress(string _street,string _city, string _state, string _postal)
{
street = _street;
city = _city;
state = _state;
postal = _postal;
}
}
public class PhoneNumber
{
private string number;
private string numberType;
public string NumberType
{
get { return numberType; }
}
public string Number
{
get { return number; }
}
public PhoneNumber(string _number, string _phoneNumberType)
{
number = _number;
numberType = _phoneNumberType;
}
}
}
And I want to somehow bind to Gridview:
(default.aspx)
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="ObjectDataSource1">
<Columns>
<asp:BoundField DataField="Name" HeaderText="Name" ReadOnly="True"
SortExpression="Name" />
<asp:DynamicField DataField="CAdress" HeaderText="CAdress" />
<asp:DynamicField DataField="PNumber" HeaderText="PNumber" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="Get"
TypeName="LINQtoXML_WebForms.Contact"></asp:ObjectDataSource>
Any ideas how to bind for example Contact.PhoneNumber.number + "-" Contact.PhoneNumber.numberType to colomn?
i.e.: 774-6655-252 - mobile
Thanks.
When I run it, it shows me an error:
Could not determine a MetaTable. A MetaTable could not be determined for the data source 'ObjectDataSource1' and one could not be inferred from the request URL. Make sure that the table is mapped to the dats source, or that the data source is configured with a valid context type and table name, or that the request is part of a registered DynamicDataRoute.
I think you either have to add meta information to your class or use the approach I'd use - write a method yourself instead of using objectdatasource object.
For example Linq to XML
public List<Contact> GetContacts()
{
XDocument doc = XDocument.Load("path_to_some_file.xml");
var contacts = from o in doc.Descendants("contact")
select new Contact()
{
Name = (string)o.Element("Name"),
Phone = (string)o.Element("Phone")
};
return contacts.ToList();
}
and then just bind it in code-behind to your control:
GridView1.DataSource = GetContacts();
GridView1.DataBind();
Hope you get the idea.
Related
To avoid querying the Database on the first loading of the page, I want to populate a List of a custom class to the GridView.
I'm trying to do it this way:
protected void Page_Load(object sender, EventArgs e)
{
List<MoviesGridDisplayColumns> listStartupData = new List<MoviesGridDisplayColumns>();
MoviesGridDisplayColumns mgdc;
mgdc = new MoviesGridDisplayColumns();
mgdc.MovieTitle = "War of the Buttons";
mgdc.MPAARating = "PG";
mgdc.IMDBRating = 7.5;
mgdc.Minutes = 94;
mgdc.YearReleased = "1994";
listStartupData.Add(mgdc);
mgdc = new MoviesGridDisplayColumns();
mgdc.MovieTitle = "The Trip to Bountiful";
mgdc.MPAARating = "PG";
mgdc.IMDBRating = 7.5;
mgdc.Minutes = 108;
mgdc.YearReleased = "1985";
listStartupData.Add(mgdc);
. . .
GridView1.DataSource = listStartupData;
GridView1.DataBind();
...but on the penultimate line above I get:
"System.Web.HttpException HResult=0x80004005 Message=A field or
property with the name 'MovieTitle' was not found on the selected data
source."
The selected data source is the List of MoviesGridDisplayColumns objects, which does indeed have a MovieTitle member. So what gives?
The custom class is:
public class MoviesGridDisplayColumns
{
public string MovieTitle = string.Empty;
public double IMDBRating = 0.0;
public string MPAARating = string.Empty;
public string YearReleased = string.Empty;
public int Minutes;
}
...and the GridView appears in the .aspx file thus:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" OnDataBound="GridView1_DataBound" OnPreRender="GridView1_PreRender">
<Columns>
<asp:BoundField DataField="MovieTitle" HeaderText="MovieTitle" SortExpression="MovieTitle" />
<asp:BoundField DataField="IMDBRating" HeaderText="IMDBRating" SortExpression="IMDBRating" />
<asp:BoundField DataField="MPAARating" HeaderText="MPAARating" SortExpression="MPAARating" />
<asp:BoundField DataField="YearReleased" HeaderText="YearReleased" SortExpression="YearReleased" />
<asp:BoundField DataField="Minutes" HeaderText="Minutes" SortExpression="Minutes" />
</Columns>
</asp:GridView>
The fields in your class are missing the getter methods. You can change the MoviesGridDisplayColumns to the following.
public class MoviesGridDisplayColumns
{
public string MovieTitle { get; set; } = string.Empty;
public double IMDBRating { get; set; } = 0.0;
public string MPAARating { get; set; } = string.Empty;
public string YearReleased { get; set; } = string.Empty;
public int Minutes { get; set; }
}
I have a database linked to my grid. When adding data a new checkbox appears, so it is registering that something has been entered, but, the columns are all blank.
Im pretty sure the issue is that I have the bindings set up for the class Person. Could I either still use this class with some additional code, or, find a way to separate the data from the database into columns?
Relevant Code:
Database Class method:
public static List<string> Grab_Entries()
{
List<string> entries = new List<string>();
using (SqliteConnection db = new SqliteConnection("Filename=sqliteSample.db"))
{
db.Open();
SqliteCommand selectCommand = new SqliteCommand("SELECT * from EmployeeTable", db);
SqliteDataReader query;
try
{
query = selectCommand.ExecuteReader();
}
catch (SqliteException)
{
//Handle error
return entries;
}
while (query.Read())
{
entries.Add(query.GetString(0));
}
db.Close();
}
return entries;
MainPage method:
public void EmployeeGrid_Loaded(object sender, RoutedEventArgs e)
{
EmployeeGrid.ItemsSource = DB.Grab_Entries();
}
Main Page XAML:
<controls:DataGrid x:Name="EmployeeGrid" Margin="170,55,35,35"
ItemsSource="{x:Bind persons}"
CanUserSortColumns="True"
AutoGenerateColumns="False" Background="Black" Loaded="EmployeeGrid_Loaded">
<controls:DataGrid.Columns>
<controls:DataGridTextColumn Header="Employee ID"
Binding="{Binding PersonId}"/>
<controls:DataGridTextColumn Header="First Name"
Binding="{Binding FirstName}"/>
<controls:DataGridTextColumn Header="Last Name"
Binding="{Binding LastName}"/>
<controls:DataGridTextColumn Header="Address"
Binding="{Binding Address}"/>
<controls:DataGridTextColumn Header="Position"
Binding="{Binding Position}"/>
<controls:DataGridTextColumn Header="Pay Rate (ph)"
Binding="{Binding PayratePH}"/>
<controls:DataGridTextColumn Header="Sex"
Binding="{Binding Sex}"/>
<controls:DataGridTextColumn Header="TaxCode"
Binding="{Binding TaxCode}"/>
<controls:DataGridTextColumn Header="Email"
Binding="{Binding Email}"/>
<controls:DataGridTextColumn Header="Emergency Contact"
Binding="{Binding EmergencyDetails}"/>
<controls:DataGridCheckBoxColumn Header="Selected"
/>
</controls:DataGrid.Columns>
</controls:DataGrid>
Ill add my Person class too:
public class Person
{
public int PersonId { get; set; }
public int DepartmentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Position { get; set; }
public string Address { get; set; }
public double PayratePH { get; set; }
public string Sex { get; set; }
public string TaxCode { get; set; }
public string EmergencyDetails { get; set; }
public string Email { get; set; }
I can spot two things here. First, the main page XAML binds the items source to persons, which gets overwritten with the return value of DB.Grab_Entries() whenever the control loads.
In EmployeeGrid_Loaded(), you should be populating the collection that the ItemsSource is bound to (persons), instead of assigning a new collection.
The loaded event should look something like this:
public void EmployeeGrid_Loaded(object sender, RoutedEventArgs e)
{
this.persons.Clear();
this.persons.AddRange(DB.Grab_Entries());
}
P.S. make sure that the ItemsSource collection is of type ObservableCollection, because otherwise it will not update the binding when the elements change.
Second, the method DB.Grab_Entries() returns a list of strings, but by the looks of it, the data grid and the persons collection is expecting a list of person objects with certain properties.
When you're reading the data from the sqlite query, you're getting a single column of data at a time (query.GetString(0)). You'll need to construct an object with all column values and put the object into a list.
As #Darius S. mentioned, the ItemsSource of DataGrid you bound with is the lists of Person class, however, the DB.Grab_Entries() method returns the lists of string type, so the DataGrid can't display well. In your Grab_Entries method, you could get the value each property and then convert them into the Person class. After that, add the Person class into entries lists.
In addition, it is recommended to use ObservableCollection class, when you insert or remove data from this class, it will automatically update the UI. So it's better to return ObservableCollection type from your Grab_Entries method directly. I take the FirstName property as an example:
public async static Task<ObservableCollection<Person>> Grab_Entries()
{
ObservableCollection<Person> entries = new ObservableCollection<Person>();
string dbpath = Path.Combine(ApplicationData.Current.LocalFolder.Path, "sqliteSample.db");
using (SqliteConnection db = new SqliteConnection($"Filename={dbpath}"))
{
db.Open();
SqliteCommand selectCommand = new SqliteCommand("SELECT * from EmployeeTable", db);
using (var reader = await selectCommand.ExecuteReaderAsync())
{
var nameOrdinal = reader.GetOrdinal("First_Name");
//The same method to get other properties
while (await reader.ReadAsync())
{
entries.Add(new Person() { FirstName = reader.GetString(nameOrdinal) });
}
}
db.Close();
}
return entries;
}
MainPage.cs:
ObservableCollection<Person> persons;
public async void EmployeeGrid_Loaded(object sender, RoutedEventArgs e)
{
persons = await Person.Grab_Entries();
EmployeeGrid.ItemsSource = persons;
}
I have been struggling to loop through my private static List in my HomeController to display in such a way it shows a list of both students and personnel. Below is an example of what my loop should look like.
[Student] Name:John Surname:Greenberg Email: 123#123 Cellphone:123456789 Age: 20
[Personnel] Name:Rose Surname:Marry Email: email#email Cellphone:123456789 WorkerType: Permanent Degree: BED Education
[Student] Name:Chaz Surname:Brown Email: chazz#gmail.com Cellphone:123456789 Age: 30
Please help me loop properly and Below is my ContestantView i tried coding
#model List<Assignment9_u14333393.Models.ContestantViewModel>
<div style="width:100%;height:auto; background-color:brown; padding-top:10px; padding-bottom:10px;">
<h2 style="text-align:center; color:white;">List of Contestants</h2>
</div>
.
<div class="members" >
<table>
#foreach (var temp in Model)
{
<div class="member">
[#temp.MemberType] Name:#temp.Name Surname:#temp.Surname Email: #temp.Email Cellphone:#temp.CellPhone
</div>
}
</table>
</div>
For additional information I also have three models (StudentViewModel, PersonnelViewModel and ContestantViewModel).
ContestantViewModel is my parent class and StudentViewModel and PersonnelViewModel are my classes which have inherited data members and properties for the parent class.
1st Model
public class ContestantViewModel
{
//Data members
private string mName;
private string mSurname;
private string mCellPhone;
private string mEmail;
private string mMemberType;
//Defeaut Constructor
public ContestantViewModel()
{
mName = "NoName";
mSurname = "NoSurname";
mCellPhone = "NoCellNumber";
mEmail = "NoEmail";
mMemberType = "NoMemberType";
}
//Constructor
public ContestantViewModel(string Name, string Surname, string CellPhone, string Email, string MemberType)
{
mName = Name;
mSurname = Surname;
mCellPhone = CellPhone;
mEmail = Email;
mMemberType = MemberType;
}
//Properties
public string Name
{
get { return mName; }
set { mName = value; }
}
public string Surname
{
get { return mSurname; }
set { mSurname = value; }
}
public string CellPhone
{
get { return mCellPhone; }
set { mCellPhone = value; }
}
public string Email
{
get { return mEmail; }
set {mEmail = value; }
}
public string MemberType
{
get; set;
}
}
2rd Model
public class PersonnelViewModel : ContestantViewModel
{
private string mWorkerType;
private string mDegree;
public PersonnelViewModel(string Name, string Surname, string CellPhone, string Email, string MemberType, string WorkerType, string Degree) : base (Name,Surname,CellPhone,Email, MemberType)
{
mWorkerType = WorkerType;
mDegree = Degree;
}
public PersonnelViewModel()
{
mWorkerType = "NoWorkerType";
mDegree = "NoDegree";
}
public string WorkerType
{
get { return mWorkerType;}
set { mWorkerType = value; }
}
public string Degree
{
get { return mDegree; }
set { mDegree = value; }
}
}
3rd Model
public class StudentViewModel : ContestantViewModel
{
//Data members
private int mAge;
//D Constructor
public StudentViewModel()
{
mAge = 0;
}
//Constructor
public StudentViewModel(string Name, string Surname, string CellPhone, string Email, string MemberType, int Age) : base(Name, Surname, CellPhone, Email, MemberType)
{
mAge = Age;
}
//properties
public int Age
{
get { return mAge; } set { mAge = value; }
}
}
and this is my controller
public class HomeController : Controller
{
// list to hold all my new members
private static List<ContestantViewModel> List = new List<ContestantViewModel>();
// GET: Home
public ActionResult Index()
{
return View();
}
// GET: Signup
public ActionResult Signup(string Name, string Surname, string Email, string Cellphone, string MemberType, int Age,string WorkerType,string Degree)
{
StudentViewModel Stundent = new StudentViewModel();
PersonnelViewModel Personnel = new PersonnelViewModel();
if (MemberType == "Student")
{
//creates instance
Stundent.Name = Name;
Stundent.Surname = Surname;
Stundent.Email = Email;
Stundent.CellPhone = Cellphone;
Stundent.MemberType = MemberType;
Stundent.Age = Age;
// Add data to list
List.Add(Stundent);
}
else
{
//creates instance
Personnel.Name = Name;
Personnel.Surname = Surname;
Personnel.Email = Email;
Personnel.CellPhone = Cellphone;
Personnel.MemberType = MemberType;
Personnel.WorkerType = WorkerType;
Personnel.Degree = Degree;
// Add data to list
List.Add(Personnel);
}
return View(List);
}
}
Put your collection into it's own view model instead of trying to reference it with this line:
#model List<Assignment9_u14333393.Models.ContestantViewModel>
Make a new view model, ViewModelCollections with a collection of your ContestantViewModel. Something like
List<ContestantViewModel> ContestantList
(you can also add others, like your students and workers and reuse the model, even if for some purposes some collections are empty)
Then reference that with:
#model ViewModelCollections
Once you have put all your contestants into the collection you are very close in your current view code.
<div class="members">
<table id="contestantListTable">
<tbody>
#* Column Headers *#
<tr class="contestantListHeaders">
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Phone</th>
</tr>
#* Content Rows *#
#foreach (var temp in Model.ContestantList)
{
<tr>
<td>#temp.mName</td>
<td>#temp.mSurName</td>
<td>#temp.mEmail</td>
<td>#temp.mCellPhone</td>
</tr>
}
</tbody>
</table>
</div>
Instead of this saying "Name: Contestant" "LastName: #1" etc etc
You will have a table:
First Name | Last Name | Email etc etc
Contestant | #1 | ...
.
.
.
I have tried to send data as a string and it is working correctly. but now i want to insert all gridview data as a list into database. Code is here
public interface IService1
{
[OperationContract]
string InsertCustomerDetails(UserDetails userInfo);
[OperationContract]
[WebGet]
List<CustomerTable> GetCustomers();
}
public class UserDetails
{
string Name = string.Empty;
string City = string.Empty;
[DataMember]
public string name
{
get { return Name; }
set { Name = value; }
}
[DataMember]
public string city
{
get { return City; }
set { City = value; }
}
public class Service1 : IService1
{
public string InsertCustomerDetails(UserDetails userInfo)
{
using(DataContext db=new DataContext())
{
CustomerTable customer = new CustomerTable();
customer.Name = userInfo.name;
customer.City = userInfo.city;
db.CustomerTables.Add(customer);
db.SaveChanges();
}
return "name= " + userInfo.name + " city= " + userInfo.city;
}
}
}
WEB Form Code
protected void ButtonADD_Click(object sender, EventArgs e)
{
for (int i = 0; i < GridView2.Rows.Count; i++) {
UserDetails info = new UserDetails();
info.name = GridView2.Rows[i].Cells[0].Text;
info.city = GridView2.Rows[i].Cells[1].Text;
obj.InsertCustomerDetails(info);
} }
In Iservice1 class use this
public List<CustomerTable> InsertCustomerDetails(UserDetails userInfo)
{
using(DataContext db=new DataContext())
{
CustomerTable customer = new CustomerTable();
customer.Name = userInfo.name;
customer.City = userInfo.city;
db.CustomerTables.Add(customer);
db.SaveChanges();
return db.CustomerTables.ToList();
}
Use this in interface. Make setter getters in class UserDetails
[OperationContract]
List<CustomerTable> InsertCustomerDetails(UserDetails userInfo);
I Have done this. Just facing problem in Web Form. Any Help will be appriciated. I want to send dqata as list into database
I have an ObjectDataSource, bind to static class state with all methods: select, update, insert, delete to work with instances of serviceRecord class. It looks fine. But when I bind it with GridView, GridView can`t find any serviceRecord property and auto generate columns. Without auto generation i have an exception: HttpException (0x80004005): A field or property with the name 'serviceStart' was not found on the selected data source.
<div style="text-align: center">
<asp:ObjectDataSource ID="ServiceRecordsDataSource" runat="server"
DataObjectTypeName="LaretsState.serviceRecord" TypeName="LaretsState.state"
DeleteMethod="deleteRecord" InsertMethod="addRecord"
SelectMethod="getRecords" UpdateMethod="updateRecord" >
</asp:ObjectDataSource>
<asp:GridView ID="GridView" runat="server" AutoGenerateColumns="False"
ObjectDataSourceId ="ServiceRecordsDataSource" DataSourceID="ServiceRecordsDataSource">
<Columns>
<asp:BoundField DataField="serviceStart" DataFormatString="dd:MM:yyyy hh:mm" HeaderText="Date and time of service" />
<asp:BoundField DataField="serviceDuration" DataFormatString="mm" HeaderText="Duration" />
<asp:BoundField DataField="creationTime" DataFormatString="dd.MM.yyyy hh.mm" HeaderText="Creation time" />
</Columns>
</asp:GridView>
The classes are:
namespace LaretsState
{
public static class state
{
public static actualState actualState
{ get { return new actualState(getActualState(), getNextRecord()); } }
private static List<serviceRecord> _plan = new List<serviceRecord>();
static state() { }
public static List<serviceRecord> getRecords()
{
return _plan;
}
public static void updateRecord(serviceRecord record)
{
serviceRecord newRecord = record;
lock (_plan)
{
serviceRecord oldRecord = _plan.Where(r=> r.id== record.id).FirstOrDefault();
if (oldRecord == null)
{ throw new ArgumentException("В плане отсутствует запись с id " + record.id, "recordid"); }
var ColissionRecords = GetCollisionRecords(newRecord);
if (ColissionRecords.Count() > 1 ||
ColissionRecords.Count() == 1 && !ColissionRecords.Contains(oldRecord))
{ throw new Exception("На предложенное время уже запланировано обслуживание"); }
oldRecord = newRecord;
//_plan.Remove(oldRecord);
//_plan.Add(newRecord);
}
}
public static void deleteRecord(serviceRecord record)
{
_plan.Remove(record);
}
public static void addRecord(serviceRecord record)
{
lock (_plan)
{
var ColissionRecords = GetCollisionRecords(record);
if (ColissionRecords.Count() > 1 )
{ throw new Exception("На предложенное время уже запланировано обслуживание"); }
_plan.Add(record);
}
}
private static List<serviceRecord> GetCollisionRecords (serviceRecord record)
{
return _plan.Where(r => r.serviceStart <= record.serviceStart.Add(record.serviceDuration)
&& r.serviceStart.Add(r.serviceDuration) > record.serviceStart).ToList();
}
private static serviceRecord getNextRecord()
{
DateTime nowdate = DateTime.Now;
if (_plan.Count() == 0) return null;
return _plan
.Where(r => r.serviceStart > nowdate)
.OrderBy(r => r.serviceStart)
.First();
}
private static serviceState getActualState()
{
DateTime nowDateTime = DateTime.Now;
var recordsInProgress = _plan.Where(r => r.serviceStart <= nowDateTime
&& r.serviceStart.Add(r.serviceDuration) > nowDateTime).Count();
if (recordsInProgress >0)
{ return serviceState.OnService; }
else
{ return serviceState.Normal; }
}
}
}
}
namespace LaretsState
{
[DataContract]
public class serviceRecord
{
private static int lastid = 0;
[DataMember]
public DateTime serviceStart;
[DataMember]
public TimeSpan serviceDuration;
[DataMember]
public readonly DateTime creationTime;
[DataMember]
public readonly int id;
public serviceRecord (DateTime serviceStart, TimeSpan serviceDuration)
:this()
{
this.serviceStart = serviceStart;
this.serviceDuration = serviceDuration;
}
public serviceRecord()
{
this.creationTime = DateTime.Now;
this.id = ++lastid;
}
}
}
Is it somthing wrong with a classes?
I found! In serviceRecord class I must use properties, not fields:
[DataMember]
public DateTime serviceStart { get; set; }
[DataMember]
public TimeSpan serviceDuration { get; set; }
[DataMember]
public DateTime creationTime { get;}
[DataMember]
public int id { get;}