How do I convert BindingSource.DataSource to my custom object? - c#

I have a custom dataset style class defined as:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace LibrarySort.Data
{
public class LibraryData
{
private AlbumList albums;
public AlbumList Albums { get { return albums; } }
public LibraryData()
{
this.albums = new AlbumList();
this.albums.AllowEdit = true;
this.Albums.AllowNew = true;
this.Albums.AllowRemove = true;
}
public void FillAll()
{
this.Albums.Fill();
}
}
public class AlbumList : BindingList<Album>
{
public AlbumList()
{
}
public void Fill()
{
int id = 1;
Album album1 = new Album();
album1.Id = id++;
album1.Artist = "Classical Piano Artist";
album1.Download = true;
album1.Person = null;
album1.Price = (decimal?)3.49;
album1.Tags.Add("classical");
album1.Tags.Add("piano");
album1.Title = "Classical Piano";
Album album2 = new Album();
album2.Id = id++;
album2.Artist = "Thrash Metal Artist";
album2.Download = false;
album2.Person = null;
album2.Price = (decimal?)7.99;
album2.Tags.Add("thrash metal");
album2.Title = "Thrash Metal";
this.Items.Add(album1);
this.Items.Add(album2);
}
}
}
I also a have Form object that inside a TabControl has a DataGridView. In the designer, I created a BindingSource and used the Add Project Data Source to create a source from the top level LibraryData object. I then bind the DataGridView to the "Albums" data member, all in the designer, and the columns get populated in the designer as expected.
When running the code, the table isn't populated, which makes sense as the Fill() hasn't been run. So I create a Load event handler for the form as follows:
private void MainForm_Load(object sender, EventArgs e)
{
LibraryData data = (LibraryData)bindingSource.DataSource;
data.FillAll();
}
However on run I get the following in MainForm_Load():
System.InvalidCastException was unhandled
Message="Unable to cast object of type 'System.RuntimeType' to type 'LibrarySort.Data.LibraryData'
I've Googled extensively on this, and in StackOverflow but no luck. Am I missing something?
Update: DataSource is definitely non-null. Also interestingly, in the designer code I see this:
this.bindingSource.DataSource = typeof(LibrarySort.Data.LibraryData);
Update 2: Album class and parent Item:
namespace LibrarySort.Data
{
public class Album : Item
{
bool download = false;
public bool Download { get { return download; } set { download = value; } }
string artist = null;
public string Artist { get { return artist; } set { artist = value; } }
}
}
namespace LibrarySort.Data
{
public class Item
{
int id = -1;
public int Id { get { return id; } set { id = value; } }
// FK to Person that currently has possession of item
int? person = null;
public int? Person { get { return person; } set { person = value; } }
string title = null;
public string Title { get { return title; } set { title = value; } }
decimal? price = null;
public decimal? Price { get { return price; } set { price = value; } }
State state = State.Owned;
public State State { get { return state; } set { state = value; } }
List<string> tags = null;
public List<string> Tags
{
get
{
if (tags == null)
tags = new List<string>();
return tags;
}
// No set needed
}
}
}

I think the issue is that although you have a binding source on your form, you have not set the datasource of the binding source.
Assuming that bindingSource is the datasource you dropped on your form, then try the following in the MainForm_Load:
LibraryData data = new LibraryData();
data.FillAll();
bindingSource.DataSource = data;

Related

Little complex Databinding in windows form combobox

I am in trouble while working on Databinding in windows form. I have two classes, one is Project and another is Update. Now all project object is having a list of Updates and it is binded to a combobox, but when the user changes selection need to display/bind the properties of Update object to another controls. But is not updating as expected, when the user changes selection. Please help me on this..
Screenshot
See my class and codes below,
public class Project
{
private int _id;
private string _name;
public Project(int id, string name)
{
_id = id;
_name = name;
ReadUpdates();
}
public List<Update> AvailableUpdates { get; set; }
public int Id { get { return _id; } }
public string ProjName
{
get { return _name; }
set { _name = value; }
}
private void ReadUpdates()
{
AvailableUpdates = new List<Update>();
for (int i = 0; i < 10; i++)
{
AvailableUpdates.Add(new
Update(i, DateTime.Now.AddDays(i)));
}
}
}
public class Update
{
private string _title;
private int _uid;
private DateTime _updatedOn;
public Update(int id, DateTime updatedOn)
{
_title = $"Update:{id}";
_uid = id;
_updatedOn = updatedOn;
}
public string Title
{
get { return _title; }
set { _title = value; }
}
public int UId
{
get { return _uid; }
set { _uid = value; }
}
public DateTime UpdatedOn
{
get { return _updatedOn; }
set { _updatedOn = value; }
}
}
public partial class Form1 : Form
{
private Update _currentUpdate;
private Project _project;
public Form1()
{
InitializeComponent();
_project = new Project(1, "Sample Project");
DoBindings();
}
private void DoBindings()
{
NameBox.DataBindings.Add("Text", _project, "ProjName");
IdBox.DataBindings.Add("Text", _project, "Id");
UpdatesCombo.DataSource = _project.AvailableUpdates;
UpdatesCombo.DisplayMember = "UId";
_currentUpdate = (Update)UpdatesCombo.SelectedItem;
UpdateTitle.DataBindings.Add("Text", _currentUpdate, "Title");
UpdateDate.DataBindings.Add("Value", _currentUpdate, "UpdatedOn");
}
private void UpdatesCombo_SelectionChangeCommitted(object sender, System.EventArgs e)
{
_currentUpdate = (Update)UpdatesCombo.SelectedItem;
}
}
Please correct me if I am wrong.
It's quite simple. All you need is to bind the related controls to the same list data source as the combo box.
var updates = _project.AvailableUpdates;
UpdatesCombo.DataSource = updates;
UpdatesCombo.DisplayMember = "UId";
UpdateTitle.DataBindings.Add("Text", updates, "Title");
UpdateDate.DataBindings.Add("Value", updates, "UpdatedOn");
The data binging infrastructure creates CurrencyManager class per each unique list data source. The non list controls are actually bound to the Current property, which is updated by the combo box selection.

linq update not working

I have tried a lot but all in vain.
I have written a LINQ code but not able to save changes in database.
It is giving no error neither it is updating record.
class Program
{
[Table(Name = "mainframe_replication")]
public class mainframe_replication
{
private string _REPL_GUID;
[Column(IsPrimaryKey = true, Storage = "_REPL_GUID")]
public string REPL_GUID
{
get { return this._REPL_GUID; }
set { this._REPL_GUID = value; }
}
private string _REPL_TYPE;
[Column(Storage = "_REPL_TYPE")]
public string REPL_TYPE
{
get { return this._REPL_TYPE; }
set { this._REPL_TYPE = value; }
}
private string _RPT_ID;
[Column(Storage = "_RPT_ID")]
public string RPT_ID
{
get { return this._RPT_ID; }
set { this._RPT_ID = value; }
}
private string _RPT_VERS;
[Column(Storage = "_RPT_VERS")]
public string RPT_VERS
{
get { return this._RPT_VERS; }
set { this._RPT_VERS = value; }
}
private string _RPT_BYTES;
[Column(Storage = "_RPT_BYTES")]
public string RPT_BYTES
{
get { return this._RPT_BYTES; }
set { this._RPT_BYTES = value; }
}
private string _REPL_DTM;
[Column(Storage = "_REPL_DTM")]
public string REPL_DTM
{
get { return this._REPL_DTM; }
set { this._REPL_DTM = value; }
}
private string _NOTIF_ID;
[Column(Storage = "_NOTIF_ID")]
public string NOTIF_ID
{
get { return this._NOTIF_ID; }
set { this._NOTIF_ID = value; }
}
}
public class MyPoco
{
public string ReportId { get; set; }
public string Reportversion { get; set; }
public string ReportBytes { get; set; }
public string ReportDate { get; set; }
public string NotifId { get; set; }
public string RecipAdd { get; set; }
}
public static string loglocation;
static void Main(string[] args)
{
try
{
using (DataClasses1DataContext db = new DataClasses1DataContext())
{
Table<NOTIF_RECIP> NOTIF_RECIP_alias = db.GetTable<NOTIF_RECIP>();
Table<NOTIF_SCHED> NOTIF_SCHED_alias = db.GetTable<NOTIF_SCHED>();
Table<mainframe_replication> mainframe_replication_alias = db.GetTable<mainframe_replication>();
var ids = NOTIF_SCHED_alias.Select(x => x.NOTIF_RPT_ID).ToArray();
foreach (string notif_sched_data in ids)
{
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias, mfr => mfr.RPT_ID, nr => nr.NOTIF_RECIP_ID, (mfr, nr)
=> new MyPoco { ReportId = mfr.RPT_ID, Reportversion = mfr.RPT_VERS, ReportBytes = mfr.RPT_BYTES.ToString(), ReportDate = mfr.REPL_DTM.ToString(), NotifId = mfr.NOTIF_ID, RecipAdd = nr.NOTIF_RECIP_ADDR });
foreach (var repljoinmf_data in repljoinmf)
{
repljoinmf_data.NotifId = "abc";
//DO STUFF
// repljoinmf_data.NotifId = "Changedxyz";
}
db.SubmitChanges();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
It is not giving any error while submitting changes.
What I need to change?
Any suggestion will be helpful.
If you want to save your changes back to the original data source, you need to be working with the actual entities instead of projections of those entities. Since you are joining two tables, one option is to put those instances into an anonymous type and update them:
foreach (string notif_sched_data in ids)
{
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias,
mfr => mfr.RPT_ID,
nr => nr.NOTIF_RECIP_ID,
(mfr, nr) => new {mfr, nr});
foreach (var repljoinmf_data in repljoinmf)
{
//DO STUFF
repljoinmf_data.mfr.NotifId = "Changedxyz";
}
db.SubmitChanges();
In your previous question you were told that anonymous types cannot be uptated, but in this case you're modifying instances that are referenced by the anonymous type. So you're not updating the anonymous type itself, just the objects that the anonymous type references.
You are modifying the property of your MyPoco object. This is just a representation of your table. That's why the database is not updated.
You can send your MyPoco to your client. It will perform some changes. Then you can recreate the entity and copy the properties from the Poco object. Then, you need to attach the modified entity to your table and then save the changes.
If you modify directly the entity, there is no need to attach, since it will have kept the links to the database (assuming you do that with the same Databasecontext).

Query Object Structure using string input

I'm trying to find a clean way to allow input of a string that can then query an object structure. I think a dynamic linq query is what I want but I can't figure out how to implement this.
The user would input a string like
relationship.IsHappy = true
or
relationship.Type = "Uncle"
or
relationship.Type = "Uncle" && relationship.IsHappy = true
The last two lines in main() are what I'm trying to find a solution for:
string zQuery = args[0];
me.Realtionships.Where(zQuery);
Complete code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Dynamic;
namespace LinqTest1
{
class Program
{
static void Main(string[] args)
{
person me = new person();
me.FirstName = "Andy";
me.Realtionships = new List<relationship>();
person aunt = new person();
aunt.FirstName = "Lucy";
relationship rAunt = new relationship();
rAunt.IsHappy = true;
rAunt.Type = "Aunt";
rAunt.Person = aunt;
me.Realtionships.Add(rAunt);
person uncle = new person();
uncle.FirstName = "Bob";
relationship rUncle = new relationship();
rUncle.IsHappy = false;
rUncle.Type = "Aunt";
rUncle.Person = uncle;
me.Realtionships.Add(rUncle);
string zQuery = args[0];
me.Realtionships.Where(zQuery);
}
}
public class person
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
private List<relationship> _realtionships;
public List<relationship> Realtionships
{
get { return _realtionships; }
set { _realtionships = value; }
}
}
public class relationship
{
private string _type;
public string Type
{
get { return _type; }
set { _type = value; }
}
private bool _isHappy;
public bool IsHappy
{
get { return _isHappy; }
set { _isHappy = value; }
}
private person _person;
public person Person
{
get { return _person; }
set { _person = value; }
}
}
}
you can use :
Dynamic expression trees Inbuilt libraries
or
Dynamic Linq queries A microsoft library with source and examples you can download.
Constructing an expression tree is a little more involved but ultimately more powerful. And you will eat and sleep Lambda when your have finished.
The Dynamic Linq library allows you to pass strings to a tool that parses the strings and creates Lambda expressions. This is easier to use.
There is a library called dynamic Linq: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx that allows you to use Strings instead of expression trees for Linq queries.
We did this with an expression tree serializer/deserializer. I believe in your case you just need to deserialize the passed in string, we used this http://expressiontree.codeplex.com/
Thanks. The piece I was missing was AsQueryable(). See solution below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Dynamic;
namespace LinqTest1
{
class Program
{
static void Main(string[] args)
{
person me = new person();
me.FirstName = "Andy";
me.Realtionships = new List<relationship>();
person aunt = new person();
aunt.FirstName = "Lucy";
relationship rAunt = new relationship();
rAunt.IsHappy = true;
rAunt.Type = "Aunt";
rAunt.Person = aunt;
me.Realtionships.Add(rAunt);
person uncle = new person();
uncle.FirstName = "Bob";
relationship rUncle = new relationship();
rUncle.IsHappy = false;
rUncle.Type = "Uncle";
rUncle.Person = uncle;
me.Realtionships.Add(rUncle);
//string zQuery = args[0];
var res = me.Realtionships.AsQueryable().Where("Type == \"Uncle\"");
foreach (relationship item in res)
{
Console.WriteLine(item.Person.FirstName);
}
Console.ReadLine();
}
}
public class person
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
private List<relationship> _realtionships;
public List<relationship> Realtionships
{
get { return _realtionships; }
set { _realtionships = value; }
}
}
public class relationship : IEnumerable<relationship>
{
private string _type;
public string Type
{
get { return _type; }
set { _type = value; }
}
private bool _isHappy;
public bool IsHappy
{
get { return _isHappy; }
set { _isHappy = value; }
}
private person _person;
public person Person
{
get { return _person; }
set { _person = value; }
}
public IEnumerator<relationship> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}

Item is not being remove from list

Item is not being remove from list
here is my code:
public interface IEmpConnection
{
int SegId { get; set; }
}
public class EmpConnection : IEmpConnection
{
private int segid;
public int SegId
{
get
{
return segid;
}
set
{
segid = value;
}
}
}
public class CustomerConnection : EmpConnection, ICustomerConnection
{
private int _id;
public int Id
{
get
{
return _id;
}
set
{
_id = value;
}
}
}
public interface ICustomerConnection
{
int Id { get; set; }
}
public class CustConn : CustomerConnection
{
private ObservableCollection<CustomerConnection> _airSeg;
public CustConn()
{
_airSeg = new System.Collections.ObjectModel.ObservableCollection<CustomerConnection>();
_airSeg.Add(new AirSegmentConnection { Id = 1, SegId = 2 });
_airSeg.Add(new AirSegmentConnection { Id = 1, SegId = 3 });
}
private bool isDeleted;
public bool IsDeleted
{
get { return isDeleted; }
set { isDeleted = value; }
}
private List<IEmpConnection> _connection;
public List<IEmpConnection> Connections
{
get
{
var s = new AirSegmentConnection();
var k = s as ISegmentConnection;
if (IsDeleted)
{
_airSeg.RemoveAt(1);
}
return _connection = _airSeg.ToList().Cast<ISegmentConnection>().ToList();
//return _airSeg.ToList().Cast<ISegmentConnection>().ToList();
}
set
{
_connection = value;
//_airSeg = new System.Collections.ObjectModel.ObservableCollection<ISegmentConnection>(value.ToList()) ;
}
}
private ObservableCollection<CustomerConnection> airConnection;
public ObservableCollection<CustomerConnection> AirConnection
{
get { return _airSeg; }
set { _airSeg = value; }
}
}
on main
button click item is not being removed. please suggest me where i am doing wrong.
CustConn a = new CustConn();
if (a.Connections.Count > 0)
{
a.Connections = new List<IEmpConnection>();
a.Connections.RemoveAt(1);// this item is not being removed.
}
please suggest i am doing worng in this code.
Thanks
Amit
It seems that you are replacing the list of connections before you remove the connection.
Since you have this marked as WPF, I'm going to assume that at some point you were able to remove the item from the List, but it still appeared on the screen. Try this:
if (a.Connections.Count > 0)
{
var newList = new List<IEmpConnection>(a.Connections);
a.Connections.RemoveAt(1);
a.Connections = newList;
}
Alternatively, you may be able to use an ObservableCollection<IEmpConnection>. This is a special collection that raises events when the collection changes. Then you would simple remove the object, and the screen would update.
You're creating a new, empty list and then trying to remove an element at position 1. In fact you've just overwritten your original list.
if (a.Connections.Count > 0)
{
/// REMOVE THIS LINE a.Connections = new List<IEmpConnection>();
a.Connections.RemoveAt(1);// this item is not being removed.
}
The line I've commented out it creating a new list and overwriting a.Connections immediately before you try to remove the item. This is what's causing the code to fail.

WPF ComboBox Databound to a class

Should it be possible to bind a WPF combo box to a class. I have a class that implements IEmunerable and IEnumerator, and contains a list of objects, as follows:
class MyClass
{
public string Title { get; set; }
public string Directory { get; set; }
public MyClass(string title, string directory)
{
Title = title;
Directory = directory;
}
}
class MyClasses : IEnumerable, IEnumerator
{
private List<MyClass> allClasses;
private int position = 0;
public List<MyClass> GetClasses()
{
allClasses = new List<MyClass>()
{
new MyClass("example1", "dir1"),
new MyClass("example2", "dir2")
};
return allClasses;
}
public IEnumerator GetEnumerator()
{
return (IEnumerator) this;
}
public object Current
{
get
{
return allClasses[position];
}
}
public bool MoveNext()
{
position++;
return (position < allClasses.Count());
}
public void Reset()
{
position = -1;
}
}
So now I want to bind this to a WPF combobox. Here’s what I have, which doesn’t work (I instead get a list of type names of the objects):
allClasses.GetClasses();
cboTest.ItemsSource = allClasses;
cboTitle.SelectedValue = "Title";
Can anyone tell me how to implement this binding?
cboTitle.SelectedValue = "Title";
should be
cboTitle.DisplayMemberPath = "Title";
Change
cboTitle.SelectedValue = "Title";
to
cboTitle.DisplayMemberPath = "Title";

Categories

Resources