C# - SQlite + Entity - Show items on a ListView - c#

Using Visual Studio 2015 and learning ORM with SQlite + Entity (WPF application)
My database with fields: ID and ShipType
I can populate a listView with the ShypType field:
private void button_Click(object sender, RoutedEventArgs e)
{
List<string> shipList = new List<string>();
using (var db = new ImperialFleetDBEntities())
{
shipList = (from g in db.ShipsType select g.ShipType).ToList();
db.Dispose();
}
listView.Items.Clear();
foreach (string str in shipList)
{
listView.Items.Add(str);
}
}
But I can't figure how to also diplay the ID field (g.ID on this example)
In this link C# ListView Display the solution is using ListViewSubItems
But If I type listView. I don't have any SubItems option
The solution is 5 years old, maybe that's de problem??

The simplest way would probably be:
private void button_Click(object sender, RoutedEventArgs e)
{
using (var db = new ImperialFleetDBEntities())
{
listView.Items.Clear();
foreach(var item in (from g in db.ShipsType select new { ID = g.ID, ShipType = g.ShipType }))
{
listView.Items.Add(item)
}
}
}
This should populate your listView in correct way and make sure these new objects won't be tracked by EF.
If you'd like, you could create full class, like ViewModel for listView containing fields you need and then select to them like:
foreach(var item in (from g in db.ShipsType select new NewShipType { ID = g.ID, ShipType = g.ShipType }))
{
listView.Items.Add(item)
}
or using constructor (if you make one).
With seprate ViewModel you can of course use in-between list object and clear and add them to listView.Items, which is impossible with anonymous object.
By the way, you don't have, and maybe you shouldn't write db.Dispose() inside using clause, as using is exactly meant to make sure the object inside is disposed - you cannot use using on object that is not implementing IDisposable interface.

Related

C# CheckedListBox how to manipulate checked data?

Hey guys new to C# and I am trying to setup a GUI, all I want the GUI to do is have a simple file explorer with a CheckedListBox to represent selected files.
I can get the CheckedListBox to show up and click on files but I'm not sure how to continue from here, most tutorials stop here, or go too advanced with tree view and other things that seem unnecessary for what I am trying to do.
Here is my code:
Any help is appreciated and if you guys could point me in the right direction that would be awesome.
EDIT:
To rephrase my question:
I want the user to select files through the CheckedListBox (user input stops here), and for those selected files to be put in a list that my code can manipulate.
Not sure how to accomplish this after my first foreach loop (which adds all files in the selected directory to the CheckedListBox for user selection).
The second foreach loop is an attempt at this, manipulating the files so that they output their filenames after being selected. However no Messagebox shows up and I assume that their is a disconnect between the user selecting files and the codes attempt at manipulating said files.
Second Edit:
I think I figured it out I made a second button and from here it looks like I can manipulate the chosen files however I want.
Currently the code is working the way I would expect it to work.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace SelectFiles
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
checkedListBox1.CheckOnClick = true;
}
private void button1_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
MessageBox.Show(fbd.SelectedPath);
checkedListBox1.Items.Clear();
string[] files = Directory.GetFiles(fbd.SelectedPath);
foreach (string file in files)
{
checkedListBox1.Items.Add(file);
}
}
private void button2_Click_1(object sender, EventArgs e)
{
List<string> list_all_excelfiles = new List<string>();
foreach (string item in checkedListBox1.CheckedItems)
{
list_all_excelfiles.Add(item);
MessageBox.Show(Path.GetFileName(item));
}
}
}
}
First i advice you to assign Value member and Display member for each item.
Display Member will be visible to user
Value Member will we use in code
To do this first create simple custom class
public class Int_String
{
public int _int { get; set; }
public string _string { get; set; }
}
Be careful because get; set; part is important to be there since if not code will not work
Now what you need to do is create list of items with custom class like this
class YourForm : Form
{
List<Int_String> myList = new List<Int_String>(); //Create list of our custom class
public YourForm()
{
PopulateMyList();
}
private void PopulateMyList()
{
//Here read from database or get data somehow and populate our list like this
//I will populate it manually but you do it in foreach loop
myList.Add(new Int_String { _int = 0, _string = "First Item" });
myList.Add(new Int_String { _int = 1, _string = "Second Item" });
myList.Add(new Int_String { _int = 2, _string = "Third Item" });
}
}
After that you need to assign this list to your checkedListBox which you will do like this:
public YourForm()
{
PopulateMyList();
checkedListBox1.DataSource = myList;
checkedListBox1.DisplayMember = "_string";
checkedListBox1.ValueMember = "_int";
}
And now when you can manipulate with checked items like this:
for(int i = 0; i < checkedListBox1.Items.Count; i++)
{
if(checkedListBox1.Items[i].CheckedState == CheckState.Checked)
{
int itemValueMember = (checkedListBox1.Items[i] as Int_String)._int;
int itemDisplayMember = (checkedListBox1.Items[i] as Int_String)._string;
//Use these two vars for whatever you need
}
}
TWO IMPORTANT TIPS:
I am not sure for this one since i am writing all this from head but i think that visual studio will not show you that there is DisplayMember or ValueMember for checkedBox component BUT also it will not show error. Reason is that they have hidden in intentionally for idk what reason but it will work.
You are able to assign Display and Value member to a lot of components in winforms BUT for some reason checkedListBox is specific. It is specific because you MUST first assign DataSource to it and then tell it checkedListBox.DisplayMember = "_string" ...... For new guy you will ask why it is important. Simple answer is create custom list for test and add 10k items inside it and then first declare datasource and after it Display and Value member. Test how long form will need to load (get out of freeze state). After that do everything same but first declare Display and Value member and then assign datasource and test again. I am telling this from head without testing but before when i needed about 5k rows with 1st solution it took me about 30 sec and second < 1 sec. If you want to know more about it google it but for now this is pretty much info for you.

Show data from related table in a data grid upon selecting a data grid row in WPF

I have two tables, Equipment and Components. Each Equipment consists of 1 or more components. Right now I have a data grid showing the Equipment, with related attributes from a View in my database.
What I want is to have a second data grid in the same window, which will show the component the selected Equipment in the data grid contains.
So far I know that I can get a selected row using the SelectedItem property:
Equipment eq= (Equipment )myDataGrid.SelectedItem;
But when should this code be run? I am using EF to map my DB entities to CLR objects, where I have included the component and its relation table as well.
When the user selects a row in the Equipment, of course I would need to refresh the component data grid with the new info, which I can do like this.
myGrid.ItemsSource = myDataSource;
How can I get started on this problem?
I am using a view, that includes data from 3 different tables in my Equipment data grid, so the table set to the data grid ItemsSource does not have a direct relation with the component table.
I fixed it by using getting the components and inserted them into the data grid when the SelectionChanged event on the Equipment data grid is called:
private void EquipDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
var row_list = GetDataGridRows(EquipDataGrid);
foreach (DataGridRow single_row in row_list)
{
if (single_row.IsSelected == true)
{
EquipmentView selectedEquipment = (EquipmentView)EquipDataGrid.SelectedItem;
using (wiki_nolek_dk_dbEntities db = new wiki_nolek_dk_dbEntities())
{
db.Configuration.LazyLoadingEnabled = true;
var equipmentRelation = db.EquipmentComponents.Where(c => c.EquipmentID == selectedEquipment.EquipmentId);
var componentsForEquipment = new List<Component>();
foreach (var row in equipmentRelation)
{
var component = db.Components.FirstOrDefault(c => c.ComponentId == row.ComponentID);
componentsForEquipment.Add(component);
}
CompDataGrid.ItemsSource = componentsForEquipment;
}
}
}
}
catch
{
MessageBox.Show("Det valgte udstyr eksisterer ikke.");
}
}
I have modified your own reply's code to remove useless foreach loop.I don't know how wiki_nolek_dk_dbEntities works exactly, but I'm also adding ToList() to any db query result to make sure the result is a List and not an IQueryable.
private void EquipDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
EquipmentView selectedEquipment = (EquipmentView)EquipDataGrid.SelectedItem;
using (wiki_nolek_dk_dbEntities db = new wiki_nolek_dk_dbEntities())
{
db.Configuration.LazyLoadingEnabled = true;
var equipmentRelationComponentIds =
db.EquipmentComponents
.Where(e => e.EquipmentID == selectedEquipment.EquipmentId)
.Select(e => e.ComponentId)
.ToList();
var componentsForEquipment =
db.Components
.Where(c => equipmentRelationComponentIds.Contains(c.ComponentId))
.ToList();
CompDataGrid.ItemsSource = componentsForEquipment;
}
}
catch
{
MessageBox.Show("Det valgte udstyr eksisterer ikke.");
}
}

Showing information form from two tables

I'm writing a course selection program using WPF and Entity Framework 6. In my database I have three tables one for students who wish to select a course, one for the information about the courses (name of the course, start time, etc) and one for the information about the instructors. I have a section in my program that lists all the courses with the corresponding data about each of them but because the instructors exist in a different table I am not able to show them in my ListView in other word I have problem in joining data of two table and show them in a single ListView:
and this is my code for showing the data of a course in a ListView which so far I'm unable to show the instructor due to the problem explained above
private void button_Click(object sender, RoutedEventArgs e)
{
using (var context = new Model1Container())
{
var course_List = new List<course>();
foreach (var course in context.courses)
{
course_List.Add(course);
}
listView.ItemsSource = course_List;
}
}
You have a one to many relationship between Course and Instructor, so, en Course entity you have a navigation property called instructor that you can use to show the related instructor.
Now my first suggestion is you don't need to iterate through all the courses to create a list, you can do this:
using (var context = new Model1Container())
{
var course_List = context.courses.Include(c=>c.instructor).ToList();
listView.ItemsSource = course_List;
}
The Include extension method allows you include in your query the related object that you want to be included in your query result.
Now, to see the Course info and the related Instructor you could define a custom ItemTemplate. As I said before, instructor is a Course property, so, you can do something like this.
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
...
<TextBlock Text="Instructor: " />
<TextBlock Text="{Binding instructor.name}" FontWeight="Bold" />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
I think it is btter to have InsctruorId in course table, and use below code for joining tabes
private void button_Click(object sender, RoutedEventArgs e)
{
using (var context = new Model1Container())
{
var course_List = new List<course>();
foreach (var course in GetAllCources)
{
course_List.Add(course);
}
listView.ItemsSource = course_List;
}
}
private List<course> GetAllCources()
{
return (from c in context.cources
join i in context.instructors on c.instructorId equals c.Id
select new
{
Cources = c,
Instructors = i,
}).AsEnumerable().Select(c => new Cources
{
.
.
All required fields
.
.
.
} : null).AsQueryable();
}
You can use Include if do not want to select properties.

Entity Framework Can't modify data in datagrid

I'm trying to learn Entity Framework but i have little problem i can not solve by myself
I'm loading data from MS SQL database to the datagrid and trying to modify/add data from there.
But i don't know how to achieve this.
Here is my code:
using (var context = new OrdersDataModelContainer())
{
var customersQuery = from o in context.Payments
select o;
dataGridView1.DataSource = customersQuery;
}
when i did it this way i get this:
when i modyfy code:
using (var context = new OrdersDataModelContainer())
{
var customersQuery = from o in context.Payments
select o;
dataGridView1.DataSource = customersQuery.ToList();
}
my form looks :
But then i can not modify data or add new rows.
Can anyone help me with this problem by showing some code snippet or pointing where I'll be able to find solution?
Thanks!
#Update
I use VS 2012 and SQL Server 2012 ( if that matters)
This is because the underlying data source of the grid does not support modification. Solution:
using (var context = new OrdersDataModelContainer())
{
var customersQuery = from o in context.Payments
select o;
dataGridView1.DataSource = new BindingList<Payments>(customersQuery.ToList());
}
Thanks to King King's comment
Update:
To save changes you need to preserve the context which actually tracks the modifications on the retrieved entities that are now presented in the grid. So one way (perhaps the simplest way) is to declare context as a form member:
public partial class Form1 : Form
{
private MyDBContext context = new MyDBContext(); // whatever your context name is
private void btnLoadData_Click(object sender, EventArgs e) // when you want to load the data
{
var customersQuery = from o in context.Payments
select o;
dataGridView1.DataSource = new BindingList<Payments>(customersQuery.ToList());
}
private void btnSaveChanges_Click(object sender, EventArgs e) // when you want to save
{
context.SaveChanges();
}
}
Be advised that context is not recommended to be preserved for a long time. There are many articles about life cycle of the context.

Entity framework usage

I have a ListView which I filled in from SQL Server view called view_ListaKlientow with this query:
private void fillClientsList() {
using (var context = new EntityBazaCRM()) {
var listaKlientow = from d in context.view_ListaKlientow
select d;
objectListViewListaKlientow.SetObjects(listaKlientow.ToList());
objectListViewListaKlientow.AutoResizeColumns();
}
}
Then after user double clicks one row in ListView, I read ID from the view_ListaKlientow and use fillClientGui to fill necessary fields in gui (for a test only one field is included).
private void objectListViewListaKlientow_DoubleClick(object sender, EventArgs e) {
foreach (view_ListaKlientow user in objectListViewListaKlientow.SelectedObjects) {
int id = user.KlienciID;
fillClientGui(id);
TabPageActivate(tabControlMain, tabPageKlient);
}
}
private void fillClientGui(int klientId) {
using (var context = new EntityBazaCRM()) {
IQueryable<Klienci> klient = context.Kliencis.Include("Podmioty").Where(d => d.KlienciID == klientId);
foreach (var source in klient.ToList()) {
textNIP.Text = source.Podmioty.PodmiotNIP;
}
}
}
Now I'm wondering since I know exactly I'm querying for one ID i should be getting only particular client and not a list of clients so foreach from fillClientGui just to travers IQueryable<Klienci> seems like additional unnecessary code. Or this is how it should be done? I'm trying to learn Entity and some things aren't just clear to me yet :)
If you're sure that you've got only one instance to be returned form the database, you can use the extension function FirstOrDefault() in this case:
var source = context.Kliencis.Include("Podmioty").Where(d => d.KlienciID == klientId).FirstOrDefault();
textNIP.Text = source.Podmioty.PodmiotNIP;

Categories

Resources