accessing array properties - arrays

var questions:Array = new Array;
questions[0] = "qname:mc_01, qvalue:1";
questions[1] = "qname:mc_02, qvalue:1";
questions[2] = "qname:mc_03, qvalue:1";
questions[3] = "qname:mc_04, qvalue:1";
questions[4] = "qname:mc_05, qvalue:1";
questions[5] = "qname:mc_06, qvalue:1";
questions[6] = "qname:mc_07, qvalue:1";
questions[7] = "qname:mc_08, qvalue:1";
questions[8] = "qname:mc_09, qvalue:1";
questions[9] = "qname:mc_10, qvalue:1";
questions[10] = "qname:mc_11, qvalue:2";
questions[11] = "qname:mc_12, qvalue:2";
questions[12] = "qname:mc_13, qvalue:2";
questions[13] = "qname:mc_14, qvalue:2";
questions[14] = "qname:mc_15, qvalue:2";
questions[15] = "qname:mc_16, qvalue:2";
questions[16] = "qname:mc_17, qvalue:2";
questions[17] = "qname:mc_18, qvalue:2";
questions[18] = "qname:mc_19, qvalue:2";
questions[19] = "qname:mc_20, qvalue:2";
questions[20] = "qname:mc_21, qvalue:3";
questions[21] = "qname:mc_22, qvalue:3";
questions[22] = "qname:mc_23, qvalue:3";
questions[23] = "qname:mc_24, qvalue:3";
questions[24] = "qname:mc_25, qvalue:3";
questions[25] = "qname:mc_26, qvalue:3";
questions[26] = "qname:mc_27, qvalue:3";
questions[27] = "qname:mc_28, qvalue:3";
questions[28] = "qname:mc_29, qvalue:3";
questions[29] = "qname:mc_30, qvalue:3";
I've got this array and want to access the qname property and can't remember how to do it. Is it something like questions[0].qname or questions[0](qname)?

You've defined your array elements as string instead of objects.
Try this instead:
var questions:Array = new Array;
questions[0] = {qname:mc_01, qvalue:1};
...
Curly braces instead of double-quotation marks. With quotation marks you create strings. With curly braces, you can create dynamic objects and set their properties. So if you are creating a string value for qname, make sure you define it as qname:"mc_01" instead of qname:mc_01.
So you can use questions[0].qname or questions[0]["qname"] to access the properties.

But if you can't do that what is told in previous answer (e.g. you get those strings from server) you can use regular expresions to get those values nicely:
var searchPattern : RegExp = /(?P<qname>(?<=qname\:)[a-zA-Z0-9_]+(?=[\s,]*))/g;
trace( searchPattern.exec(questions[1]).qname ); // traces out: mc_02

As you tagged ActionScript 3.0, and its a strongly typed language, I would recommend a typed class to hold your data structure.
package your.package.name
{
public class Question
{
protected var _name:String;
protected var _value:String;
public function Question(name:String = null, value:String = null)
{
this.name = name;
this.value = value;
}
public function get name():String
{
return _name;
}
public function set name(value:String):void
{
_name = value;
}
public function get value():String
{
return _value;
}
public function set value(value:String):void
{
_value = value;
}
}
}
By having getters and setters and also exposing these props in the constructor you can create them in two ways:
var question:Question = new Question("Question1", "Question value");
OR:
var question:Question = new Question();
question.name = "Question1";
question.value = "Question value";
This offers benefits in terms of intellisense for getting properties in your ide and also type safety to stop you putting in incorrect types for name and value.
Then to get hold of a question:
questions[0].name; // in this example Question1
questions[0].value; // in this example Question value
Usually your questions would be coming from some data source, like xml or a web service, whatever I'll use literal xml for this example, in that scenario you would want to build your objects in some loop eg:
var questionsXML:XML =
<questions>
<question name="Question1">Question1 value</question>
<question name="Question2">Question2 value</question>
<question name="Question3">Question3 value</question>
</questions>
Then:
var questions:Array = [];
for each (var questionXML:XML in questionsXML.question)
{
var question:Question = new Question();
question.name = questionXML.#name;
question.value = questionXML.text();
questions.push(question);
}

Related

Net 6: (T)Activator.CreateInstance(typeof(T)) throws an MissingMethodException: 'Cannot dynamically create an instance of type

I Have Excel import feature with ClosedXM and meet the errror with ctivator.CreateInstance(typeof(T)). It throws:
System.MissingMethodException: 'Cannot dynamically create an instance of type
'FSH.WebApi.Domain.Catalog.Brand'.
Reason: No parameterless constructor defined.
Please help !!!
// Controller
[HttpPost("import")]
public async Task<ActionResult<int>> ImportAsync(ImportBrandsRequest request)
{
IList<Brand> result = new List<Brand>();
result = await _excelReader.ImportAsync<Brand>(request.ExcelFile, FileType.Excel);
return Ok(result.Count);
}
// Interface
public interface IExcelReader : ITransientService
{
Task<IList<T>> ImportAsync<T>(
FileUploadRequest request,
FileType supportedFileType,
string sheetName = "Sheet1");
}
// Service:
public class ExcelReader : IExcelReader
{
public async Task<IList<T>> ImportAsync<T>(FileUploadRequest request, FileType supportedFileType, string sheetName = "Sheet1")
{
var streamData = new MemoryStream(Convert.FromBase64String(base64Data));
List<T> list = new List<T>();
Type typeOfObject = typeof(T);
using (IXLWorkbook workbook = new XLWorkbook(streamData))
{
var worksheet = workbook.Worksheets.First(w => w.Name == sheetName);
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
// header column texts
var columns = worksheet.FirstRow().Cells().Select((v, i) => new { v.Value, Index = i + 1 });
// indexing in closedxml starts with 1 not from 0
// Skip first row which is used for column header texts
foreach (IXLRow row in worksheet.RowsUsed().Skip(1))
{
T item = (T)Activator.CreateInstance(typeof(T));
// T item = (T)Activator.CreateInstance(typeof(T));
foreach (PropertyDescriptor prop in properties)
{
int colIndex = columns.Single(
c => c.Value.ToString() == prop.Name).Index;
if (colIndex == 0) continue;
object? val = row.Cell(colIndex).Value;
var type = prop.PropertyType;
prop.SetValue(item, Convert.ChangeType(val, type));
}
if (item != null) list.Add(item);
}
}
return await Task.FromResult(list);
}
Presumably, Brand doesn't have a constructor without parameters. So, either add a parameterless constructor to Brand or pass parameter arguments to Activator.CreateInstance.

Windows Forms Custom DataGridView

I am not very experienced with Windows Forms and am not pretty sure how I should tackle with this task the best way possible. I have a class which looks like this:
public class VariableMapping
{
private string variableName;
private string variableText;
private string variableSelector;
public VariableMapping(string variableName, string variableText, string variableSelector)
{
this.VariableName = variableName;
this.VariableText = variableText;
this.VariableSelector = variableSelector;
}
public string VariableName
{
get { return this.variableName; }
set { this.variableName = value; }
}
public string VariableText
{
get { return this.variableText; }
set { this.variableText = value; }
}
public string VariableSelector
{
get { return this.variableSelector; }
set { this.variableSelector = value; }
}
}
I want to create a DataGridView which should be bound to a number of elements of type VariableMapping in a list. However, I want only 1 of the properties(VariableText) of every instance to be shown in the DataGridView but I want to be able to address the whole object through the DataGrid when I need to. I also need to add 2 more custom columns: a ComboBox with predefined values and a NumberBox.
It might seem a really simple task but I'm trully unexperienced in WinForms and couldn't find a solution I can use already. Thank you!
Edit: I am trying something like this but it doesn't seem to work properly:
public partial class MappingTable : Form
{
private DataGridView dataGridView1 = new DataGridView();
public MappingTable(List<VariableMapping> variableMappings)
{
InitializeComponent();
var colors = new List<string>() { "#color_k1", "#color_k2", "#color_s1" };
dataGridView1.AutoGenerateColumns = false;
dataGridView1.AutoSize = true;
dataGridView1.DataSource = variableMappings;
DataGridViewColumn titleColumn = new DataGridViewColumn();
titleColumn.DataPropertyName = "VariableText";
titleColumn.HeaderText = "Variable";
titleColumn.Name = "Variable*";
dataGridView1.Columns.Add(titleColumn);
DataGridViewComboBoxColumn colorsColumn = new DataGridViewComboBoxColumn();
colorsColumn.DataSource = colors;
colorsColumn.HeaderText = "Color";
dataGridView1.Columns.Add(colorsColumn);
DataGridViewTextBoxColumn opacityColumn = new DataGridViewTextBoxColumn();
opacityColumn.HeaderText = "Opacity";
dataGridView1.Columns.Add(opacityColumn);
this.Controls.Add(dataGridView1);
this.AutoSize = true;
}
}

Reference a scalar property from a string value

I have a combobox that contains a list of scalar properties of an entity. I need to do a search on the property specified by the user in the combobox.
How do I reference the property when I have it as a string?
Something similar to DBSet<> for entity.
Example:
if (order.Firstname != null && order.Firstname.ToLower().Contains(textBoxSearch.Text.ToLower()))
In the above example, I need to replace Firstname with Surname or any other property, at runtime, depending on what the user selected.
You can always use reflection, for your case you'll need something along these lines:
static void Main(string[] args)
{
var entity = new Entity {
Height = 172,
FirstName = "Foo",
Birthday = new DateTime(1, 1, 1995)
};
var firstName = GetEntityProperty<string>(entity, "FirstName");
}
public static T GetEntityProperty<T>(object entity, string propertyName)
{
var type = entity.GetType();
var property = type.GetProperty(propertyName);
return (T)property.GetValue(entity);
}
Provided solution works, but it is not strongly-typed, so it is sensible to property renaming. A strongly-typed approach can be used, but it requires some setup. However, part of the setup is so generic that it can be reused:
public class Order
{
public String OrderNo { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public String Misc { get; set; }
}
// clearly define properties that allow search
public enum OrderSearchableProp
{
OrderNo = 1,
FirstName = 2,
LastName = 3
}
class Program
{
// strongly-type requires an explicit mapping between property and its expression within the order object
static Dictionary<OrderSearchableProp, Expression<Func<Order, String>>> OrderSearchableMap = new Dictionary<OrderSearchableProp, Expression<Func<Order, string>>>()
{
{ OrderSearchableProp.OrderNo, o => o.OrderNo },
{ OrderSearchableProp.FirstName, o => o.FirstName },
{ OrderSearchableProp.LastName, o => o.LastName },
};
// this gets a PropertyInfo based from an Expression. It should be placed into a generic utility class
// credit goes to Daniel - http://stackoverflow.com/a/17116267/2780791
public static PropertyInfo GetPropertyFromExpression<T, TProp>(Expression<Func<T, TProp>> GetPropertyLambda)
{
MemberExpression Exp = null;
//this line is necessary, because sometimes the expression comes in as Convert(originalexpression)
if (GetPropertyLambda.Body is UnaryExpression)
{
var UnExp = (UnaryExpression)GetPropertyLambda.Body;
if (UnExp.Operand is MemberExpression)
{
Exp = (MemberExpression)UnExp.Operand;
}
else
throw new ArgumentException();
}
else if (GetPropertyLambda.Body is MemberExpression)
{
Exp = (MemberExpression)GetPropertyLambda.Body;
}
else
{
throw new ArgumentException();
}
return (PropertyInfo)Exp.Member;
}
public static IList<Order> getFilteredOrders(int propFilterValue, IList<Order> orders, String needle)
{
var filterValue = (OrderSearchableProp)propFilterValue;
var filterProp = OrderSearchableMap[filterValue];
var lowNeedle = needle?.ToLower() ?? String.Empty;
return orders.Where(o =>
{
var propInfo = GetPropertyFromExpression<Order, String>(filterProp);
var propValue = (String) propInfo.GetValue(o) ?? String.Empty;
return propValue.ToLower().Contains(lowNeedle);
}).ToList();
}
static void Main(string[] args)
{
// can be used to populate the combo items
// otherwise, not used in this example
OrderSearchableProp[] enumValues = (OrderSearchableProp[])Enum.GetValues(typeof(OrderSearchableProp));
// test orders
var orderList = new List<Order>()
{
new Order() { OrderNo = "1234ABC", FirstName = "George", LastName = "Taylor", Misc = "Extra information"},
new Order() { OrderNo = "AB10", FirstName = "Anonymous", LastName = "X", Misc = "No comment"}
};
// test OrderNo search
var searchProp = (int) OrderSearchableProp.OrderNo;
var foundOrders = getFilteredOrders(searchProp, orderList, "ABC");
// test FirstName search
searchProp = (int)OrderSearchableProp.FirstName;
foundOrders = getFilteredOrders(searchProp, orderList, "a");
// test LastName search with empty string
searchProp = (int)OrderSearchableProp.LastName;
foundOrders = getFilteredOrders(searchProp, orderList, "");
// empty return
searchProp = (int)OrderSearchableProp.OrderNo;
foundOrders = getFilteredOrders(searchProp, orderList, null);
}
}

pick any string to display in a text box in EF

Using Entity framework how can I pick any string to display in a textbox. Using myReader in the past I would do the following:
while (myReader.Read())
{
string sName = myReader.GetString(1);
txtName.Text = sName;
}
You have to load the entity (=table) you desire and than assign the property of the entity to the textbox.
Something like:
using (var myContext = new EntityContext())
{
myContext.TableName.Load(); //this will load all rows from the table
var list = myContext.TableName.Local; //.Local is a list of the entities which gets populated when you cann the Load() method
//now you can either enumarte your list like so
foreach (TableName item in list)
{
string sName = item.PropertyName; //PropertyName is the property you want to display, this would be like using not an index in myReader.GetString(1) but the columnname myReader.GetString("ColumnName")
txtName.Text = sName;
}
//or if you want to get a certain item out of your list you can use LINQ/MethodChains
//MethodChain
var item = list.First(x => x.PropertyName == "HelloWorld!");
string sName = item.PropertyName;
txtName.Text = sName;
//LINQ
var item = (from x in list
where x.PropertyName == "HelloWorld!"
select x).First();
string sName = item.PropertyName;
txtName.Text = sName;
//the methodchain and linq is a "new" technology that simplifies this code (which does the same)
TableName item = null;
foreach (TableName tempItem in list)
{
if (tempItem.PropertyName == "HelloWorld!")
{
item = tempItem;
break;
}
}
string sName = item.PropertyName;
txtName.Text = sName;
}

Unable to populate a DataGridViewComboBoxColumn created at design time

I have a DataGridViewComboBoxColumn being craeted at design time.But I want to polulate it at runtime. But it is not happening.
Here is the entire code
public partial class Form1 : Form
{
private List<FileInformation> FileInformationList;
public Form1()
{
InitializeComponent();
PrepareGrid();
DisplayResult();
}
private void PrepareGrid()
{
var fileNameColumn = new DataGridViewTextBoxColumn
{
Name = #"FileName",
HeaderText = "File Name",
DataPropertyName = #"FileName",
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
ReadOnly = false,
Frozen = false
};
dataGridView1.Columns.Add(fileNameColumn);
var downloadColumn = new DataGridViewLinkColumn
{
Name = #"Download",
HeaderText = #"Download",
DataPropertyName = #"Download",
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
ReadOnly = true
};
dataGridView1.Columns.Add(downloadColumn);
var dropdownColumn = new DataGridViewComboBoxColumn
{
Name = #"Test",
HeaderText = #"Country",
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
ReadOnly = true
};
dataGridView1.Columns.Add(dropdownColumn);
}
private void DisplayResult()
{
FileInformationList = LoadItems();
dataGridView1.DataSource = FileInformationList;
((DataGridViewComboBoxColumn)dataGridView1.Columns["Test"]).DataSource = GetCountryList();
((DataGridViewComboBoxColumn)dataGridView1.Columns["Test"]).ValueMember = "id";
((DataGridViewComboBoxColumn)dataGridView1.Columns["Test"]).DisplayMember = "Name";
}
private List<FileInformation> LoadItems()
{
var lstScriptInfo = new List<FileInformation>();
for (int i = 1; i <= 5; i++)
{
lstScriptInfo.Add(new FileInformation { FileName = "File" + i.ToString() + ".txt" });
}
return lstScriptInfo;
}
private DataTable GetCountryList()
{
DataTable CountryDt = new DataTable();
CountryDt.Columns.Add("id");
CountryDt.Columns.Add("Name");
CountryDt.Rows.Add("1", "Canada");
CountryDt.Rows.Add("2", "USA");
return CountryDt;
}
}
public class FileInformation
{
public string FileName { get; set; }
public string Download { get { return "Download File"; } }
}
}
The output is
Please help me to identity what has went wrong?
Two ways to achieve that:
Setting defualt null value for column (skipped null checks):
var cbColumn = (DataGridViewComboBoxColumn)dataGridView1.Columns["Test"];
var ds = GetCountryList();
cbColumn.DataSource = ds;
cbColumn.ValueMember = "id";
cbColumn.DisplayMember = "Name";
cbColumn.DefaultCellStyle.NullValue = ds.Rows[0][0];
cbColumn.DefaultCellStyle.DataSourceNullValue = ds.Rows[0][1];
Second is to iterate after DataBinding and set it manually:
private void DataGridDataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
var hasValue = row.Cells["Test"].Value != null;
if (!hasValue)
{
row.Cells["Test"].Value = 1;
}
}
}
also I'd change binding order:
private void DisplayResult()
{
var cbColumn = (DataGridViewComboBoxColumn)dataGridView1.Columns["Test"];
var ds = GetCountryList();
cbColumn.DataSource = ds;
cbColumn.ValueMember = "id";
cbColumn.DisplayMember = "Name";
cbColumn.DefaultCellStyle.NullValue = ds.Rows[0][0];
cbColumn.DefaultCellStyle.DataSourceNullValue = ds.Rows[0][1];
FileInformationList = LoadItems();
dataGridView1.DataSource = FileInformationList;
}

Resources