Why does my UIPickerView crashing when selecting - c#

I have created a sample on github Github link
When clicking on a row or trying to scroll in the UIPickerView it will crash and i wonder why.
// create a ActionSheet
var actionPickerSheet = new UIActionSheet("Select a Category");
actionPickerSheet.Style = UIActionSheetStyle.BlackTranslucent;
// Create UIpickerView
var catPicker = new UIPickerView(){
Model = new catPickerModel(),
AutosizesSubviews = true,
Hidden = false,
ShowSelectionIndicator = true
};
// show inside view and add the catPicker as subView
actionPickerSheet.ShowInView(View);
actionPickerSheet.AddSubview(catPicker);
// resize both views so it fits smoothly
actionPickerSheet.Frame = new RectangleF(0,100,320,500);
catPicker.Frame = new RectangleF(actionPickerSheet.Frame.X,actionPickerSheet.Frame.Y-25,actionPickerSheet.Frame.Width, 216);
And the Model
private class catPickerModel : UIPickerViewModel
{
public string[] protocolNames = new string[]
{
"Web", "Phone Call", "Google Maps", "SMS", "Email"
};
public override int GetComponentCount(UIPickerView uipv)
{
return 1;
}
public override int GetRowsInComponent( UIPickerView uipv, int comp)
{
//each component has its own count.
int rows = protocolNames.Length;
return(rows);
}
public override string GetTitle(UIPickerView uipv, int row, int comp)
{
//each component would get its own title.
return protocolNames[row];
}
public override void Selected(UIPickerView uipv, int row, int comp)
{
Console.WriteLine("selected:" + row);
}
public override float GetComponentWidth(UIPickerView uipv, int comp)
{
return 300f;
}
}
I have no idea why it keeps crashing, is it some method i am missing in the Model or am i trying to do this in the wrong way ?
Thanks

Try to make your catPicker to a private variable of the class:
namespace TextfieldUIPickerView
{
public partial class TextfieldUIPickerViewViewController : UIViewController
{
private UIPickerView catPicker;
...
Looks like the GC has collected your catPicker and disposed it.

Related

Building an Editor for nested ScriptableObjects to compose abilities in a card game

I'm building a card game and I'd like to have a clean architecture for card abilities.
I've got a CardData ScriptableObject with properties for a card. I want card abilities to compose together to describe what a card does, like a card called DrawAndHealCard that draws 2 cards and heals 5 health when played.
I realized right away that this means I'll need a concrete asset for each variation of a CardAbility. So DrawAndHealCard has a reference to two assets: DrawCards2 and HealPlayer5. That's ridiculous, I want all the data to feel like it's on a single DrawAndHealCard.
So I learned about AssetDatabase.AddObjectToAsset(), this seems like the right idea, I can have the abilities as sub-assets of a CardData asset and not have deal with the organization of all these separate assets. So now I'm trying to build an Editor to manage this and it is painful.
I've read so much stuff about Unity serialization, SOs, Editor scripts, ... seriously hitting a wall with this and about to downgrade to something that feels less elegant architecturally. If there's a better way to do this, I'm open to suggestions about totally different routes too.
Code below is stripped down, but it's the gist of what I'm trying to figure out.
Where I'm at right now is onAddCallback seems to be adding a sub-asset correctly, but onRemoveCallback does not remove it. My Clear All Abilities button does work however. I can't find any good docs or guides about this stuff, so I'm pretty lost currently.
// CardData.cs
[CreateAssetMenu(fileName = "CardData", menuName = "Card Game/CardData", order = 1)]
public class CardData : ScriptableObject
{
public Sprite image;
public string description;
public CardAbility[] onPlayed;
}
// CardAbility.cs
public class CardAbility : ScriptableObject
{
public abstract void Resolve();
}
// DrawCards.cs
public class DrawCards : CardAbility
{
public int numCards = 1;
public override void Resolve()
{
Deck.instance.DrawCards(numCards);
}
}
// HealPlayer.cs
public class HealPlayer : CardAbility
{
public int healAmt = 10;
public override void Resolve()
{
Player.instance.Heal(healAmt);
}
}
// CardDataEditor.cs
[CustomEditor(typeof(CardData))]
public class CardDataEditor : Editor
{
private ReorderableList abilityList;
public void OnEnable()
{
abilityList = new ReorderableList(
serializedObject,
serializedObject.FindProperty("onPlayed"),
draggable: true,
displayHeader: true,
displayAddButton: true,
displayRemoveButton: true);
abilityList.onRemoveCallback = (ReorderableList l) => {
l.serializedProperty.serializedObject.Update();
var obj = l.serializedProperty.GetArrayElementAtIndex(l.index).objectReferenceValue;
DestroyImmediate(obj, true);
AssetDatabase.SaveAssets();
l.serializedProperty.DeleteArrayElementAtIndex(l.index);
l.serializedProperty.serializedObject.ApplyModifiedProperties();
};
abilityList.onAddCallback = (ReorderableList l) => {
var index = l.serializedProperty.arraySize;
l.serializedProperty.arraySize++;
l.index = index;
var element = l.serializedProperty.GetArrayElementAtIndex(index);
// Hard coding a specific ability for now
var cardData = (CardData)target;
var newAbility = ScriptableObject.CreateInstance<DrawCards>();
newAbility.name = "test";
newAbility.numCards = 22;
element.objectReferenceValue = newAbility;
AssetDatabase.AddObjectToAsset(newAbility, cardData);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
serializedObject.ApplyModifiedProperties();
};
// Will use this to provide a menu of abilities to choose from.
/*
abilityList.onAddDropdownCallback = (Rect buttonRect, ReorderableList l) => {
var menu = new GenericMenu();
var guids = AssetDatabase.FindAssets("", new[]{"Assets/CardAbility"});
foreach (var guid in guids) {
var path = AssetDatabase.GUIDToAssetPath(guid);
menu.AddItem(new GUIContent("Mobs/" + Path.GetFileNameWithoutExtension(path)), false, clickHandler, new WaveCreationParams() {Type = MobWave.WaveType.Mobs, Path = path});
}
menu.ShowAsContext();
};
*/
// Will use this to render CardAbility properties
/*
abilityList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => {
};
*/
}
public override void OnInspectorGUI()
{
serializedObject.Update();
DrawDefaultInspector();
abilityList.DoLayoutList();
// XXX: Ultimately don't expect to use these, experimenting with
// other ways of adding/deleting.
if (GUILayout.Button("Add Ability")) {
var cardData = (CardData)target;
var newAbility = ScriptableObject.CreateInstance<CardAbility>();
AssetDatabase.AddObjectToAsset(newAbility, cardData);
AssetDatabase.SaveAssets();
}
if (GUILayout.Button("Clear All Abilities")) {
var path = AssetDatabase.GetAssetPath(target);
Object[] assets = AssetDatabase.LoadAllAssetRepresentationsAtPath(path);
for (int i = 0; i < assets.Length; i++) {
if (assets[i] is CardAbility) {
Object.DestroyImmediate(assets[i], true);
}
}
AssetDatabase.SaveAssets();
}
serializedObject.ApplyModifiedProperties();
}
}
Ok I finally figured this out. I read a hundred stack overflow and forum posts trying to understand this, so I'm paying it forward, hopefully this helps someone else navigate this. This produces an Editor like the image below, where OnPlayed is an array of polymorphic ScriptableObjects. These CardAbility SO's are stored as sub-assets on the owning ScriptableObject (CardData). Still more to clean up here, and it could be made more generic, but should be a good start for someone else trying to do this.
The [+] button produces a list of all CardAbility SO's that are available to add.
And the properties for a concrete CardAbility are rendered dynamically.
One of the weirdest thing about all this is that you can't render the contents of an objectReferenceValue using PropertyField, you have to construct a SerializedObject first like this:
SerializedObject nestedObject = new SerializedObject(element.objectReferenceValue);
Thanks to Unity: Inspector can't find field of ScriptableObject for that tip.
Some other great resources for ReorderableList:
https://va.lent.in/unity-make-your-lists-functional-with-reorderablelist/
https://sites.google.com/site/tuxnots/gamming/unity3d/unitymakeyourlistsfunctionalwithreorderablelist
https://sandordaemen.nl/blog/unity-3d-extending-the-editor-part-3/
// CardData.cs
[CreateAssetMenu(fileName = "CardData", menuName = "Card Game/CardData", order = 1)]
public class CardData : ScriptableObject
{
public enum CardType
{
Attack,
Skill
}
public CardType type;
public Sprite image;
public string description;
// XXX: Hidden in inspector because it will be drawn by custom Editor.
[HideInInspector]
public CardAbility[] onPlayed;
}
// CardAbility.cs
public abstract class CardAbility : ScriptableObject
{
public abstract void Resolve();
}
// DrawCards.cs
public class DrawCards : CardAbility
{
public int numCards = 1;
public override void Resolve()
{
Deck.instance.DrawCards(numCards);
}
}
// HealPlayer.cs
public class HealPlayer : CardAbility
{
public int healAmount = 10;
public override void Resolve()
{
Player.instance.Heal(healAmount);
}
}
// CardDataEditor.cs
[CustomEditor(typeof(CardData))]
[CanEditMultipleObjects]
public class CardDataEditor : Editor
{
private ReorderableList abilityList;
private SerializedProperty onPlayedProp;
private struct AbilityCreationParams {
public string Path;
}
public void OnEnable()
{
onPlayedProp = serializedObject.FindProperty("onPlayed");
abilityList = new ReorderableList(
serializedObject,
onPlayedProp,
draggable: true,
displayHeader: true,
displayAddButton: true,
displayRemoveButton: true);
abilityList.drawHeaderCallback = (Rect rect) => {
EditorGUI.LabelField(rect, "OnPlayed Abilities");
};
abilityList.onRemoveCallback = (ReorderableList l) => {
var element = l.serializedProperty.GetArrayElementAtIndex(l.index);
var obj = element.objectReferenceValue;
AssetDatabase.RemoveObjectFromAsset(obj);
DestroyImmediate(obj, true);
l.serializedProperty.DeleteArrayElementAtIndex(l.index);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
ReorderableList.defaultBehaviours.DoRemoveButton(l);
};
abilityList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => {
SerializedProperty element = onPlayedProp.GetArrayElementAtIndex(index);
rect.y += 2;
rect.width -= 10;
rect.height = EditorGUIUtility.singleLineHeight;
if (element.objectReferenceValue == null) {
return;
}
string label = element.objectReferenceValue.name;
EditorGUI.LabelField(rect, label, EditorStyles.boldLabel);
// Convert this element's data to a SerializedObject so we can iterate
// through each SerializedProperty and render a PropertyField.
SerializedObject nestedObject = new SerializedObject(element.objectReferenceValue);
// Loop over all properties and render them
SerializedProperty prop = nestedObject.GetIterator();
float y = rect.y;
while (prop.NextVisible(true)) {
if (prop.name == "m_Script") {
continue;
}
rect.y += EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(rect, prop);
}
nestedObject.ApplyModifiedProperties();
// Mark edits for saving
if (GUI.changed) {
EditorUtility.SetDirty(target);
}
};
abilityList.elementHeightCallback = (int index) => {
float baseProp = EditorGUI.GetPropertyHeight(
abilityList.serializedProperty.GetArrayElementAtIndex(index), true);
float additionalProps = 0;
SerializedProperty element = onPlayedProp.GetArrayElementAtIndex(index);
if (element.objectReferenceValue != null) {
SerializedObject ability = new SerializedObject(element.objectReferenceValue);
SerializedProperty prop = ability.GetIterator();
while (prop.NextVisible(true)) {
// XXX: This logic stays in sync with loop in drawElementCallback.
if (prop.name == "m_Script") {
continue;
}
additionalProps += EditorGUIUtility.singleLineHeight;
}
}
float spacingBetweenElements = EditorGUIUtility.singleLineHeight / 2;
return baseProp + spacingBetweenElements + additionalProps;
};
abilityList.onAddDropdownCallback = (Rect buttonRect, ReorderableList l) => {
var menu = new GenericMenu();
var guids = AssetDatabase.FindAssets("", new[]{"Assets/CardAbility"});
foreach (var guid in guids) {
var path = AssetDatabase.GUIDToAssetPath(guid);
var type = AssetDatabase.LoadAssetAtPath(path, typeof(UnityEngine.Object));
if (type.name == "CardAbility") {
continue;
}
menu.AddItem(
new GUIContent(Path.GetFileNameWithoutExtension(path)),
false,
addClickHandler,
new AbilityCreationParams() {Path = path});
}
menu.ShowAsContext();
};
}
private void addClickHandler(object dataObj) {
// Make room in list
var data = (AbilityCreationParams)dataObj;
var index = abilityList.serializedProperty.arraySize;
abilityList.serializedProperty.arraySize++;
abilityList.index = index;
var element = abilityList.serializedProperty.GetArrayElementAtIndex(index);
// Create the new Ability
var type = AssetDatabase.LoadAssetAtPath(data.Path, typeof(UnityEngine.Object));
var newAbility = ScriptableObject.CreateInstance(type.name);
newAbility.name = type.name;
// Add it to CardData
var cardData = (CardData)target;
AssetDatabase.AddObjectToAsset(newAbility, cardData);
AssetDatabase.SaveAssets();
element.objectReferenceValue = newAbility;
serializedObject.ApplyModifiedProperties();
}
public override void OnInspectorGUI()
{
serializedObject.Update();
DrawDefaultInspector();
abilityList.DoLayoutList();
if (GUILayout.Button("Delete All Abilities")) {
var path = AssetDatabase.GetAssetPath(target);
Object[] assets = AssetDatabase.LoadAllAssetRepresentationsAtPath(path);
for (int i = 0; i < assets.Length; i++) {
if (assets[i] is CardAbility) {
Object.DestroyImmediate(assets[i], true);
}
}
AssetDatabase.SaveAssets();
}
serializedObject.ApplyModifiedProperties();
}
}
Not sure since Editor scripting is always quite tricky if you don't have a full project in front of you.
On first glance I would say you are adding the assets to the asset but you do not remove them using AssetDatabase.RemoveObjectFromAsset
You should probably do something like
abilityList.onRemoveCallback = (ReorderableList l) =>
{
// Update should be redundant here since you already call it anyway on beginning of the draw loop
// Are you also sure the `l.index` is the correct value to use here?
var obj = l.serializedProperty.GetArrayElementAtIndex(l.index).objectReferenceValue;
AssetDatabase.RemoveObjectFromAsset(obj);
DestroyImmediate(obj, true);
l.serializedProperty.DeleteArrayElementAtIndex(l.index);
// If you do save assets also refresh
// Not sure if you should even do that though to be honest
AssetDatabase.SaveAssets();
// Also refresh here
AssetDatabase.Refresh();
// Also ApplyModifiedProperties should be redundant
};
also as commented I think you wouldn't even have to use
AssetDatabase.SaveAssets();
without it the assets would simply be marked as dirty and be saved along with the scene on the next CTRL+S press.
However, afaik, if you do it you should always combine it with AssetDatabase.Refresh(); to actually see the changes made reflected in the assets view

How to allow my client to interact with Lists of my code without Unity software?

I'm working on a fortune gift program.There is atleast 2 different fortune gift with a list of itself. Client also want to set the percentages of fortune gift by themself. I don't know how to let them do it. How can I let them edit the list (add more GValue, edit GWeight) and create another List?
public class GiftValue
{
public int GValue;
public int GWeight;
public GiftValue(int gvalue, int gweight)
{
GValue = gvalue;
GWeight = gweight;
}
}
public List<GiftValue> GiftwithWeight = new List<GiftValue>
{
new GiftValue(1, 25),
new GiftValue(2, 25),
new GiftValue(3, 25),
new GiftValue(5, 20),
new GiftValue(4, 5),
};
private readonly List<int> _GiftList = new List<int>();
private void Start()
{
foreach (GiftValue kvp in GiftwithWeight)
{
for (int i = 0; i < kvp.GWeight; i++)
{
_GiftList.Add(kvp.GValue);
}
}
}
public int GetRandomNumber()
{
int randomIndex = Random.Range(0, _GiftList.Count);
randomnumber=randomIndex;
return _GiftList[randomIndex];
}
I would serialize those lists as JSON and load them at runtime.
Your client can replace this file or adjust values before he starts the application.
Code would look like this.
[Serializable]
public struct GiftValue
{
public int Value;
public int Weight;
}
[Serializable]
public class GiftConfig
{
public List<GiftValue> Gifts;
}
public void LoadConfig(string filePath) {
string fileContent = File.ReadAllText(filePath);
var giftConfig = JsonUtility.FromJson<GiftConfig>(fileContent);
}
JSON would look like this:
{
"Gifts":[
{
"Value":1,
"Weight":25
},
{
"Value":2,
"Weight":25
}
]
}
Edit: Added code and json

Using enum item to call a method

I have an enum with 30 items in it. Each item has a corresponding function with the same name. I would like to be able to call the function by referencing the enum at a certain position.
So if the value at enum[0] = Foo, I would like to be able to call Foo(string bar) by using something like enum(0)("foobar")
In the end the point is I am running each function as a task like so:
enum Test { AA, BB, CC, DD ....}
tasks[0] = Task.Run(() => { prices[0] = AA("a string"); });
tasks[1] = Task.Run(() => { prices[1] = BB("a string"); });
tasks[2] = Task.Run(() => { prices[2] = CC("a string"); });
//for 30 tasks
What I would like to do is something along the lines of:
enum Test { AA, BB, CC, DD ....}
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() => { prices[i] = (Test)i("a string"); });
}
Task.WaitAll(tasks.ToArray());
Is this something that is even possible?
EDIT:
The enum relates to controls on a form so i have an array of textboxs, label and a array of prices that is populated with the results of the functions:
enum Dealers { Dealer1, Dealer2 ... Dealer29, Dealer30 };
static int noOfDealers = Enum.GetNames(typeof(Dealers)).Length;
decimal[] prices = new decimal[noOfDealers];
TextBox[] textBox = new TextBox[noOfDealers];
Label[] boxes = new Label[noOfDealers];
for (int i = 0; i < noOfDealers; i++)
{
textBox[i] = Controls.Find("txt" + (Dealers)i, true)[0] as TextBox;
boxes[i] = Controls.Find("box" + (Dealers)i, true)[0] as Label;
prices[i] = 0;
}
//RUN 30 TASKS TO POPULATE THE PRICES ARRAY
for (int i = 0; i < noOfDealers; i++)
{
textBox[i].Text = "£" + prices[i].ToString();
}
//LOOP THROUGH PRICES ARRAY AND FIND CHEAPEST PRICE, THEN COLOUR THE LABEL BACKGROUND GREEN FOR THE TEXT BOX WITH THE NAME AT ENUM VALUE WHATEVER I IS
I guess i am just trying to make my code as concise as possible, there is the potential for the amount of tasks to double and didn't want to end up with 60 lines to populate the tasks array
I would create dictionary and map enum to actions:
Dictionary<Test, Func<string,double>> actions = new Dictionary<Test, Func<string,double>>()
{
{Test.AA, (x) => { return 5;}},
{Test.BB, (x) => { return 15; }},
}; //x is your string
var res = actions[Test.AA]("hello");
I would strongly suggest using a built in construct - like an extension method and a simple switch:
public static int GetPriceWithString(this Test test, string str)
{
switch (test)
{
case Test.AA:
break;
case Test.BB:
break;
case Test.CC:
break;
case Test.DD:
break;
default:
throw new ArgumentOutOfRangeException(nameof(test), test, null);
}
}
then your loop looks almost the same:
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() =>
{
prices[i] = ((Test)i).GetPriceWithString("a string");
});
}
What you want to do is possible with reflection, which can be a powerful tool - but ideally should only be used as a last resort, as it will hide what could be compile time errors, and cause less code readability.
Using a simple switch like this makes your code self-documented, so when you come back to this in a month you can quickly remember what the intention was.
How about using an array of delegates:
using System;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
private static int AA(string a) { return 0; }
private static int BB(string a) { return 1; }
private static int CC(string a) { return 2; }
private static Func<string, int>[] functions = new Func<string, int>[] { AA, BB, CC };
private static int[] prices = new int[functions.Length];
private static Task[] tasks = new Task[functions.Length];
static void Main(string[] args)
{
for (int i = 0; i < functions.Length; ++i)
tasks[i] = Task.Run(() => { prices[i] = functions[i]("a string"); });
Task.WaitAll(tasks);
}
}
}
An eg. speaks a lot more than words.
I used it in a winform so the this refers to win form.
I have assumed all your methods are public , have same signature & return the same type.
enum MyName { AA,BB,CC};
//Call this in one of your methods
string [] strVal= Enum.GetNames(typeof(MyName));
int x = CallFunction(strVal[0], "A");
int y = CallFunction(strVal[1], "h");
int z = CallFunction(strVal[1], "C");
//End Call this in one of your methods
int CallFunction(string strName,string strValue)
{
return Convert.ToInt32(this.GetType().InvokeMember(strName, BindingFlags.Public | BindingFlags.InvokeMethod|BindingFlags.Instance, null, this, new object[] { strValue }));
}
public int AA(string s)
{
return 1;
}
public int BB(string s)
{
return 2;
}
public int CC(string s)
{
return 3;
}
Another solution. I hope somebody will consider it as overkill :)
Create abstract class DealerBase.
public abstract class DealerBase
{
public string Name { get; }
public decimal Price { get; set; }
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
}
Then create classes for every dealers you have and implement own logic for UpdatePrice method.
public class Dealer1 : DealerBase
{
public Dealer1() : base("DealerOne") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerOneCalculationMethod();
}
}
public class Dealer2 : DealerBase
{
public Dealer2() : base("DealerTwo") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerTwoCalculationMethod();
}
}
And so on..
Then you just create collection of dealers which can be easily iterated
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
}
foreach(var dealer in dealers)
{
dealer.UpdatePrice();
}
You can loop dealers and generate textboxes, labels in the winforms.
But I suggest to use DataGridView where code will be tiny clearer.
First implement INotifyPropertyChanged interface in the base class DealerBase
public abstract class DealerBase : INotifyPropertyChanged
{
public string Name { get; }
protected decimal _Price;
public decimal Price
{
get { return _Price; }
set
{
if (Equals(_Price, value)) return;
_Price = value;
// next method will inform DataGridView about changes
// and update value there too
RaisePropertyChanged();
}
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
// Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
The in the Form you can create BindingList<DealerViewModelBase> and set it to DataGridView.DataSource
public class YourForm: Form
{
public YourForm()
{
InitializeComponent();
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
};
var bindSource = new BindingList<DealerBase>(dealers);
dataGridView.DataSource = bindSource;
}
// Add button which update prices for all dealers
private void ButtonUpdatePrices_Click(object sender, EventArgs e)
{
var dealers = (BindingList<DealerBase>)dataGridView.DataSource;
foreach (var dealer in dealers)
{
dealer.UpdatePrice();
// Because we call `RaisePropertyChanged` in
// setter of Price - prices will be automatically
// updated in DataGridView
}
}
}
Idea of this approach you put different logic of different dealers in the separated class which. Because all dealer classes will inherit from same abstract class you can add different dealers to the collection.
You already have hardcoded enums and correspondent method which you try to link together. This approach make using of dealers collection little bid easy

Can i add a row number in object list while mapping with automapper?

I want to add row number in object list.
here's the they i do it now but there must be better way
Profile for mapping
public class VendorEnquiryDM_TO_VM : Profile
{
public VendorEnquiryDM_TO_VM()
{
CreateMap<VENDORENQUIRY, VendorEnquiryVM>();
}
}
public class VendorEnquiryVM_TO_DM : Profile
{
public VendorEnquiryVM_TO_DM()
{
CreateMap<VENDOR_ENQUIRY, VendorEnquiryVM>().ReverseMap();
}
}
Register profile
cfg.AddProfile<VendorEnquiryDM_TO_VM>();
cfg.AddProfile<VendorEnquiryVM_TO_DM>();
This is how I add sno.
alldata = Mapper.Map<IEnumerable<Vendor_EnquiryVM>>(objDAO.getVendorEnquiry());
var _roles = alldata.Select((t, index) => new Vendor_EnquiryVM
{
sno = index + 1,
CONTACT_NO=t.CONTACT_NO,
DATE=t.DATE,
EMAIL=t.EMAIL,
id=t.id,
FIRST_NAME=t.FIRST_NAME,
wer=t.wer,
asdf=t.asdf
});
Due to just one serial no. I need to assign all properties and this is somewhat fraustrating to me for large model, please suggest me better way of doing this.
You can define a static Id and when you create the class, increment it by one
here how your class code should look like
public class Test
{
private static int mId = 0;
public Test()
{
mId = mId +1;
}
public int Id
{
get{ return mId;}
}
}
Here a demo
in order to use the same idea with collections like List, I applied some modifications and here what you can do
public class Test
{
private static int mIndex = 0; // this parameter will be incremented for each new Test
private int mId =0; // this parameter will hold the last incremented value
public Test()
{
mId = ++mIndex; // mIndex++ if you want to start with 0
}
public int Id
{
get{ return mId;}
}
}
Demo with lists
hope this will help you

C# custom object in combobox

I am relatively new to C# (WinForms), and had a question regarding combo boxes. I have a combo box of Reviewer objects (it is a custom class with an overridden ToString method) and am currently attempting to go through all the checked items and use them to generate a setup file.
Here is how the combo box is populated (populated on form load). Parameters is just a collection of linked lists and parsing code.
for (int i = 0; i < parameters.GetUsers().Count; i++)
{
UserList.Items.Add(parameters.GetUsersArray()[i], parameters.GetUsersArray()[i].isSelected());
}
Here is how I am trying to read it. setup is a StringBuilder. The problem is that GetID is not defined. Does the add function above cast the Reviewer object to a Object object? It looks a little funny since it creates a file fed into a Perl script. A sample desired output line looks like this: inspector0 => "chg0306",
for (int i = 0; i < UserList.CheckedItems.Count; i++)
{
setup.AppendLine("inspector" + i.ToString() + " => \t \"" +
UserList.CheckedItems[i].GetID() + "\",");
}
Here is the users class: (Sample User is ID = aaa0000 name: Bob Joe)
public class Reviewer
{
private string name;
private string id;
private bool selected;
public Reviewer(string newName, string newID, bool newSelected)
{
name = newName;
id = newID;
selected = newSelected;
}
public string GetName()
{
return name;
}
public override string ToString()
{
//string retVal = new string(' ', id.Length + name.Length + 1);
string retVal = id + '\t' + name;
return retVal;
}
public string GetID()
{
return id;
}
public bool isSelected()
{
return selected;
}
}
For posterity, here is the Parameters class:
public class ParameterLists
{
public ParameterLists()
{
projects = new LinkedList<string>();
reviewers = new LinkedList<Reviewer>();
}
public enum FileContents {
PROJECT_LIST,
USERS_LIST,
}
public LinkedList<Reviewer> GetUsers()
{
return reviewers;
}
public LinkedList<string> GetProjects()
{
return projects;
}
public Reviewer[] GetUsersArray()
{
Reviewer[] userArray = new Reviewer[reviewers.Count];
reviewers.CopyTo(userArray, 0);
return userArray;
}
public string[] GetProjectsArray()
{
String[] projectArray = new String[projects.Count];
projects.CopyTo(projectArray, 0);
return projectArray;
}
public void LoadParameters(string fileName)
{
//Reads the parameters from the input file.
}
private void CreateDefaultFile(string fileName)
{
// Create the file from the defaultfile , if it exists.
// Otherwise create a blank default file.
}
private LinkedList <string> projects;
private LinkedList <Reviewer> reviewers;
}
I am probably missing something simple, coming from embedded C++. Any help would be appreciated.
You have to cast that object:
((Reviewer)UserList.CheckedItems[i]).GetID()

Categories

Resources