GridView and Dynamically adding Items - c#

I have searched a lot for this but really haven't found anything useful yet. So I am asking it here.
I am doing this in Xamarin Android and I have an ItemsGrid class which extends to BaseAdapter. Everything is working fine since I am able to populate the items and show the information I need to show but there is one thing that's not quite right and it is described as follows:
In my GridView I load more items dynamically as I click on a button but the first set of items is added when the activity is created. Everything works fine up to the point where I add more items. Because every time I add more items I set the Adapter to the ItemsGrid new instance (I use new instance every time). That way the items are loaded but the scroll viewer goes up to zero every time. So I added an auto scroll function to automatically scroll into view the first item of the newly created set of items.
The above is my approach currently but I am looking for something more nice and UI friendly as the new Items should be added after the already available items in the view as it happens with "UWP Apps in XAML".
Here is my code for "ItemsGrid.cs":
public class ItemsGrid : BaseAdapter
{
private Context mContext;
private int iCount = 0;
private int mCount = 0;
private string type = "";
private int[] mThumbIds = new int[24];
public override int Count
{
get
{
mThumbIds = getIds();
return mThumbIds.Count();
}
}
public ItemsGrid(Context c, int initialCount, int maxCount, string itemType)
{
mContext = c;
iCount = initialCount;
mCount = maxCount;
type = itemType;
}
private int[] getIds()
{
string[] ids = new string[10000];
for (int b = iCount; b < mCount; b++)
{
ids[b] = b + "";
}
int[] x = new int[mCount];
for (int a = 0; a < mCount; a++)
{
if (ids[a] != null)
{
x[a] = Convert.ToInt32(ids[a]);
}
}
return x;
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
RelativeLayout layout = new RelativeLayout(mContext);
ImageView image = new ImageView(mContext);
TextView text = new TextView(mContext);
TextView text2 = new TextView(mContext);
TextView text3 = new TextView(mContext);
if (type == "Movies")
{
Picasso.With(mContext).Load(MoviesActivity.MoviesImageLinks[position]).Into(image);
text.Text = MoviesActivity.MoviesTitles[position];
text2.Text = "Movie";
}
else if (type == "TV Shows")
{
Picasso.With(mContext).Load(TVShowsActivity.TVShowsImageLinks[position]).Into(image);
text.Text = TVShowsActivity.TVShowsTitles[position];
text2.Text = "TV Show";
}
else if (type == "Search")
{
Picasso.With(mContext).Load(SearchActivity.SearchImageLinks[position]).Into(image);
text.Text = SearchActivity.SearchTitles[position];
if (SearchActivity.SearchLinks[position].Contains("movie"))
{
text2.Text = "Movie";
}
else
{
text2.Text = "TV Show";
}
}
image.Id = 2;
//setting text
text.Id = 1;
text2.Id = 3;
text3.Id = 4;
text3.Text = (position + 1) + "";
text.SetSingleLine(true);
text.Ellipsize = Android.Text.TextUtils.TruncateAt.End;
// setting layout
int borderID = HelperClass.GetBorder(mContext);
layout.SetBackgroundResource(borderID);
RelativeLayout.LayoutParams textLayout = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent,
ViewGroup.LayoutParams.WrapContent);
textLayout.AddRule(LayoutRules.CenterHorizontal);
textLayout.AddRule(LayoutRules.AlignParentTop);
RelativeLayout.LayoutParams imageLayout = new RelativeLayout.LayoutParams(180,250);
imageLayout.AddRule(LayoutRules.CenterHorizontal);
imageLayout.AddRule(LayoutRules.Below, text.Id);
RelativeLayout.LayoutParams text2Layout = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent,
ViewGroup.LayoutParams.WrapContent);
text2Layout.AddRule(LayoutRules.CenterHorizontal);
text2Layout.AddRule(LayoutRules.Below, image.Id);
RelativeLayout.LayoutParams text3Layout = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent,
ViewGroup.LayoutParams.WrapContent);
text3Layout.AddRule(LayoutRules.CenterHorizontal);
text3Layout.AddRule(LayoutRules.Below, text2.Id);
text3Layout.TopMargin = 5;
//adding to layout
layout.AddView(text, textLayout);
layout.AddView(text2, text2Layout);
layout.AddView(image, imageLayout);
layout.AddView(text3, text3Layout);
return layout;
}
}
Scrolling into view:
mGridView.SmoothScrollToPosition(lastListItems - 24);
Getting Items from ItemsGrid class:
mGridView.Adapter = new ItemsGrid(this, lastListItems, numberOfLinks, type);
So if someone has any tips to share about how this can be achieved smoothly, please help me.
Thanks

Related

How to bind dynamically created text box?

I'm trying to create pricelist for hotel. I'm having a list of dates, and list of room types in hotel. That lists can contain random number of elements. That is created dynamically, and here is the code:
private void CreateControls() { var colIndex = 0;
var vrsteSoba = _Presenter.VrstaSobeDto.ToArray();
foreach (var bindingItem in vrsteSoba)
{
var lbl = new Label()
{
Width = LABEL_WIDTH,
Height = LABEL_HEIGHT - 5,
Left = 10,
Top = 30 + colIndex * (EDIT_BOX_HEIGHT + SPACE_BETWEEN_CONTROL),
Text = bindingItem
};
_dataPanel.Controls.Add(lbl);
colIndex++;
}
int a = 1;
foreach (var date in _Presenter.CeneTarifa)
{
int y = 0;
var panel = new Panel
{
Height = PANEL_HEIGHT * (vrsteSoba.Length-4),
Width = EDIT_BOX_WIDTH,
Left = a * (EDIT_BOX_WIDTH + SPACE_BETWEEN_CONTROL + 50),
Top = 5
};
_dataPanel.Controls.Add(panel);
var label = new Label
{
Height = EDIT_BOX_HEIGHT,
Location = new Point(0, 10),
Text = date.Datum,
Margin = new Padding(0)
};
panel.Controls.Add(label);
int index = 0;
foreach (var item in date.VrstaSobeCena)
{
var box = new TextBox();
panel.Controls.Add(box);
box.Height = EDIT_BOX_HEIGHT;
box.Width = EDIT_BOX_WIDTH;
box.Location = new Point(0, 30 + y * (EDIT_BOX_HEIGHT + SPACE_BETWEEN_CONTROL));
box.DataBindings.Add(new Binding(nameof(box.Text), date, date.Cena[index].Cena1));
y++;
index++;
}
++a;
}
_dataPanel.AutoScroll = true;
}`
Here is image of that representation.
Now I'm facing a problem of data binding. I need to bind price, two way, for each text box. And I'm stuck.
I have tried to bind it to property name, but then all boxes get same value. If I try to bind it to value via index, I'm getting error
Cannot bind to the property or column 34 on the DataSource. Parameter name: dataMember
Code below is used to fill model that is used in presenter
` private void FillCenePoTarifi() { var sobeArr = VrstaSobeDto.ToArray();
foreach (var datum in Datumi)
{
var dictionary = new Dictionary<string, decimal>();
var cene = new List<Cena>();
foreach (var item in sobeArr)
{
var tarif = _Tarife.Where(x => x.SifTarife == item).FirstOrDefault();
if (tarif != null)
_SastavTarife = HotelierServerLocal.Default.TarifaViewBlo.GetSastaveTarife(tarif.IdTarife);
//proveriti ovu logiku
var cena = _SastavTarife.Where(x => x.Cena1 != 0).Select(c => c.Cena1).FirstOrDefault();
cene.Add(new Cena { Cena1 = cena.ToString()});
dictionary.Add(item, cena);
}
var model = new CenePoTarifi
{
Datum = datum,
VrstaSobeCena = dictionary,
Cena = cene
};
CeneTarifa.Add(model);
}
}`
Finally here are classes that use as model.
` public class CenePoTarifi{
public Dictionary<string, decimal> VrstaSobeCena { get; set; } = new Dictionary<string, decimal>();
public string Datum { get; set; }
private List<Cena> _Cena;
public List<Cena> Cena
{
get => _Cena;
set
{
_Cena = value;
NotifyPropertyChanged("Cena");
}
}
public class Cena :
{
private string _Cena1;
public string Cena1
{
get => _Cena1;
set
{
_Cena = value;
NotifyPropertyChanged("Cena1");
}
}
}`
Does anyone has any suggestions?
Your question is: How to bind dynamically created text box. Here is one tested way for accomplishing that specific task.
First create some textboxes dynamically:
public MainForm()
{
InitializeComponent();
buttonRandom.Click += (sender, e) => generateRandomList();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
List<TextBox> tmp = new List<TextBox>();
for (int column = 1; column < tableLayoutPanel.ColumnCount; column++)
{
for (int row = 1; row < tableLayoutPanel.RowCount; row++)
{
TextBox textBox = new TextBox { Anchor = (AnchorStyles)0xF };
tableLayoutPanel.Controls.Add(textBox, column, row);
tmp.Add(textBox);
textBox.KeyDown += onAnyTextBoxKeyDown;
}
}
_textboxes = tmp.ToArray();
// Generate first dataset
generateRandomList();
}
TextBox[] _textboxes = null;
Then, whenever a new random list is generated, clear any old text and databindings from every TextBox before creating a new data binding for it.
public static Random Rando { get; } = new Random(2);
private void generateRandomList()
{
// Clear ALL the data + bindings for ALL the textboxes.
foreach (var textbox in _textboxes)
{
textbox.Clear();
textbox.DataBindings.Clear();
}
// Generate and create new bindings
int count = Rando.Next(1, 79);
for (int i = 0; i < count; i++)
{
var textbox = _textboxes[i];
VrstaSobeCena vrstaSobeCena =
new VrstaSobeCena{ Sobe = (Sobe)tableLayoutPanel.GetRow(textbox) };
textbox.Tag = vrstaSobeCena;
textbox.DataBindings.Add(
new Binding(
nameof(TextBox.Text),
vrstaSobeCena,
nameof(VrstaSobeCena.Cena),
formattingEnabled: true,
dataSourceUpdateMode: DataSourceUpdateMode.OnPropertyChanged,
null,
"F2"
));
// TO DO
// ADD vrstaSobeCena HERE to the Dictionary<string, decimal> VrstaSobeCena
}
}
The classes shown in your code as binding sources may not bind correctly. One issue I noticed is that the property setters are failing to check whether the value has actually changed before firing the notification. Here's an example of doing that correctly. (For testing purposes I'm showing a Minimal Reproducible Sample "mock" version of a class that implements INotifyPropertyChanged.)
enum Sobe { APP4 = 1, APP5, STUDIO, SUP, APP6, STAND, STDNT, COMSTU, LUXSTU, APP4C, APP4L, APP62, APP6L }
class VrstaSobeCena : INotifyPropertyChanged
{
decimal _price = 100 + (50 * (decimal)Rando.NextDouble());
public decimal Cena
{
get => _price;
set
{
if (!Equals(_price, value))
{
_price = value;
OnPropertyChanged();
}
}
}
Sobe _sobe = 0;
public Sobe Sobe
{
get => _sobe;
set
{
if (!Equals(_sobe, value))
{
_sobe = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Finally, one way to test the two-way binding is to intercept the [Enter] key.
private void onAnyTextBoxKeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.Enter) && (sender is TextBox textbox))
{
e.SuppressKeyPress = e.Handled = true;
VrstaSobeCena vrstaSobeCena = (VrstaSobeCena)textbox.Tag;
string msg = $"Price for {vrstaSobeCena.Sobe} is {vrstaSobeCena.Cena.ToString("F2")}";
BeginInvoke((MethodInvoker)delegate {MessageBox.Show(msg); });
SelectNextControl(textbox, forward: true, tabStopOnly: true, nested: false, wrap: true);
}
}
Create a List for storing the textbox:
List<TextBox> lstTextbox = new List<TextBox>();
Create a class object that stores the values of "Date" and "room type"
public class RoomTypeDate
{
public string RoomType = "";
public string DateRange = "";
}
Immediately after you created the textbox, assigned the RoomTypeDate info to the tag, add it to lstTextbox.
foreach (var item in date.VrstaSobeCena)
{
var box = new TextBox();
panel.Controls.Add(box);
box.Height = EDIT_BOX_HEIGHT;
box.Width = EDIT_BOX_WIDTH;
box.Location = new Point(0, 30 + y * (EDIT_BOX_HEIGHT + SPACE_BETWEEN_CONTROL));
box.DataBindings.Add(new Binding(nameof(box.Text), date, date.Cena[index].Cena1));
// add the box to the list
lstTextbox.Add(box);
// mark the box with RoomType and DateRange
RoomTypeDate rtd = new RoomTypeDate();
rtd.RoomType = "APP4"; // get the room type
rtd.DateRange = "1.6 - 30.6"; // get date range
box.Tag = rtd;
y++;
index++;
}
Now, to get and set the room price:
public void SetRoomPrice(decimal price, string roomType, string dateRange)
{
foreach (var tb in lstTextBox)
{
var rtd = (RoomTypeDate)tb.Tag;
if(rtd.RoomType == roomType && rtd.DateRange == dateRange)
{
tb.Text = price.ToString();
return;
}
}
}
public decimal GetRoomPrice(string roomType, string dateRange)
{
foreach (var tb in lstTextBox)
{
var rtd = (RoomTypeDate)tb.Tag;
if(rtd.RoomType == roomType && rtd.DateRange == dateRange)
{
return Convert.ToDecimal(rt.Text);
}
}
return 0m;
}
*code untested, might contains bugs

Winforms insert image into ListView / ImageList at index

Winforms, C#, VS2017
ImageList does not have an Insert method (however ListViewItemCollection does). I have tried a few different ways to insert a new image into the middle of a ListView and it's LargeImageList, but not getting it to work quite properly.
Anyone have any tried and true code that works properly?
This is what I have, but the images don't get synced properly to the items in the list.
protected void InsertThumbnail(string key, string keySelected)
{
var newImageList = new ImageList()
{
ImageSize = new Size(thumbWidth, thumbHeight)
};
var itemNew = new ListViewItem();
var foundSelected = false;
//lvAllPages.BeginUpdate();
for (int i = 0; i < lvAllPages.Items.Count; i++)
{
var item = lvAllPages.Items[i];
newImageList.Images.Add(item.Tag.ToString(), lvAllPages.LargeImageList.Images[i]);
if (item.Tag.ToString() == keySelected)
{
var image = batch.GetThumbnail(key);
newImageList.Images.Add(key, image);
itemNew = new ListViewItem()
{
BackColor = Color.Aquamarine,
ImageIndex = i,
Tag = key,
};
if (isLocal)
itemNew.Text = $"{GetFileName(key)} (insert) - {itemNew.ImageIndex}";
foundSelected = true;
}
if (foundSelected)
{
item.ImageIndex = item.ImageIndex + 1;
if (isLocal)
item.Text = $"{GetFileName(item.Tag.ToString())} - {item.ImageIndex}";
}
}
lvAllPages.LargeImageList.Dispose();
lvAllPages.LargeImageList = newImageList;
lvAllPages.Items.Insert(itemNew.ImageIndex, itemNew);
}
One more related thing, but not pertinent to the problems I am having. For anyone looking at this question and having similar issues, this helped with the issue of sorting items after inserting a new one. Default behavior when you insert a new ListViewItem at a given index, it will appear at the bottom of the list. I found this handy class to keep items sorted by index, which solved that problem:
class CompareByIndex : IComparer
{
private readonly ListView _listView;
public CompareByIndex(ListView listView)
{
this._listView = listView;
}
public int Compare(object x, object y)
{
int i = this._listView.Items.IndexOf((ListViewItem)x);
int j = this._listView.Items.IndexOf((ListViewItem)y);
return i - j;
}
}
And in the form load:
lvAllPages.ListViewItemSorter = new CompareByIndex(lvAllPages);
Obviously, that's a design decision. ImageList.Images is a ImageCollection and as such, it implements the IList interface.
Unfortunately, the Insert() method is allowed to throw a NotSupportedException. And that's what the list will do when used like a IList:
((IList)imageList.Images).Insert(5, new Bitmap(10,10));
System.NotSupportedException: 'Specified method is not supported.'
In order to have the images shown in a specific order, use the Add() method which takes the key:
imageList.Images.Add("1", new Bitmap(100,100));
That should also enable you to replace the image:
imageList.Images.RemoveByKey("1");
imageList.Images.Add("1", new Bitmap(200,200));
For that to work, you need to set the Sorting property:
listView1.Sorting = SortOrder.Ascending;
For storing additional information like path etc. use anotther data structure with the same key.
Here's the code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
ImageList imageList = new ImageList();
Dictionary<string, Metadata> metadata = new Dictionary<string, Metadata>();
private string dir = #"H:\temp";
private void button1_Click(object sender, EventArgs e)
{
// You would set this in the designer, probably
listView1.Sorting = SortOrder.Ascending;
listView1.View = View.LargeIcon;
listView1.LargeImageList = imageList;
// Make sure we start from the beginning
listView1.Items.Clear();
imageList.Images.Clear();
metadata.Clear();
// Add items
for (int i = 0; i < 10; i++)
{
var filename = "1 ("+(i+1)+").png"; // Just strange names I have
var fullFileName = Path.Combine(dir, filename);
imageList.Images.Add(i.ToString(), Bitmap.FromFile(fullFileName));
metadata.Add(i.ToString(), new Metadata{Path = fullFileName});
listView1.Items.Add(i.ToString(), "Image " + i, i.ToString());
}
// Update view
listView1.Refresh();
listView1.Invalidate();
}
private void button2_Click(object sender, EventArgs e)
{
for (int i = 3; i < 6; i++)
{
var filename = "1 ("+(i+2)+").png";
var fullFileName = Path.Combine(dir, filename);
// Change image
imageList.Images.RemoveByKey(i.ToString());
imageList.Images.Add(i.ToString(), Bitmap.FromFile(fullFileName));
// Match metadata and image
metadata[i.ToString()] = new Metadata{Path = fullFileName};
}
listView1.Refresh();
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
var key = listView1.SelectedItems[0].ImageKey;
label1.Text = metadata[key].Path;
}
else
{
label1.Text = "No image selected";
}
}
}
internal class Metadata
{
internal string Path;
}

C# Create Tracks Parents which Depend on Children

I'm trying to create tracks of Parent that have more than a child and put theme in dynamic ListBox
i have this ParentActivity table"
tblParentActivity
and I want to make tracks depend on ParentActivity table to be in ListBox like this:
Tracks in ListBox
the code so far:
private void TrackingActivity(long ParentActivityID)
{
DataTable dtActiveChild = objA.SelectActivityChild(ParentActivityID);
ListBox lstBox = new ListBox();
lstBox.ID = "lstTrack" + ParentActivityID.ToString();
lstBox.Width = 200;
pnlTrack.Controls.Add(lstBox);
for (int i = 0; i < dtActiveChild.Rows.Count; i++)
{
long ActivityChildID = Convert.ToInt64(dtActiveChild.Rows[i]["ActivityID"].ToString());
string ActivityChildName = dtActiveChild.Rows[i]["ActivityName"].ToString();
lstBox.Items.Add(new ListItem (ActivityChildName.ToString(),ActivityChildID.ToString()));
DataTable dtBrotherActivity = objA.selectBrotherActivity(ActivityChildID);
if (dtBrotherActivity.Rows.Count > 0)
{
TrackingActivity(ActivityChildID);
}
}
}
for example ParentActivityID=1;
selectBrotherActivity is query to get another child of it parent
it gave me distribution like this:
|1|2 3|4 5|7|9|10|7|9|10|6|8|9|10|
which || means ListBox
Ok thanks to everyone I found it:
protected void btnCreateTrack_Click(object sender, EventArgs e)
{
ListBox lstBoxParent = new ListBox();
lstBoxParent.ID = "lstTrack1";
lstBoxParent.Width = 200;
lstBoxParent.Height = 200;
pnlTrack.Controls.Add(lstBoxParent);
TrackingActivity(1, lstBoxParent );
}
private void TrackingActivity(long ParentActivityID, ListBox lstBoxParent)
{
chk:
DataTable dtActiveChild = objWFAI.SelectActivityChild(ParentActivityID);
string ActivityName = objWFA.CurrentActivityName(ParentActivityID);
lstBoxParent.Items.Add(new ListItem(ActivityName, ParentActivityID.ToString()));
for (int i = dtActiveChild .Rows.Count - 1; i >= 0; i--)
{
long ActivityChildID = Convert.ToInt64(dtActiveChild .Rows[i][" ActivityID"].ToString());
if (i != 0)
{
ListBox lstBoxChild = new ListBox();
lstBoxChild.ID = "lstTrack" + ActivityChildID.ToString();
lstBoxChild.Width = 200;
lstBoxChild.Height = 200;
pnlTrack.Controls.Add(lstBoxChild);
for (int p = 0; p < lstBoxParent.Items.Count; p++)
{
lstBoxChild.Items.Add(new ListItem(lstBoxParent.Items[p].Text, lstBoxParent.Items[p].Value));
}
TrackingActivity(ActivityChildID, lstBoxChild);
}
else
{
ParentActivityID = ActivityChildID ;
goto chk;
}
}

Loop is not storing data in array correctly C#

Hey guys I'm currently working on a bank program for a class project. The idea the user will need to make an account if not done so already but if they already do they can just login using account number and pin. However. instead of my program constantly adding data to an array that's size is 100 it just replaces the data in slot [0] just wondering why.
public partial class Form1 : MetroForm
{
//For Creating new account
string newAccountType;
Accounts[] customers = new Accounts[99999];
int temp;
string VerifyPin = ("");
private void openAccount_Click(object sender, EventArgs e)
{
for (int index=0;index < customers.Length; ++index)
{
var R1 = new Random();
var R2 = new Random();
customers[index] = new Accounts();
customers[index].Name = newName.Text;
customers[index].accountType = newAccountType;
customers[index].accountNumber = (R1.Next(1000000,9000000))+(R2.Next(100,9000));
customers[index].accountPin = createPin.Text;
customers[index].accountBalance = 100.00;
temp = index;
}
MetroMessageBox.Show(this, "Thank you member "+customers[temp].Name+"\nYour member number is: "+customers[temp].accountNumber, "You are now a memeber", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
metroTabControl1.SelectedTab = metroTabPage2;
}
private void checkBalance_Click(object sender, EventArgs e)
{
int veri=0;
bool isfound = false;
for (int count = 0; count < customers.Length; ++count)
{
if (Convert.ToInt32(userName.Text) == customers[count].accountNumber)
{
veri = count;
isfound = true;
}
else
isfound = false;
accountnotfound.Text = "Account Not Found";
}
if (isfound && (customers[veri].accountPin == pinText.Text))
{
MetroMessageBox.Show(this, "account found", "account found");
}
else
{
MetroMessageBox.Show(this, "account not found or wrong pin", "account not found");
pinText.Text = "";
}
accountBalance.Visible = true;
userWithdraw.Visible = true;
userDeposite.Visible = true;
accountBalance.Text = "Welcome, "+customers[veri].Name+"\nYour current balance is: "+customers[veri].accountBalance;
}
public class Accounts
{
private string name, AccountType, AccountPin;
private int AccountNumber;
private double AccountBalance;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public int accountNumber
{
get
{
return AccountNumber;
}
set
{
AccountNumber = value;
}
}
public string accountPin
{
get
{
return AccountPin;
}
set
{
AccountPin = value;
}
}
public string accountType
{
get
{
return AccountType;
}
set
{
AccountType = value;
}
}
public double accountBalance
{
get
{
return AccountBalance;
}
set
{
AccountBalance = value;
}
}
}
I think you just need to keep track of which element in the array is available (i.e. has a null value). Once no elements in the array are null, this means that the customers array is full, so you can't add any more customers at that point.
Make these following changes. In the part of the code just where the code starts the loop:
bool added = false;
for (int index=0;index < customers.Length; ++index)
{
if (customers[index] != null) continue;
...
Also, after you actually add a customer, do this (right after the loop ends):
if (!added)
{
// show error message here!
}
else
{
MetroMessageBox.Show(this, "Thank you member "+customers[temp].Name+"\nYour member number is: "+customers[temp].accountNumber, "You are now a memeber", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
metroTabControl1.SelectedTab = metroTabPage2;
}
for (int index=0;index < customers.Length; ++index)
customers[index] = new Accounts();
Index will be 0 every time your array loops, thus replacing customers[0] every time you openAccount_Click is called.
You don't really need to loop to add. You just need to make sure you are writing the next possible index. Maybe use your Temp variable and increment it + 1 for every user added and then without a loop do like do.
customers[Temp] = new Accounts();
customers[Temp].Name = newName.Text;
customers[Temp].accountType = newAccountType;
customers[Temp].accountNumber = (R1.Next(1000000,9000000))+ (R2.Next(100,9000));
customers[Temp].accountPin = createPin.Text;
customers[Temp].accountBalance = 100.00;
Temp += 1;
You would be better off using a List of Accounts for your customers global instead.
List<Accounts> customers = new List<Accounts>();
Then inside openAccount_Click you can add a new Accounts like so.
customers.Add(new Accounts {
Name = newName.Text,
accountType = newAccountType,
accountNumber = (R1.Next(1000000,9000000))+(R2.Next(100,9000)),
accountPin = createPin.Text,
accountBalance = 100.00
});
bool added = false;
for (int x = 0; x <= temp; x++)
{
if (customers[temp] != null) continue;
{
for (int indexies = 0; indexies < customers.Length; indexies++)
{
var R1 = new Random();
var R2 = new Random();
Convert.ToInt32(createPin.Text);
customers[temp] = new Accounts();
customers[temp].Name = newName.Text;
customers[temp].accountType = newAccountType;
customers[temp].accountNumber = 1;//(R1.Next(1000000, 9000000)) + (R2.Next(100, 9000));
customers[temp].accountPin = Convert.ToInt32(createPin.Text);
customers[temp].accountBalance = 100.00;
added = true;
}
}
}

how to add items to TreeViewAdv in multi-column mode with winforms

I was playing around with this control called TreeViewAdv. I've already added the control and added couple of columns trying to see how it works. but till now when I add items to the control all I get is empty nodes. the example provided with the control is not clear at all and it just gave me headaches when I try to figure out how the data is being added to it. anyway here is what I've done so far and I hope that someone can guide me to the right direction.
TreeModel _model = new TreeModel();
treeViewAdv1.Model = _model;
treeViewAdv1.BeginUpdate();
for (int i = 0; i < 20; i++)
{
Node parentNode = new Node("root" + i);
_model.Nodes.Add(parentNode);
for (int n = 0; n < 2; n++)
{
Node childNode = new MyNode("child" + n);
parentNode.Nodes.Add(childNode);
}
}
treeViewAdv1.EndUpdate();
anyway, all I'm getting is empty nodes and I really can't figure out how to add data to the other columns... any help would be appreciated...
Obviously this questions is old, but I was unable to find any answers to this question, so I figured I would try to save someone some future frustration.
To get multiple columns to display, first change the UseColumns property to true.
Then add desired columms to the Columns collection property.
Next using the NodeControls collection property to create a list of the types of data that will be shown, and how they should be formatted (Checkbox, TextBox, etc). Make sure to set 1) the DataPropertyName (will be used later), 2) the ParentColumn (to show which column in the treeView is supposed to show the data.
Finally, create a new class inheriting from the Node class, and add a public property with the same name as each NodeControl. Then when adding Nodes, use your new class with the correct value.
private class ColumnNode: Node
{
public string NodeControl1=""; // This sould make the DataPropertyName specified in the Node Collection.
public string NodeControl2 = "";
public string NodeControl3 = "";
public ColumnNode(string nodeControl1, string nodeControl2, int nodeControl3)
{
NodeControl1 = nodeControl1;
NodeControl2 = nodeControl2;
NodeControl3 = nodeControl3.ToString();
}
}
Then when adding the
TreeModel _model = new TreeModel();
_treeViewAdv.Model = _model;
_treeViewAdv.BeginUpdate();
for (int i = 0; i < 20; i++)
{
Node parentNode = new ColumnNode("root" + i, "",0);
_model.Nodes.Add(parentNode);
for (int n = 0; n < 2; n++)
{
Node childNode = new ColumnNode("child" + n,"Further Information",1);
parentNode.Nodes.Add(childNode);
}
}
_treeViewAdv.EndUpdate();
For reference, the designer code for the treeViewAdv in this case would look like this:
private Aga.Controls.Tree.TreeViewAdv _treeViewAdv;
private Aga.Controls.Tree.TreeColumn Column1;
private Aga.Controls.Tree.TreeColumn Column2;
private Aga.Controls.Tree.TreeColumn Column3;
private Aga.Controls.Tree.NodeControls.NodeTextBox NodeControl1;
private Aga.Controls.Tree.NodeControls.NodeTextBox NodeControl2;
private Aga.Controls.Tree.NodeControls.NodeTextBox NodeControl3;
private InitializeComponent()
{
// Left out all other initialization, since this was long enough already.
this.treeViewAdvPrint = new Aga.Controls.Tree.TreeViewAdv();
this.Column1 = new Aga.Controls.Tree.TreeColumn();
this.Column2 = new Aga.Controls.Tree.TreeColumn();
this.Column3 = new Aga.Controls.Tree.TreeColumn();
this.NodeControl1 = new Aga.Controls.Tree.NodeControls.NodeTextBox();
this.NodeControl2 = new Aga.Controls.Tree.NodeControls.NodeTextBox();
this.NodeControl3= new Aga.Controls.Tree.NodeControls.NodeTextBox();
//
// _treeViewAdv
//
this._treeViewAdv.BackColor = System.Drawing.SystemColors.Window;
this._treeViewAdv.Columns.Add(this.Column1);
this._treeViewAdv.Columns.Add(this.Column2);
this._treeViewAdv.Columns.Add(this.Column3);
this._treeViewAdv.DefaultToolTipProvider = null;
this._treeViewAdv.DragDropMarkColor = System.Drawing.Color.Black;
this._treeViewAdv.GridLineStyle = ((Aga.Controls.Tree.GridLineStyle)((Aga.Controls.Tree.GridLineStyle.Horizontal | Aga.Controls.Tree.GridLineStyle.Vertical)));
this._treeViewAdv.LineColor = System.Drawing.SystemColors.ControlDark;
this._treeViewAdv.Location = new System.Drawing.Point(12, 12);
this._treeViewAdv.Model = null;
this._treeViewAdv.Name = "_treeViewAdv";
this._treeViewAdv.NodeControls.Add(NodeControl1);
this._treeViewAdv.NodeControls.Add(NodeControl2);
this._treeViewAdv.NodeControls.Add(NodeControl3);
this._treeViewAdv.SelectedNode = null;
this._treeViewAdv.Size = new System.Drawing.Size(443, 356);
this._treeViewAdv.TabIndex = 6;
this._treeViewAdv.Text = "_treeViewAdv";
this._treeViewAdv.UseColumns = true;
//
// Column1
//
this.Column1.Header = "Column 1";
this.Column1.SortOrder = System.Windows.Forms.SortOrder.None;
this.Column1.TooltipText = null;
this.Column1.Width = 290;
//
// Column3
//
this.Column3.Header = "Column 3";
this.Column3.SortOrder = System.Windows.Forms.SortOrder.None;
this.Column3.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.Column3.TooltipText = null;
//
// Column2
//
this.Column2.Header = "Column 2";
this.Column2.SortOrder = System.Windows.Forms.SortOrder.None;
this.Column2.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.Column2.TooltipText = null;
this.Column2.Width = 91;
//
// NodeControl1
//
this.NodeControl1.DataPropertyName = "NodeControl1";
this.NodeControl1.IncrementalSearchEnabled = true;
this.NodeControl1.LeftMargin = 3;
this.NodeControl1.ParentColumn = this.Column1;
//
// NodeControl2
//
this.NodeControl2.DataPropertyName = "NodeControl2";
this.NodeControl2.IncrementalSearchEnabled = true;
this.NodeControl2.LeftMargin = 3;
this.NodeControl2.ParentColumn = this.Column2;
//
// NodeControl3
//
this.NodeControl3.DataPropertyName = "NodeControl3";
this.NodeControl3.IncrementalSearchEnabled = true;
this.NodeControl3.LeftMargin = 3;
this.NodeControl3.ParentColumn = this.Column3;
}
It seems as though the price of entry for using this fantastic control is hours, and hours, of head scratching frustration.
This is what you need to do:
private void Form1_Load(object sender, EventArgs e)
{
TreeModel _model = new TreeModel();
treeViewAdv1.Model = _model;
treeViewAdv1.BeginUpdate();
for (int i = 0; i < 20; i++)
{
Node parentNode = new Node("root" + i);
_model.Nodes.Add(parentNode);
for (int n = 0; n < 2; n++)
{
Node childNode = new Node("child" + n);
parentNode.Nodes.Add(childNode);
}
}
NodeTextBox ntb = new NodeTextBox();
ntb.DataPropertyName = "Text";
this.treeViewAdv1.NodeControls.Add(ntb);
treeViewAdv1.EndUpdate();
}
Just in case you're still struggling with the issue, or anyone else is having the same trouble: the solution to empty nodes is to assign a view component to tree.
TreeViewAdv uses MVC, and it requires that you assign a view, though this is not obvious from the example project. NodeTextBox class under NodeControls folder in the source of the TreeViewAdv is one of the viewers you can use. You need to add it to your form and connect it to tree control through its DataPropertyName attribute like this:
this._tBox.DataPropertyName = "Text";
where _tBox is the NodeTextBox instance. Needless to say, I've just lost hours figuring this out. Hope it helps someone else.
You need to instantiate your columns first, then attach them to the TreeView. After all add new cells in all columns at same cell index.
Hope to help

Categories