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
Related
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;
}
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
i have a problem. i am using the BrightIdeasSoftware.TreeListView to create treeview in my windows form and i also take the reference of How to create a MultiColumn treeview like this in C# Winforms app but i am not success to create this. Can you please tell me what i am doing mistake to create the treeview. The complete description is below.
i want to add the dynamic collapsible Panel and into this want to add tree in this.
The data will display into the panel according the collapsible panel header id .
i have a parent id and that can have multiple child.
Status Column will display one image
below is my code that i am using to create the treeview
class Node
{
public string Name { get; private set; }
public string Column1 { get; private set; }
public string Column2 { get; private set; }
public List<Node> Children { get; private set; }
public Node(string name, string col1, string col2)
{
this.Name = name;
this.Column1 = col1;
this.Column2 = col2;
this.Children = new List<Node>();
}
}
private void InitializeFristTabValue()
{
if (_UserDAC == null)
_UserDAC = new UserDAC();
try
{
DataTable dtUserGroup = _UserDAC.GetAllSECGROUPS(appDirectory, this.FindForm().Name, "InitializeFristTabValue()").Tables[0];
CommonDataGridBind cc = new CommonDataGridBind();
cc.GridviewGrouping(dtUserGroup, kryptonOutlookGridUserGroup, true, "GROUPID");
DataTable SEC_Info = _UserDAC.GetSECAPPINFO(appDirectory, this.FindForm().Name, "InitializeFristTabValue()").Tables[0];
int Location = 0;
foreach (DataRow dtrow in SEC_Info.Rows)
{
int APPID;
int.TryParse(dtrow["APPID"].ToString(), out APPID);
collapsiblePanelobj = new CollapsiblePanel();
if (Location == 0)
{
collapsiblePanelobj.Collapse = false;
//collapsiblePanelobj.Dock = System.Windows.Forms.DockStyle.Fill;
this.collapsiblePanelobj.Size = new System.Drawing.Size(1000, 150);
//DataTable SEC_InfoTreeView = _UserDAC.GetAPPITEMSbyAPPID(APPID, appDirectory, this.FindForm().Name, "InitializeFristTabValue()").Tables[0];
// ADDNode(APPID);
treeListView1.Dock = System.Windows.Forms.DockStyle.Fill;
//_panelBox.Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left;
//_panelBox.Controls.Add(treeListView1);
//collapsiblePanelobj.Controls.Add(_panelBox);
collapsiblePanelobj.Controls.Add(treeListView1);
}
else
collapsiblePanelobj.Collapse = true;
Location = Location + 30;
collapsiblePanelobj.Name = dtrow["APPNAME"].ToString() + dtrow["APPID"].ToString();
collapsiblePanelobj.HeaderText = "PROGRAM: " + dtrow["APPNAME"].ToString();
collapsiblePanelobj.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
collapsiblePanelobj.BackColor = System.Drawing.Color.Transparent;
collapsiblePanelobj.HeaderCornersRadius = 5;
collapsiblePanelobj.HeaderFont = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold);
collapsiblePanelobj.HeaderImage = null;
collapsiblePanelobj.HeaderTextColor = System.Drawing.Color.Black;
collapsiblePanelobj.Location = new System.Drawing.Point(10, Location);
collapsiblePanelobj.RoundedCorners = true;
//this.collapsiblePanelobj.Dock = System.Windows.Forms.DockStyle.Fill;
this.collapsiblePanelobj.Size = new System.Drawing.Size(1000, 150);
collapsiblePanelobj.UseAnimation = true;
InitializeData(APPID);
FillTree();
AddTree();
panel1.Controls.Add(collapsiblePanelobj);
// GrpBoxUserGroupInfo.Controls.Add(collapsiblePanelobj);
}
}
catch (Exception ex)
{
LogsWrite(ex, appDirectory, this.FindForm().Name, "InitializeFristTabValue()");
}
}
public void ADDNode()
{
AddTree();
InitializeData();
FillTree();
}
private void AddTree()
{
treeListView1 = new BrightIdeasSoftware.TreeListView();
treeListView1.Dock = DockStyle.Fill;
this.Controls.Add(treeListView1);
}
private void InitializeData()
{
UserDAC _UserDAC = new UserDAC();
DataTable SEC_InfoTreeView = _UserDAC.GetAPPITEMSbyAPPID(2, "", this.FindForm().Name, "InitializeFristTabValue()").Tables[0];
data = new List<Node> {};
var parent1 = new Node("User Name ", "State ", "Static Caption ");
for (int i = 0; i < SEC_InfoTreeView.Rows.Count; i++)
{
int PrentID = Convert.ToInt32(SEC_InfoTreeView.Rows[i]["PARENTID"]);
if (PrentID == 0 && Convert.ToInt32(SEC_InfoTreeView.Rows[i]["INDENT"]) == 0)
{
data.Add(parent1);
var parentAdd = new Node(Convert.ToString(SEC_InfoTreeView.Rows[i]["USERNAME"]), "", Convert.ToString(SEC_InfoTreeView.Rows[i]["ACAPTION"]));
parent1 = parentAdd;
}
else if (PrentID != 0 && Convert.ToInt32(SEC_InfoTreeView.Rows[i]["INDENT"]) == 2)
{
parent1.Children.Add(new Node(Convert.ToString(SEC_InfoTreeView.Rows[i]["USERNAME"]), "", Convert.ToString(SEC_InfoTreeView.Rows[i]["ACAPTION"])));
}
}
}
private void FillTree()
{
// this.treeListView.SmallImageList = imageList1;
// set the delegate that the tree uses to know if a node is expandable
// treeListView1.Margin = new System.Windows.Forms.Padding(2, 1000, 2, 2);
treeListView1.CanExpandGetter = x => (x as Node).Children.Count > 0;
// set the delegate that the tree uses to know the children of a node
treeListView1.ChildrenGetter = x => (x as Node).Children;
// create the tree columns and set the delegates to print the desired object proerty
var nameCol = new BrightIdeasSoftware.OLVColumn("User Name", "Name");
nameCol.AspectGetter = x => (x as Node).Name;
nameCol.Width = treeListView1.Width / 3;
var col1 = new BrightIdeasSoftware.OLVColumn("State", "Column1");
col1.AspectGetter = x => (x as Node).Column1;
col1.Width = treeListView1.Width / 3;
var col2 = new BrightIdeasSoftware.OLVColumn("Static Caption", "Column2");
col2.AspectGetter = x => (x as Node).Column2;
col2.Width = treeListView1.Width / 3;
// add the columns to the tree
treeListView1.Columns.Add(nameCol);
treeListView1.Columns.Add(col1);
treeListView1.Columns.Add(col2);
// set the tree roots
this.treeListView1.Roots = data;
}
Thanks in advance for your help and comments
Basically I want to show a calendar when I edit some columns in my Datagridview.
Following How to: Host Controls in Windows Forms DataGridView Cells from MSDN I can add wanted kind of column at building.
But in my case, I have to use a datasource provided by an Excel reader which give headings have to be connected to date type columns.
private DataGridView AddCalendars(DataGridView dtgv)
{
dtgv.DataSource = controller.getEmptyDataTable(); // DataTable provided by excel reader
var l = dtgv.Columns.Count;
string[] dateColumns = {"date_received", "date_of_birth"};
for (var i = 0; i < l; ++i)
{
if ( dateColumns.Any( dtgv.Columns[i].HeaderText.Contains )
{
dtgv.Columns[i] = new CalendarColumn(); // this line does not work cause by readonly
}
}
return dtgv;
}
How can I apply Calendar Column control to selected columns ?
Or, how can I obtain same result by building Datagridview different way ?
find an acceptable solution working around this post http://www.codeproject.com/Questions/175124/placing-datetimepicker-in-datagridview
private DateTimePicker cellDateTimePicker;
private List<int> dateColumnsIndexes;
public MainForm()
{
InitializeComponent();
///
this.cellDateTimePicker = new DateTimePicker();
this.cellDateTimePicker.ValueChanged += new EventHandler(cellDateTimePickerValueChanged);
this.cellDateTimePicker.Visible = false;
this.cellDateTimePicker.CustomFormat = "dd/MM/yyyy";
this.cellDateTimePicker.Format = DateTimePickerFormat.Custom;
this.dataGridView1.Controls.Add(cellDateTimePicker);
(...)
}
private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
var index = masterDataGridView.CurrentCell.ColumnIndex;
if (this.dateColumnsIndexes.Contains(index))
{
Rectangle tempRect = this.dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
cellDateTimePicker.Location = tempRect.Location;
cellDateTimePicker.Width = tempRect.Width;
try
{
cellDateTimePicker.Value = DateTime.Parse(dataGridView1.CurrentCell.Value.ToString());
}
catch
{
cellDateTimePicker.Value = DateTime.Now;
}
cellDateTimePicker.Visible = true;
}
}
void cellDateTimePickerValueChanged(object sender, EventArgs e)
{
masterDataGridView.CurrentCell.Value = cellDateTimePicker.Value.ToString("dd/MM/yyyy");
cellDateTimePicker.Visible = false;
}
private void AddCalendars(DataGridView dtgv)
{
dateColumnsIndexes = new List<int>();
dtgv.DataSource = controller.getEmptyDataTable(); // DataTable provided by excel reader
var l = dtgv.Columns.Count;
string[] dateColumns = {"date_received", "date_of_birth"};
for (var i = 0; i < l; ++i)
{
if ( dateColumns.Any( dtgv.Columns[i].HeaderText.Contains )
{
dateColumnsIndexes.add(i);
}
}
}
I am currently working/experimenting with lists. I am able to determine with function GetNextTree the position of each item in my list such as: First, Next and Last. I have an already made list from an array ax but now I am trying to implement an insert button that will take values tree_type, tree_height, tree_price, tree_instock and create the item. Since I can point anywhere in my list, the insert will be intended to add an item after the currently pointed to item. That is where my question is: How can I add a new item after the currently pointed to item?
public class fruit_trees
{
private string tree_type = " ";
private int tree_height = 0;
public double tree_price = 0;
private int tree_instock = 0;
public fruit_trees next_tree;
public fruit_trees(string newtree, int newheight, double newprice, int newinstock)
{
tree_type = newtree;
tree_height = newheight;
tree_price = newprice;
tree_instock = newinstock;
next_tree = null;
}
public string GetTreeType
{
get { return tree_type;
}
}
public override string ToString()
{
return tree_type + " " + tree_height + " " + tree_price + " " + tree_instock;
}
}
public class ListForTrees
{
private fruit_trees first_tree;
public fruit_trees First_tree
{
get
{
return first_tree;
}
}
public fruit_trees last_tree;
public int current;
public int count = 0;
public ListForTrees(fruit_trees new_tree)
{
first_tree = new_tree;
last_tree = new_tree;
count = 1;
current = 0;
}
public ListForTrees(IEnumerable trees)
{
current = 0;
foreach (fruit_trees t in trees)
{
this.AddTree(t);
}
}
public fruit_trees GetNextTree()
{
//current = 0;
fruit_trees ft = first_tree;
if (current == count)
{
current = 0;
}
int i = 0;
while (i != current)
{
ft = ft.next_tree;
i++;
}
return ft;
}
}
ListForTrees mainlist = new ListForTrees();
private void BtnInsertTree_Click(object sender, EventArgs e)
{
try
{
int height = Convert.ToInt32(TxtTreeHeight.Text);
int stock = Convert.ToInt32(TxtTreeStock.Text);
double price = Convert.ToDouble(TxtTreePrice.Text);
fruit_trees treeadd = new fruit_trees(TxtTreeName.Text, height, price, stock);
mainlist.AddTree(treeadd);
}
catch
{
MessageBox.Show("Please check intput fields");
}
}
private void BtnGo_Click(object sender, EventArgs e)
{
fruit_trees[] ax = { new fruit_trees("cherry", 48, 12.95, 3),
new fruit_trees("pine", 36, 9.95, 8),
new fruit_trees("oak", 60, 14.95, 2),
new fruit_trees("peach", 54, 19.95, 3),
new fruit_trees("pear", 36, 11.85, 2),
new fruit_trees("apple", 62, 13.45, 5)
};
mainlist = new ListForTrees(ax);
fruit_trees current = mainlist.First_tree;
while (current != null)
{
TxtOutput.AppendText(current.ToString() + Environment.NewLine);
current = current.next_tree;
}
}
private void ShowFirstItem_Click(object sender, EventArgs e)
{
//Show Next Item
labelSpecificTree.Text = mainlist.First_tree.GetTreeType;
}
private void ShowNextItem_Click(object sender, EventArgs e)
{
fruit_trees obj = mainlist.GetNextTree();
if (obj.next_tree == null)
{
labelSpecificTree.Text = mainlist.First_tree.GetTreeType.ToString();
}
else
{
mainlist.current++;
labelSpecificTree.Text = obj.next_tree.GetTreeType.ToString();
}
}
private void ShowLastItem_Click(object sender, EventArgs e)
{
// Show First Item
labelSpecificTree.Text = mainlist.last_tree.GetTreeType;
}
So I'm slightly confused by what's going on here. You're implementing your own ArrayList like class which is not really a list at all... I don't really see the point of doing such things in C# but alright... Here's the method;
fruit_trees[] InsertNode(fruit_trees current, fruit_trees nNode)
{
fruit_trees[] temp = new fruit_trees[ax.Length + 1];
int i = 0;
while (ax[i] != current)
{
temp[i] = ax[i];
i++;
}
temp[i+1] = nNode;
while (i < ax.Length)
{
temp[i+1] = ax[i];
}
return temp;
}
call this like such;
ax = InsertNode(current, nNode);
What we're doing is making a new list with one extra slot, copying each fruit_tree over til we hit the node we want to insert after, then we copy the new tree in. After that we copy over the rest of the old array. Then we return the new array.