I have a application im working on that uses the Jabber Libraries to connect to a jabber Server and receive contacts etc.
I have buit all login system and interface for the chat but now im working on how to Bind the data for the contacts to the ListView
I have a function that is called when a contact comes online such, See Below
//AppController.cs
public void XmppConnection_OnRosterItem(Object Sender, RosterItem RosterItem)
{
if (LoginWindow.ActiveForm.InvokeRequired)
{
LoginWindow.ActiveForm.BeginInvoke(
new XmppClientConnection.RosterHandler(XmppConnection_OnRosterItem),
new object[] { Sender, RosterItem}
);
return;
}
//UPDATE HERE
}
The idea is to have a class such as ContactList so that when the above function is called i can go ContactList.AddRoster(Roster);
What i need to know is how do I create a custom list class and then bind it to the the Form witch holds the ListView element
And if possible set an update interval to recompile the ListVeiw?
Hope you guys can help me
Edit:
If I could have 2 classes one for the individual contact and one to hold the collection like so:
Contact C = new Contact(Roster.Name,Roster.Jid,Roster.Group);
ContactList.Add(C);
This as well would be good.
You could create a Contact class the just create a List of Contacts
List<Contact> ContactList=new List<Contact>();
ContactList.Add(Roster);
How to Bind ListView to List
http://www.vistax64.com/avalon/615-how-bind-listview-list-mystruct.html
Not sure about the update interval though. Attach it to a certain event and check the time in between maybe? MouseMove (Performance Cost?)
Anyone else have any ideas?
EDIT:
class ContactList:List<Contact>
{
public ContactList()
{
}
}
You shouldn't need to add anything to this class
class Contact
{
public string _Name;
public string _Jid;
public string _Group;
public Contact()
{
_Name = "Test";
_Jid = "One";
_Group = "Two";
}
public Contact(string Name, string Jid, string Group)
{
_Name = Name;
_Jid = Jid;
_Group = Group;
}
public override string ToString()
{
return _Name+" "+_Jid+" "+_Group;
}
}
Overiding the ToString function allows you easier control over what is displayed in the listbox
public Form1()
{
InitializeComponent();
ContactList C = new ContactList();
C.Add(new Contact("Name","Jid","Group"));
C.Add(new Contact());
C.Add(new Contact("Test","2","Something"));
for (int i = 0; i < C.Count; i++)
{
listView1.Items.Add(C[i].ToString());
}
}
Let me know if this works for you.
Related
I'm building an application in which I run the following code to display the results in a listbox from an API call. Link below directs to full extent of script that runs app.
https://dotnetfiddle.net/gFL2M0
I am able to get the results from the API call, match them to Class1 properties, and display them in the listbox.
Nevertheless, I want to bind the EntryID property results to the values displayed in the listbox because once the user presses the button upon a selected value, I'm looking to get that value to run another command of another method or within the button's method itself.
This is where I'm here asking y'all for help (binding the API's parsed EntryID results to the selected values (displayed members)) of the listbox.
Two things:
The route I pursued to call and parse the API data is one I chose based on my current knowledge of C#. I apologize if this method is making this much more difficult. I'm still new to C#.
If you take a look at the link above, I will eventually make the API call a class of its own. I just went ahead and provided it twice in the script for context reasons.
Here's the code at the part of the button. Thank you in advance for the help!
private void Button_Click(object sender, RoutedEventArgs e)
{
StarRezApiClient call2 = new StarRezApiClient("BaseURL", "UserName", "Password");
var selection = call2.Select("Entry", Criteria.Equals("NameLast", "Rincon Recio"));
var transfer = JsonConvert.SerializeObject(selection);
var output = JsonConvert.DeserializeObject<Class1[]>(transfer);
foreach (var id in output)
{
testListBox.SelectedItem.Equals(id.EntryID);
///Assigns SelectedItem of ListBox to EntryID [WHERE I NEED HELP PLEASE]
}
//TODO
//MessageBox.Show(SelectedValue.ToString()); for testing
//System.Diagnostics.Process.Start("BaseURL?EntryID=" + SelectedItem); takes user to webpage of api results
}
https://dotnetfiddle.net/yq45jU --- Class Properties
https://codebeautify.org/jsonviewer/cbfb31d2 --- Json Results
Answer
You want to add instances of Class1 to your listbox, not just the text display. Which for proper display in a listbox wants the .ToString() method overridden.
Line 34 in your fiddle shows testListBox.Items.Add(name.NameFirst + ' ' + name.NameLast);
which should be testListBox.Items.Add(name);
The second part is making Class1 whose code you did not include have a method like the following
public override string ToString()
{
return this.NameFirst + ' ' + this.NameLast;
}
Side note
I use a wrapper access around listboxes or comboboxes like so for easier type-safe access.
I flesh out the interfaces as needed and fallback to direct access where strong doesn't necessarily make things any simpler.
public class ListBoxT<T>
{
readonly ListBox _lb;
public T SelectedItem { get => (T)_lb.SelectedItem; set => _lb.SelectedItem = value; }
public void AddItem(T item) => _lb.Items.Add(item);
public ListBoxT(ListBox lb) => this._lb = lb;
}
public class ComboBoxT<T>
{
readonly ComboBox _cb;
public ComboBoxT(ComboBox cb) => this._cb = cb;
public T SelectedItem { get => (T)_cb.SelectedItem; set => _cb.SelectedItem = value; }
public Rectangle Bounds => this._cb.Bounds;
public int Count => this._cb.Items.Count;
public IReadOnlyCollection<T> Items { get => new ReadOnlyCollection<T>(_cb.Items.Cast<T>().ToList()); }
public void BeginUpdate() => _cb.BeginUpdate();
public void Clear() => _cb.Items.Clear();
public void AddRange(IEnumerable<T> items)
{
_cb.SuspendLayout();
_cb.Items.AddRange(items.Cast<object>().ToArray());
_cb.ResumeLayout();
}
public void EndUpdate() => _cb.EndUpdate();
public bool Enabled { get => _cb.Enabled; set => _cb.Enabled = value; }
public int SelectedIndex { get => _cb.SelectedIndex; set => _cb.SelectedIndex = value; }
public ComboBox Value => _cb;
public T this[int x]
{
get => (T)this._cb.Items[x];
set => this._cb.Items[x] = value;
}
}
Here is a simple example. As Maslow noted, you should first add objects of Class1 to your list, not plain strings. Then, you simply add the items that match your search criteria to the SelectedItems collection:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
<Grid>
<ListBox Name="list" />
</Grid>
</Window>
class Class1
{
public int EntryID { get; set; }
public string NameFirst { get; set; }
public string NameLast { get; set; }
public override string ToString()
{
return NameFirst;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
list.SelectionMode = SelectionMode.Multiple;
//fill list with dummy items
var items = new Class1[10];
for(int i = 0; i < 10; ++i)
items[i] = new Class1() { EntryID = i, NameFirst = ((char)('A' + (char)i)).ToString() };
list.ItemsSource = items;
//simulate second API call
var selection = new Class1[3];
selection[0] = new Class1() { EntryID = 3 };
selection[1] = new Class1() { EntryID = 4 };
selection[2] = new Class1() { EntryID = 8 };
list.SelectedItems.Clear();
foreach (var sel in selection)
foreach (var item in items.Where(i => i.EntryID == sel.EntryID))
list.SelectedItems.Add(item);
}
}
Instead of arrays, you might want to employ more flexible or more efficient data structures like List<Class1> or Dictionary<int, Class1>. I.e., when you get your result as an array, simply fill in these data structures from it. If you have a dictionary, you can directly get the element with a specific key instead of using the LINQ query (.Where(...)).
Btw, please do not use .Net Fiddle to simply add more code to your question. The question should be self-contained and show all relevant code. .Net Fiddles can be used as supplementary material to link to a running example. However, linking to a non-compiling fiddle is just making your question harder to follow.
Step 1: I have created a C# application called : Student details
Step 2: Added four TextBoxes and named them as :
Image below to refer:
Studentname.Text
StudentSurname.Text
StudentCity.Text
StudentState.Text
DATA INSIDE CSV FILE
vikas,gadhi,mumbai,maharashtra
prem,yogi,kolkata,maha
roja,goal,orissa,oya
ram,kala,goa,barka
Issue is How do I fetch all the data(surname,city,state) of user prem into above textboxes studentsurname,studentcity,studentstate from csv file when I search the name in textbox 1 => studentname.Text as prem
Below is the Code where I am stuck at return null and code inside Load_Script_Click
void Connection_fetch_details(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
if (line.Split(',')[0].Equals(searchName))
{
Connection_fetch_details cd = new Connection_fetch_details()
{
username = line.Split(',')[1]
};
}
}
return;
}
private void Load_Script_Click(object sender, EventArgs e)
{
// load script is button
String con_env = textenv.Text.ToString();
//Address Address = GetAddress("vikas");
//textsurname.text = Address.Surname
Connection_fetch_details cd = Connection_fetch_details(con_env);
textusername.Text = cd.username;
}
==============================================================
Class file name : Address.class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DDL_SCRIPT_GENERATOR
{
public class Connection_fetch_details
{
public string username { get; set; }
}
}
The main problem is that your method is void, which means it doesn't return any value. So even though you may be finding a match, and creating a Connection_fetch_details object, you aren't returning that result back to the calling method.
This will fix that problem:
Connection_fetch_details Connection_fetch_details(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
if (line.Split(',')[0].Equals(searchName))
{
Connection_fetch_details cd = new Connection_fetch_details()
{
username = line.Split(',')[1]
};
return cd; //return the object containing the matched username
}
}
return null;
}
Now it will return a Connection_fetch_details object if there is a match, or null if there is no match.
Next, you asked about returning all the fields, not just one. For that you would need to
a) add more properties to your object
b) add more code to populate those properties from the CSV
c) add code to populate the textboxes with the results from the object.
I'm also going to rename "username" to something more relevant, since none of the field names you described in the question match that. I'm also going to rename your class to "Student", and rename your search method, for the same reason.
Here's an example:
Student searchStudent(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
var split = line.Split(',');
if (split[0].Equals(searchName))
{
Student s = new Student()
{
firstname = searchName,
surname = split[1],
city = split[2],
state = split[3]
};
return s; //return the object containing the matched name
}
}
return null;
}
private void Load_Script_Click(object sender, EventArgs e)
{
// load script is button
String con_env = textenv.Text.ToString();
//Address Address = GetAddress("vikas");
//textsurname.text = Address.Surname
Student st = searchStudent(con_env);
textsurname.Text = st.surname;
txtcity.Text = st.city;
txtstate.Text = st.state;
}
namespace DDL_SCRIPT_GENERATOR
{
public class Student
{
public string firstname { get; set; }
public string surname { get; set; }
public string city { get; set; }
public string state { get; set; }
}
}
To accomplish your goal you have to further separate your problem in more granular steps and also distinguish between what you show in your UI and what informations you hold in the background in which format.
Create a class with the desired properties
public class Student { public string Name { get; set; } ... }
Learn how to read a csv file into such an object by using an existing library like CsvHelper or CsvReader.
When you have something like List<Student> from this part. Learn how you can visualize such a thing by using some Binding (also depends on the visualization you use Winforms, WPF, etc.).
Depending on the visualization component it already supports filtering or you need to filter by yourself by using e.g. LINQ to get the matching elements students.Where(student => student.Name.StartsWith(search)).
So far a lot of smaller problems which is simply to much to answer in a single one. Please try to break down your problems into smaller ones and search for their solutions. If you get stuck, ask a new question. That's all I can do for you now.
Edit to save you from reading through this whole post
tldr: an object's fields should not be static unless you want all instances of that object to have the same value for that field
I'm trying to create and populate an ArrayList of Blog objects. I do know the generic way do this:
create ArrayList of Blogs
loop (some condition)
create new Blog
add this Blog to AL
However, when I attempt to do so within the while(datareader.read()) loop, all of the elements in the ArrayList are exactly the same Blog. Specifically, I end up with an ArrayList filled with multiple pointers to the very last Blog object from the database table. Here is my code:
public static ArrayList AllBlogs()
{
SqlDataReader dr = anonPage.ExecuteReader("SELECT * FROM Kristina_Blogs");
ArrayList allBlogs = new ArrayList();
if (dr.HasRows)
{
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
}
dr.Close();
return allBlogs;
}
As I said before, the result of this is an ArrayList filled with pointers to the very last blog from the Kristina_Blogs table. I imagine the ArrayList allBlogs looks like [b, b, b, ... b] and therefore they ALL get updated when I say b.setTitle() etc. But how can this be the case if I am creating a NEW Blog object at the beginning of each iteration?
Here is some extra info that you don't have to read but it might clear up some confusion about the structure of the problem:
Blog object has id, title, and message fields and their respective getter/setters
Kristina_Blogs is a table representing these blogs with columns for id, title, message
The suggestions say to include a tag for my DB engine but I can't find a tag for it: Microsoft SQL Server Management Studio
This code works perfectly when I use an ArrayList of Strings instead of Blogs
Edit: Including the code from Blog class
public class Blog
{
public App myApp;
public static string Title;
public static string Message;
public static int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public string getTitle() { return Title; }
public void setTitle(string t) { Title = t; }
}
The main problem you have, as I mentioned in comments is your member variables are static, so when you set the value, they change in all instances. you should change your code this way:
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string Message { get; set; }
}
And fill your list this way, don't forget to add using System.Linq;:
var result = new List<Blog>();
var connection = #"your connection string";
var command = "SELECT * FROM Kristina_Blogs";
var adapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
var dataTable = new DataTable();
//Get data
adapter.Fill(dataTable);
dataTable.Rows.Cast<DataRow>().ToList()
.ForEach(row =>
{
var b = new Blog();
b.Id = row.Field<int>("Id");
b.Title = row.Field<string>("Title");
b.Message = row.Field<string>("Message");
result.Add(b);
});
return result;
Note:
When you create a member static, it is shared between all instances of that calss.
In C# you can use property to get or set values, you don't need to setX or setY, when you get the value of a property, the get code of that property will execute and when you assign a value to a property the set part of it will execute. you can define properties this way:
Property:
private int id;
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
or more simple:
public int Id { get; set; }
All of the fields in your Blog class are static, meaning they're shared between all object instances. You want them to be instance field (meaning not static) so that each object has its own copy of each of those values.
Remove the static attributes from your class:
public class Blog
{
public App myApp;
public String Title;
public String Message;
public int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public String getTitle() { return Title; }
public String getMessage() { return Message; }
public void setTitle(String t) { Title = t; }
public void setMessage(String m) { Message = m; }
}
When you use static variables, all instances of an object will contain the same values in those variables. By removing the static keyword, you are allowing different instances of the object to hold different values.
Now, every time you create a blog object, that object's Title and Message etc, will contain its own information.
I would make a quick method to prevent null value from throwing error
public static string GetSafeString(SqlDataReader reader, int index)
{
if (!reader.IsDBNull(index))
return reader.GetString(index);
else
return string.Empty;
}
Replace this code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
With This Code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setId(dr.GetInt32(0));
b.setTitle(GetSafeString(dr, 1);
b.setMessage(GetSafeString(dr, 2);
allBlogs.Add(b);
}
Where the number is the index of field in the record and assuming "id" is an integer. Also consider moving creation of "Blog" object outside of loop and just change values.
If I have a observablecollection in a page that inserts items on a listview. How can I add to that same observablecollection(listview) from a different window(class)? I do not want to use INotifyPropertyChanged and all that. All I'm trying to do is add a item to the existing listview. I have tried literally everything and I can't figure it out. Please any help is appreciated.
CampersPage...(BindingCamper is just my way of basically saying new ObservableCollection()
public partial class CampersPage : Page
{
MainWindow _parentForm;
public GridViewColumnHeader currentColumnSorted = null;
private SortAdorner currentAdorner = null;
String request1;
String request2;
String request3;
String request4;
// public ObservableCollection<Camper> Campers { get; private set; }
public CampersPage(MainWindow parent)
{
_parentForm = parent;
InitializeComponent();
_parentForm.bindings = new BindingCamper();
for (int i = 0; i < _parentForm.allCampers.Count; i++)
{
if (_parentForm.allCampers[i].getRequest(1) != null && _parentForm.allCampers[i].getRequest(2) != null && _parentForm.allCampers[i].getRequest(3) != null && _parentForm.allCampers[i].getRequest(4) != null)
{
request1 = _parentForm.allCampers[i].getRequest(1).getName();
request2 = _parentForm.allCampers[i].getRequest(2).getName();
request3 = _parentForm.allCampers[i].getRequest(3).getName();
request4 = _parentForm.allCampers[i].getRequest(4).getName();
}
_parentForm.bindings.Campers.Add(new Camper { FirstName = "" + _parentForm.allCampers[i].getFirstName(), LastName = "" + _parentForm.allCampers[i].getLastName(), Ages = _parentForm.allCampers[i].getAge(), SchoolGrade = _parentForm.allCampers[i].getGrade(), Gender = "" + _parentForm.allCampers[i].getGender(), bindingRequest1 = request1, bindingRequest2 = request2, bindingRequest3 = request3, bindingRequest4 = request4 });
//DataContext = _parentForm.bindings;
}
DataContext = _parentForm.bindings;
}
---Now I click on a button and a new window comes up where I would like to add a new camper to the listview in CampersPage.
public partial class AddNewCamper : Window
{
MainWindow _parentForm;
public AddNewCamper(MainWindow parentForm)
{
InitializeComponent();
_parentForm = parentForm;
// _parentForm.bindings = new BindingCamper();
}private void btnSubmitNewCamper_Click(object sender, RoutedEventArgs e)
{
String firstName = txtNewFirstName.Text;
String lastName = txtLastName.Text;
int age;
int grade;
String newage = comboNewAge.Text;
if (firstName != "" && lastName != "" && IsNumber(txtNewGrade.Text) && newage != "")
{
age = Convert.ToInt16(newage);
grade = Convert.ToInt16(txtNewGrade.Text);
// Create New Camper
Camper person = new Camper(age, grade, boxNewGender.Text, firstName, lastName);
_parentForm.allCampers.Add(person);
//This is just adding the camper to the listview. Not sure if it is actually adding it to the database.
_parentForm.bindings.Campers.Add(new Camper { FirstName = person.getFirstName(), LastName = person.getLastName(), Ages = person.getAge(), SchoolGrade = person.getGrade() });
//CampersPage p = new CampersPage(_parentForm);
DataContext = _parentForm.bindings;
Do I have to somehow add AddNewCamper's namespace to CampersPage's namespace in xaml?
<ListView HorizontalAlignment="Stretch" Margin="0,12" x:Name ="listViewCampers" ItemsSource="{Binding Campers}" DisplayMemberPath="bindMe" IsSynchronizedWithCurrentItem="True" Grid.Column="1">
ObservableCollection class:
public partial class BindingCamper
{ // This class assist in binding campers from listview to the textboxes on the camperspage
public ObservableCollection<Camper> Campers { get; set; }
public ObservableCollection<Staff> StaffMembers { get; set; }
public ObservableCollection<Schedule> schedule { get; set; }
public ObservableCollection<Group> Groups { get; set; }
public BindingCamper()
{
Campers = new ObservableCollection<Camper>();
StaffMembers = new ObservableCollection<Staff>();
schedule = new ObservableCollection<Schedule>();
Groups = new ObservableCollection<Group>();
}
I won't go as far as claiming you're using WPF wrong, but you're certainly making your life difficult. I suggest reading up a bit on MVVM pattern - it really makes WPF development easier (here's good starting article).
Approach you're using at the moment is not correct on several levels:
your windows/pages need to have way too much knowledge about each other to work properly
result of which, is dependency on parent form in your child windows (while what you really need is dependency on window context, which in fact is campers list)
you need to do too much manual notifications/setting up to achieve your goals (while WPF has great tools to do it automatically)
you seem to be exposing model (allCampers) through view (MainWindow)
All of this can be solved with a bit of redesigning:
Your views (Main, CampersPage, AddNewCamper) should be dependent on BindingCamper class (which essentially could be view model for them), not on each other
Same instance of BindingCamper should be set as DataContext for all of them
You should not add bindings manually (like you're doing now); all can (and should) be done from XAML
Having above in mind, your CampersPage class should look like this:
public partial class CampersPage : Page
{
public CampersPage(BindingCamper camper)
{
InitializeComponent();
DataContext = camper;
}
}
It should by no means initialize data for parent window and set it's binding. This is simply wrong.
Actually, this approach (providing data context through constructor) can be used in all your view classes (AddNewCamper and MainWindow too, probably).
Now, when you need campers page, say from your main window, it gets very easy:
public partial class MainWindow : Window
{
public void ShowCampers()
{
var campersPage = new CampersPage((BindingCampers) this.DataContext);
// show campersPage
}
}
It is the same with AddNewCamper window. Just pass it data context. When you add new camper, add it to BindingCamper.Campers list (which is available through data context):
// rest of the btnSubmitNewCamper_Click method elided
Camper person = new Camper(age, grade, boxNewGender.Text, firstName, lastName);
((BindingCamper)this.DataContext).Campers.Add(person);
That's all. Thanks to combined mechanisms of data binding and observable collection, this new element will immediately be visible both in MainWindow and CampersPage.
Edit:
Code to fetch campers from database should be wrapper with some kind of DAO object (as a part of DAL - I know, lot of ugly buzzwords, but luckily they are all related and fairly obvious). For example, you can have a class that will deal with getting campers from database:
public class CampersProvider
{
public IEnumerable<Camper> GetAllCampers()
{
// here you put all your code for DB interaction
// and simply return campers
}
}
To give you quick solution, you can once again pass CampersProvider to MainWindow constructor, call GetAllCampters method and build observable collection for BindingCamper. However, this is not very MVVM approach. Those stuff usually is handled by view model (yet another, separate class), which at the moment you don't have.
Code you posted requires quite some work, I think it won't be a bad idea if you read a bit about MVVM pattern and try to apply it to your application.
Hello guys i have collection :
public class ActionData
{
private int iD;
public int ID
{
get { return iD; }
set { iD = value; }
}
private string roomType;
public string RoomType
{
get { return roomType; }
set { roomType = value; }
}
}
like this
private void btnGridToExcel_Click(object sender, RoutedEventArgs e)
{
ExportExcel<ActionData, ActionDatas> exp = new ExportExcel<ActionData, ActionDatas>();
exp.GenerateReport();
ICollectionView view = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource);
exp.dataToPrint = (ActionDatas)view.SourceCollection;
exp.GenerateReport();
}
On this button click must export data to excel but i gives such error on exp.dataToPrint = (ActionDatas)view.SourceCollection;:
Unable to cast object of type 'System.Collections.ObjectModel.ObservableCollection`1[H_Pro.Logicstic+ActionData]' to type 'ActionDatas'.
Here is a some part of method which gets values
public class ActionDatas : List<ActionData> { }
#region toxls
public class ExportExcel<T, U>
where T : class
where U : List<T>
{
public List<T> dataToPrint;
does anyone have an idea why im getting such error?
The data from ActionDatas might be implicitly being assigned to SourceCollection (possibly in XAML) which is an ObservableCollection<> (not the same thing as a List<>). It being an ObservableCollection is a good thing, since collection changes will automatically notify the listening WPF UI.
You should be able to simply assign an ActionDatas, and transfer the elements:
exp.dataToPrint = new ActionDatas();
foreach(ActionData data in view.SourceCollection) {
exp.dataToPrint.Add(data);
}
Or something along those lines.
Update: If your datagrid ItemsSource is already an ActionDatas object, then you should assign it directly to the dataToPrint member, no need to put it in a view and then transfer back into a new collection.