public class PurchaseOrderItem
{
public Int64 PONumber { get; set; }
public string Description { get; set; }
public string UM { get; set; }
public int QTY { get; set; }
public decimal Cost { get; set; }
}
foreach (PurchaseOrderItem item in po.PurchaseOrderItems)
{
dgvPOItem.Rows.Add(item);
}
The Foreach above isn't working.
I can't use DataSource since i need to add a blank row after adding the data
So there will be a empty row where users can add values on gridview in the future.
can't you use a BindingList<PurchaseOrderItem> ?
this should allow you to add items to your collection from dgv control (using empty row)
Edit: I've created simple WinForm app,
only DGV control in the main form
Form1.cs code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
list.Add( new PurchaseOrderItem() {
PONumber = 1,
Description = "First item",
UM = "something",
QTY = 2341,
Cost = 0.99M
} );
dataGridView1.DataSource = list;
dataGridView1.RowsAdded += new DataGridViewRowsAddedEventHandler( dataGridView1_RowsAdded );
}
void dataGridView1_RowsAdded( object sender, DataGridViewRowsAddedEventArgs e ) {
object o = list; // added for breakpoint with variable viewing
// you can watch your list changing here, when you add new rows
}
BindingList<PurchaseOrderItem> list = new BindingList<PurchaseOrderItem>();
}
public class PurchaseOrderItem {
public Int64 PONumber { get; set; }
public string Description { get; set; }
public string UM { get; set; }
public int QTY { get; set; }
public decimal Cost { get; set; }
}
}
Related
I am completely new to C# and have zero background in the language.
The only programming language I am an expert in is SQL.
My situation:
I have a an API url from a website my company uses to monitor product levels in tanks.
The API returns a json list of the tanks (location, tank id, tank size, current level, etc.).
My goal is to create a windows form application with an input field.
The user types the name of the location, clicks a button, and sees the information for any tanks at that location.
What I have tried:
What I have done so far:
Again, I have zero knowledge of programming so do not be critical if I have done things in very unusual/inefficient ways.
I have managed to create a windows form that has a button and text box.
When the button is clicked, the text box is populated with all of the tank data from the API.
I can't figure out how to filter the data that has been returned.
My current code is below...
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using RestSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using static APIform.Form1;
namespace APIform
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var client = new RestClient("https://{{my tank monitor website}}/admin/data_feed_configs/140.json");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("auth-token", "{{my token}}");
request.AddHeader("auth-email", "{{my authorization email}}");
request.AddHeader("Authorization", "{{my auth code}}");
request.AddHeader("Cookie", "{{cookies}}");
IRestResponse response = client.Execute(request);
var data = response.Content;
JArray jsonArray = JArray.Parse(data);
textBox1.Text = jsonArray.ToString();
}
}
}
I have added a model class TankClass that resembles the text returned from the request.
public class TankClass
{
public string location_name { get; set; }
public string owner_name { get; set; }
public string tank_id { get; set; }
public string tank_name { get; set; }
public string product_name { get; set; }
public int tank_size { get; set; }
public string sensor_value { get; set; }
public string reading_inches { get; set; }
public string reading_volume { get; set; }
public string available_capacity { get; set; }
public int fill_percentage { get; set; }
public string fill_status { get; set; }
public string alert_status { get; set; }
public int days_to_empty { get; set; }
public string battery_level { get; set; }
public string product_sku { get; set; }
public string reading_time { get; set; }
public string division { get; set; }
}
Everything I try to deserialize/filter the results does not seem to be working.
What do I need to add into the code to make this work?
I have a second text box (textbox2) on the form.
This is where the user will enter "Warehouse 1" for example.
When they then hit the button, I would like only tanks at Warehouse 1 to show in the textbox1 field.
With my current code, this is a sample of what shows in the textbox1 field when clicking the button:
[
{
"location_name": "Warehouse 1",
"owner_name": "ABC Oil, Inc.",
"tank_id": "W00813862",
"tank_name": "Dow - Desitherm (TEG) Tank #M-20-065",
"product_name": "Dow - Desitherm (TEG)",
"tank_size": 2005.0,
"sensor_value": "2.379",
"reading_inches": "29.6",
"reading_volume": "908.2",
"available_capacity": "1096.8",
"fill_percentage": 45,
"fill_status": "COULD",
"alert_status": "",
"days_to_empty": 124.4,
"battery_level": "6.1",
"product_sku": "",
"reading_time": "2020-09-16T10:55:35-04:00",
"division": "1024"
},
{
"location_name": "Warehouse 2",
"owner_name": "ABC Oil, Inc.",
"tank_id": "Z057101",
"tank_name": "OSI 84 - Diesel Exhaust Fluid (DEF)",
"product_name": "Diesel Exhaust Fluid (DEF)",
"tank_size": 8806.0,
"sensor_value": "2554.0 | 3263.0",
"reading_inches": "76.3",
"reading_volume": "4868.8",
"available_capacity": "3937.2",
"fill_percentage": 55,
"fill_status": "GOOD",
"alert_status": "",
"days_to_empty": 14.5,
"battery_level": "-",
"product_sku": "",
"reading_time": "2020-09-16T10:59:00-04:00",
"division": ""
},
.
.
.
]
My Program.cs tab:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using RestSharp;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Security.Principal;
using System.Text;
using System.IO;
using static APIform.Form1;
namespace APIform
{
public class TankClass
{
public string location_name { get; set; }
public string owner_name { get; set; }
public string tank_id { get; set; }
public string tank_name { get; set; }
public string product_name { get; set; }
public double tank_size { get; set; }
public string sensor_value { get; set; }
public string reading_inches { get; set; }
public string reading_volume { get; set; }
public string available_capacity { get; set; }
public int fill_percentage { get; set; }
public string fill_status { get; set; }
public string alert_status { get; set; }
public double days_to_empty { get; set; }
public string battery_level { get; set; }
public string product_sku { get; set; }
public DateTime reading_time { get; set; }
public string division { get; set; }
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
In your class just change tank_size and days_to_empty to a double and reading_time to DateTime.
Then Deserialize into a List<TankClass>
var listOfTanks = Newtonsoft.Json.JsonConvert.DeserializeObject<List<TankClass>>(data);
Then with the form data, you can use Linq to filter the results:
var returnValues = listOfTanks.Where(x => x.location_name == TextBox1.Text);
Perhaps I am misunderstanding how a ViewModel works. A ViewModel is used to display custom data to the user without having to use the full Model. So you would use only the database fields that you want displayed. I have a ViewModel that looks like this
using PagedList;
using Resolutions.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
namespace Resolutions.ViewModels
{
public class SearchPagingViewModels
{
public int ObjectID { get; set; } //Database Primary Key
[DisplayName("Resolution Year")]
public string ResolutionYear { get; set; } //Year of the Resolution
[DisplayName("Resolution Number")]
public string ResolutionNumber { get; set; } //Number of the Resolution
[DisplayName("Resolution Text")]
public string ResolutionText { get; set; } //OCR'd text for the Resolution
[DisplayName("Resolution Date")]
public Nullable<System.DateTime> ResolutionDate { get; set; } //Date of the Resolution
public int? PageNumber { get; set; }
public bool? IsResYearChecked { get; set; }
public bool? IsResNumChecked { get; set; }
public bool? IsKeywordChecked { get; set; }
public string SearchKeyword { get; set; }
}
}
I want to store the value of a checkbox from the client side into my object and use the boolean to be able to filter and page through the results. However, if I use my current ViewModel I get 25 checkboxes when I try to access the object's boolean; As I can only seem to access the value of the checkbox within a foreach loop that I am using to display each item. I am currently pulling information from a database and then storing the database results into a list of the ViewModel.
This is my controller:
using PagedList;
using Resolutions.Models;
using Resolutions.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Resolutions.Controllers
{
public class SearchPagingController : Controller
{
private DocumentManagementEntities db = new DocumentManagementEntities();
// GET: SearchPaging
public ViewResult Index(int? page, bool? resnum)
{
var temp = resnum;
int pageSize = 25;
int pageNumber = (page ?? 1);
List<SearchPagingViewModels> searchList = new List<SearchPagingViewModels>();
var allResolutions = from c in db.AllResolutions select c;
allResolutions = allResolutions.OrderBy(c => c.ResolutionYear).ThenBy(c => c.ResolutionNumber);
foreach (var item in allResolutions)
{
SearchPagingViewModels searchItem = new SearchPagingViewModels();
searchItem.ObjectID = item.ObjectID;
searchItem.ResolutionYear = item.ResolutionYear;
searchItem.ResolutionNumber = item.ResolutionNumber;
searchItem.ResolutionText = item.ResolutionText;
searchItem.ResolutionDate = item.ResDate;
searchItem.IsResNumChecked = resnum;
searchList.Add(searchItem);
}
return View(searchList.ToPagedList(pageNumber, pageSize));
}
}
}
As you can see I create a List<SearchPagingViewModels> and then add each SearchPagingViewModels into the List<SearchPagingViewModels>. In my Index.cshtml, I use a foreach loop to traverse the list and display each item and create a PagedList. Should I be changing my ViewModel to store a List<AllResolutions> like so:
using PagedList;
using Resolutions.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
namespace Resolutions.ViewModels
{
public class SearchPagingViewModels
{
public List<AllResolution> AllResolutions { get; set; }
public int? PageNumber { get; set; }
public bool? IsResYearChecked { get; set; }
public bool? IsResNumChecked { get; set; }
public bool? IsKeywordChecked { get; set; }
public string SearchKeyword { get; set; }
}
}
or do I want to use the current values within the ViewModel? If instead I used a List<AllResolutions>, how do you access the values within the list in the cshtml file?
In the code below, I am converting the results of an SQL View to a DataTable:
DataTable tierOnes = db.xxxxxxxxx_vw_TierOnes.ToDataTable();
The View is defined in a separate class:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DPN.Entities.Moonboot
{
[Table("vw_TierOnes", Schema = "xxxxxxxxx")]
public class xxxxxxxxx_vw_TierOnes
{
[Key]
public Guid TierOneID { get; set; }
public string TierOneName { get; set; }
public DateTime DateCreated { get; set; }
public Boolean IsActive { get; set; }
public int? CreatedByUserID { get; set; }
}
}
I try to retrieve data from columns AS BELOW:
foreach (DataRow row in tierOnes.Rows)
{
if (row["IsActive"].ToString() == "True")
{
TierOne t1 = new TierOne();
t1.Id = Guid.Parse(row["TierOneID"].ToString());
t1.Name = row["TierOneName"].ToString();
output.TierOnes.Add(t1);
}
}
I get the following error:
Column 'TierOneID' does not belong to table .
Where did my column go?
More importantly, how do I get this data?
I want to show a calculated field in a view, so I tried to create a viewmodel like this:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Facturacion.Models
{
public class Test
{
public int testId { get; set; }
[Required]
public decimal price { get; set; }
}
public class TestViewModel
{
[Key]
public int testId { get; set; }
public Test test { get; set; }
public decimal price { get; set; }
public decimal calculated { get; set; }
public TestViewModel(Test test)
{
Test = test;
calculated = Test.price * 2;
}
}
}
It gave me an error so I changed the constructor:
public TestViewModel(Test test)
{
var foo = test;
calculated = foo.price * 2;
}
But now when I build the project, it creates a table called "TestViewModels", so I can not reach the data in the Tests table.
I think a viewmodel shouldn't have an id, but if it does not the scaffolder won't generate the controllers.
What is the correct way to use a viewmodel to show a calculated field in a view?
I could solve it without using the viewmodel
namespace Facturacion.Models
{
public class Test
{
public int testId { get; set; }
[Required]
public decimal price { get; set; }
public decimal calculated
{
get
{
return (decimal)(price*2);
}
}
}
}
Notice the calculated field does not have a set method.
Im Having Problems Figuring Out Why I am Receiving an "Object reference not set to an instance of an object" Error in the Presentation Layer with this line:
TempAccountManager.Accounts.Add(tempAccount);
I Have Walked Through the Code With Visual Studios Debugger and the Account Gets Created. I Believe I Have an Issue With an Access Modifer, Not Sure.
Presentation Layer
using myBudget.BusinessObject;
using myBudget.BusinessLogic;
namespace myBudget
{
public partial class NewBudgetWizard : Form
{
public int CurrentStep { get; set; }
public Account TempAccount = new Account();
public AccountManager TempAccountManager = new AccountManager();
public NewBudgetWizard()
{
private void createAccountList(ListView lvAccounts)
{
foreach (ListViewItem lvi in lvAccounts.Items)
{
int tempAccNumber = Int32.Parse(lvi.SubItems[0].Text);
string tempAccName = lvi.SubItems[1].Text;
string tempAccType = lvi.SubItems[2].Text;
decimal tempAccBalance = decimal.Parse(lvi.SubItems[3].Text, System.Globalization.NumberStyles.Currency);
Account tempAccount = new Account(tempAccNumber, tempAccName, tempAccType, tempAccBalance, DateTime.Now);
TempAccount = new Account(tempAccNumber, tempAccName, tempAccType, tempAccBalance, DateTime.Now);
TempAccountManager.Accounts.Add(tempAccount);
}
}
}
}
Business Logic Layer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using myBudget.BusinessObject;
namespace myBudget.BusinessLogic
{
public class AccountManager : Account
{
public List<Account> Accounts { get; set; }
}
}
Business Object
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace myBudget.BusinessObject
{
public class Account
{
public int AccountID { get; set; }
public int UserID { get; set; }
public int Number { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public decimal Balance { get; set; }
public DateTime ReconcileTimeStamp { get; set; }
public Account()
{
}
public Account(int number, string name, string type, decimal balance, DateTime reconcileTimeStamp)
{
Number = number;
Name = name;
Type = type;
Balance = balance;
ReconcileTimeStamp = reconcileTimeStamp;
}
}
}
The AccountManager Class Never Initializes The Accounts Property. Therefore TempAccountManager.Accounts Is Null.
Adding A Constructor Like This Will Fix It.
public class AccountManager : Account
{
public AccountManager()
{
Accounts = new List<Account>();
}
public List<Account> Accounts { get; set; }
}
Do you create Accounts in your AccountManager?
You should do somewhere:
Accounts = new List<Account>();
EDIT
You've got public set accessor. You may do:
TempAccountManager.Accounts = new List<Account>();
Or add a constructor to the class, as Joel Mueller suggested. But think over, if you need the public set. It gives an opportunity to completely replace your collection out of the object.
Not sure, but where do you initialize Accounts?
public List<Account> Accounts { get; set; }
Your get, set interface provides access, but doesn't define the value.