WPF Vertical representation of a DataRow - c#

I'm not sure where to look for this one... I've got a viewmodel that has an underlying DataRow providing part of the model. I want to display this information as a single record, in a vertical layout. I planned to use the DataGrid because I want the user to be able to add/delete/rename rows right across the DataTable despite only looking at one record. I'm not quite sure how to achieve this though. Example of what I'm expecting is below:
Source Data Table
ID, Name, Value
1, One, 1
2, Two, 2
Expected in my UI would be a table looking like the following
ID | 1
Name | One
Value | 1

You can expose the DataRow as a list of fields :
public class DataRowField
{
public int Index { get; set; }
public string Name { get; set; }
public object Value { get; set; }
}
public IEnumerable<DataRowField> Fields
{
get
{
return _dataRow.Table.Columns.Cast<DataColumn>()
.Select((column, i) => new DataRowField
{
Index = i,
Name = column.ColumnName,
Value = _dataRow[column]
});
}
}
Then you just need to bind your DataGrid to the Fields property

Related

C# Winform - How to bind my object's enum property to a DataGridView's Combobox?

So I'm attempting to code a fully-automated DnD sheet, and for the Extra Bonus section I figured I'd use a DataGridView where the user can freely add new bonuses to their character (including its equipped state, its name, its affected value, and its bonus value).
Here's my class. The 3rd property is an enum with some placeholder values for the sake of testing it.
public class ExtraBonus
{
public bool isEquipped { get; set; }
public string bonusName { get; set; }
public AffectedValues.values affectedValue { get; set; }
public string bonus { get; set; }
}
Here's my list with some more pre-entered placeholder values:
public static List<ExtraBonus> list = new List<ExtraBonus>()
{
new ExtraBonus { isEquipped = true, bonusName = "Divine Smite", affectedValue = AffectedValues.values.Heavy, bonus = "+1d6"},
new ExtraBonus { isEquipped = false, bonusName = "Hexblade", affectedValue = AffectedValues.values.None, bonus = "+3"},
new ExtraBonus { isEquipped = true, bonusName = "Hex", affectedValue = AffectedValues.values.Light, bonus = "+1d8"}
};
And here is where the list is bound to my DataGridView:
var bindingList = new BindingList<ExtraBonus>(ExtraBonusList.list);
var source = new BindingSource(bindingList, null);
ExtraBonusesGridView.DataSource = source;
With this I currently get the following (don't mind the formatting):
This seems to work but the program returns an error message when it's attempting to fill the third column. Says the value in DataGridViewComboBoxCell isn't valid (paraphrasing because the actual error log is in french).
I've been looking up all kinds of tutorials and I just can't find anything for this. I want my 3rd property (an enum of possible values that can be affected) to be bound to this ComboBox column where the user can freely select which value gets affected by this bonus.
How can I do this?
Thanks!

How to transform Spec-flow table data into different values

I need to transform Spec-flow table data that we get via table.CreateInstance() or table.CreateSet() . I am using Spec flow for DB testing and in some cases, Table field values needs to be mapped to different values as DB tables are storing codes instead of the the values we have entered in tables of feature files. I do not want to include the codes in feature files as it reduces the readability. For example, If I have entered Single for status as mentioned below, I want it to be mapped or transform to S in the data transfer object / POCO. What is the best approach ? Thanks in advance.
Given I entered the following data into the new account form:
| Name | Birthdate | Status |
| John Butcher| 2/2/1902 | Single |
I've started using "Test Models," which ended up being view models for my spec flow tests.
Using your example:
Given I entered the following data into the new account form:
| Name | Birthdate | Status |
| John Butcher| 2/2/1902 | Single |
The Domain Model:
public class Account
{
public string Name { get; set; }
public DateTime? Birthdate { get; set; }
public string Status { get; set; }
}
And the "Test Model":
public class AccountForm
{
public string Name { get; set; }
public DateTime? Birthdate { get; set; }
public string Status { get; set; }
public Account CreateInstance()
{
return new Account()
{
Name = Name,
Birthdate = Birthdate,
Status = Status.Substring(0, 1)
};
}
}
The step defintion:
[Given(#"Given I entered the following data into the new account form:")]
public void GivenIEnteredTheFollowingDataIntoTheNewAccountForm(Table table)
{
var form = table.CreateInstance<AccountForm>();
var account = form.CreateInstance();
// save to the database
}
For this one particular example it might be more than you need, but I've found this pattern works well when the data in the Scenario needs to be in a human readable format, which gets translated to a complex format in your Domain Model.
I'm not aware of anyway to do this automatically, so I can only think of two possibilities.
Don't use the CreateInstance or CreateSet methods and instead do all of the mapping manually, but encapsulate it in a [StepArgumentTransformation]
Use the methods you are using but then afterwards overwrite the automatically generated 'Single' values with 'S' after the instances have been created.
As Sam pointed out, we can use StepArgumentTransformarion or an approach similar to below. Add if else inside the extension methods if you want to map Value1 to Code1 for one type and Value1 to CodeX in another type using typeof(T).Name.Equals(typeof(yourtype).Name) as the condition
public static IEnumerable<T> CreateSetWithValueTransfer<T>(this Table table)
{
var mapper = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
{
{"Value1", "Code1"},
{"value2", "Code2"}
};
var set = ChangeValues(table, mapper);
return set.CreateSet<T>();
}
private static Table ChangeValues(Table table, Dictionary<string, string> mapper)
{
var mappedTable = new Table(table.Header.ToArray());
foreach (var row in table.Rows)
{
mappedTable.AddRow(row.Values.Select(x => mapper.ContainsKey(x) ? mapper[x] : x).ToArray());
}
return mappedTable;
}
I posed a similar question with a different example here. Seems like it should be possible to apply StepArgumentTransforms to CreateInstance/CreateSet, but just hasn't been implemented yet for basic types that already get transformed in the table conversion.
In your case (unlike mine), I think you could do it relatively easily with a custom ValueRetriever.
you can get values out of the table by
table.Rows.FirstOrDefault().Values.FirstOrDefault();

Datatable like custom collection in c#

In theory how would I do this.
short winded: store data like a datatable using custom collections, having variable amount of fields and columns...so long as the rows are consistent.
Long winded:
2 or 3 classes: field, row, optionally: table
Normally I would do something like List<Person> myList = new List<Person>;
Then that list could be bound to a datagridview and the columns would be based off the properties of the Person class.
Code to look at:
List<row> table = new List<row>;
List<field> row0 = new List<field>;
row0.Add(new field(col1,"value1"));
row0.Add(new field(col2,"value2"));
row0.add(new field(col3,"value3"));
table.Add(row0);
dataGridView1.DataSource = table;
theoretical Output:
| |col 1 | col 2| col 3|
___________________________
|row0|value1|value2|value3|
public class cField
{
public string Name { get; set; }
public string Content { get; set; }
public cField()
{
}
public cField(string name, string content)
{
Name = name;
Content = content;
}
}
public class cRow:BindingList<cField>
{
public cRow()
{
}
}
public class tables:BindingList<cRow>
{
public tables()
{
fillTestData();
}
private void fillTestData()
{
for (Int32 i = 0; i < 10; i++)
{
cRow tRow = new cRow();
for (Int32 x=0; x < 3; x++)
{
cField f1 = new cField("ColumnName" + x.ToString(), "content" + x.ToString());
tRow.Add(f1);
}
base.Items.Add(tRow);
}
}
}
//example class which shows the output of what I'd like.
public class eField
{
public string ColumnName0 { get; set; }
public string ColumnName1 { get; set; }
public string ColumnName2 { get; set; }
public eField(string colName0, string colName1, string colName2)
{
ColumnName0 = colName0;
ColumnName1 = colName1;
ColumnName2 = colName2;
}
}
public class eTable : BindingList<eField>
{
public eTable()
{
base.Add (new eField ("content","content", "content"));
base.Add(new eField("content", "content", "content"));
base.Add(new eField("content", "content", "content"));
}
}
Now Here is code for the form.
public partial class Form1 : Form
{
tables t;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
t = new tables ();
dataGridView1.DataSource = t;
dataGridView2.DataSource = t[0];
eTable table3 = new eTable ();
dataGridView3.DataSource = table3;
}
}
If you make that code into a project...you will see the first binding....pulls some built in stuff from the bindinglist into grid1. Grid2 lists my fields vertically when I want them horizontal.
Grid 3 shows exactly how I want my output to be.....yet I can't achieve it with the collection structure I have going to mimic a dataTable....(provided in code)
Disclaimer:
I am short on keywords I would need to research this problem. I didn't find much. The closest thing I found was related to linq and pivots. But non of their outputs seemed to be as I described.
I use custom collections all over the place, so I would like to keep my code very similar instead of using a datatable. This is the first time I have needed my collections to behave in this manner.
It sounds like you are looking for a collection of objects to use in memory once you have loaded the data from a database. You can do calculations and the like on the built-in System.Data objects, but it is cumbersome, and it does not perform well with a large amount of data.
We use System.Data objects heavily to present data. We try to do calculations in the database later and present the results as a DataSet, so the client doesn't have to do any data manipulation.
A few of our modules need more sophisticated data processing. In one case, we used an array of objects that represented a large amount of data to be massaged on the fly. The columns were fixed, so they were easy to implement as properties on each object. When the app presented this data, it generated a small summary DataSet to be displayed in a grid.
We have another module in which there are fields that can have values, or they can also have calculations based on other fields. For this model, we opted to use objects that have dependencies on other objects that made a sort of web of calculations. Change one value, and the ValueChanged event notifies any dependent fields that they need to be calculated, which changes those values, etc. (This is a gross simplification.)
If I had to present a variable number of columns, I'd seriously consider sticking with a System.Data.DataSet. If that really doesn't work for you, you might consider a hashtable that maps a column name to a collection of row values for that column. I believe that is how the System.Data.DataTable is implemented; it stores values by column, not by row. Then a row object would know its row index and how to grab the values out of the column collections.

How construct a Type, To hold two 'types' of data , to be sent As a Single Parameter

I need to implement this approach - two kinds of data sent as one set of parameters in a single Type - so that one type will hold those two parameters. That way I will be able to pass that Type to be processed by some method.
the first data item is:
Columns to be displayed , named: displayed
the second data item:
A copy (or only a portion) of that Columns displayed, as it has the same source, only these columns will not be displayed... in other words, Columns to omit, so I've named it: omitted
both are of a type Columns that I named - SelectedColumns
public class SelectedcColoumns
{
public enum renederingMode
{
Displayed,
omitted
}
public class omitted
{
}
public class displayed
{
}
}
As the request for that SetOfColumns to be displayed is done by choosing table-name. So the Column class as data to be displayed varies based on the user choice the available source For SelectedColumns to choose from, is as shown below:
public class tableNames
{
public static readonly string tblCustomers = "tblCustomers";
public static readonly string tblProducts = "tblProducts";
}
public class TblColumns
{
public class tblCustomers
{
public const string custID = "custID",
Name = "Name",
Phone = "Phone";
Email = "Email";
}
public class tblProducts
{
public const string PrudctID = "PrudctID ",
PrudctName = "PrudctID",
PrudctCategory = "PrudctCategory";
}
...etc'
}
When the user selects a set of tables Columns ... from any table user could, in this example.. choose either Customers or Products columns (e.g. SelectedColumns - is tblCustomers Columns), I then need to have another list, of those that the user selected to omit (not to display) from all of available table Columns.
Say the user chose to have Table Customers as a table. He chose to omit tblCustomers.custID + tblCustomer.Email because he only needs the name and phone to be displayed.
The problem I've encountered is while having these parameters in my reach (table name + columns to omit), How could I send it to process (passing it as One Parameter)? So that is why I've created a dedicated class, to hold this Type as sent parameter: all columns + omitted Columns in one piece.
This is where I am currently stuck; I need to know how to use it to build / construct the parameter out of user selection.
public class SelectedColoumns
{
public enum renederingMode
{
Displayed,
omitted
}
public class omitted
{
List<string> omitCols_ListStr = new List<string>();
}
public class displayed
{
List<string> dispCols_ListStr = new List<string>();
}
}
In this part, I retrieve list of Columns through reflection as the supplier of data, via the following method:
Get any Nested Class-Fields, As List<string>, By a nested class-name and it's parent - Type.
public static List<string> anyNestedClassFiledsAsListByType<ClassToReturnOneOfitsNested_Fields>(string NetedClassName)
{
var RetNestedClassFildsListValues = typeof(ClassToReturnOneOFitsNested).GetNestedTypes()
.First(t => String.Compare(t.Name, NetedClassName, true) == 0).GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(f => f.FieldType == typeof(string)).Select(f => (string)f.GetValue(null)).ToList();
return RetNestedClassFildsListValues;
}
so to produce this I could use the method above Like that
var TableColumns_ALL =
anyNestedClassFldsAsListByType<TblColumns>(tableNames.tblCustomers);
My question is related to the class that needs to send TableColumns_ALL + the selected Columns to omit to be then processed by renderSelectedTable() below.
So it's even more basic than the complexity of reflection, but still some how i do not know the popper way to construct, the SelectedColumns class, so it will accommodate and format the structure of this new data type that will be sent as a parameter the method is something like this.
public void renderSelectedTable(SelectedColoumns CurrentUserSelectedCols)
{
StringBuilder NwTRLoopSB = new StringBuilder();
string curRowStyle= string.Empty,
nwLine = Environment.NewLine + "\t\t\t",
BaseTemplateTD = string.Empty;
NwTRLoopSB.Append(
string.Format(
"<table id='tbl_Settings' cellspacing='0' border='1'><tr id='TR_headers'{0}>{1}",
curRowStyle,
nwLine
)._Dhtml_DoubleQoutes()
);
foreach (var Item in SelectedListStr.Select((Val, counter) => new { Value = Val, Index = counter }))
{
curRowStyle = Lsts.DynamicStyle_Generator(Item.Index);
if(Lsts.ExcludeColumns(Item.Value, OmittedCols))
{
BaseTemplateTD = string.Format("<td>{0}</td>{1}", Item.Value, nwLine)._Dhtml_DoubleQoutes();
NwTRLoopSB.Append(BaseTemplateTD);
}
}///ENd TR cells generator Section
NwTRLoopSB.Append("</tr></table>");
return NwTRLoopSB.ToString();
}
I would approach it this way:
public class Column{
public string Name { get; set; }
public bool Visible { get; set; }
}
public class Grid{
public List<Column> Columns { get; set; }
}
So the I could easily define my full table with either visible or ommited columns.
In the OP's example:
public class SelectedColumns
{
//instead of the enum you would have boolean in the column type "Visible" (whether is shown or not)
public enum renederingMode
{
Displayed,
omitted
}
// instead of both these you would have a List o Column types that have a name AND a boolean, so you have your List<string> and a boolean to indicate whether it is visible or ommited. Well at least that's how I understood it.
public class ommited
{
}
public class displayed
{
}
}
so.. first.. a design note: Given a list of columns.. you will either display a column, or not display a column.. there are no other options where visibility is concerned. So you really only need to pass in a single list of EITHER the columns to display, OR the columns to omit - but NOT both.
If you choose to make that modification then you can simply pass in a single List<string>
If you choose to keep your current design then you will need a class with two properties:
public class SelectedColumns {
public List<string> displayed { get; set; }
public List<string> omitted { get; set; }
}

Converting rows in Columns

I am developing an asp.net mvc application with NHibernate and I have a query where I would like to know how can I convert rows in columns?
I have a dynamic system with a model like this:
// It's a kind of metadata
public class Field
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
}
// the value is here with respective field
public class FieldValue
{
public virtual long Id { get; set; }
public virtual Field Field { get; set; }
public virtual string Value { get; set; }
}
I would like to know how can I get a result where columns are the Field objects and values are FieldValue objects, should I create a ViewModel? or a way to do it with asp.net mvc?
I can do a query to get a result like this:
But I would like to do a query like this (or a way to create a result on my View on the asp.net mvc):
Thanks
I think you are going to need to get fancy/familiar with GroupBy(). If you Group By the Field, you "group" all the values for a field then move to the next one. The pseudo-code would be something like the following
#model IEnumerable<FieldValue>
foreach(var fields in Model.GroupBy(x=>x.Field.Name){
<h2>fields.key</h2>
<ul>
foreach(var fieldValue in fields){
<li>#fieldValue.Value</li>
}
</ul>
}
This should render something like
Field 1
some value 1
some value 2
Field 2
some value 3
some value 4
etc.
By using this approach, you can control the formatting however you want to get the desired output.
Not clear with the question. if you want to transform rows into columns - you can use pivot. But i would suggest instead of operating on resultset to transpose, let it return the transposed result set. I meant handle the conversion of rows into columns in your query itself

Categories

Resources