C# adding multiple images to same column in objectlistview - c#

I try to add image to my first column(it might be change to another column later, it's in first column for now), so far I have do
if (item.Index == 0)
{
item.ImageGetter = delegate (object RowObj)
{
return ((RowObjectModel)RowObj).ImageToShow.ToString();
};
}
this part at start, I use a custom headerstyle and apply it on constructor while I do that I also do ImageGetter part. I also set my SmallImageList like this
ImageList IList = new ImageList();
IList.Images.Add("MyIcon", Properties.Resources.MyIcon);
mainForm.objListview.SmallImageList = IList;
I have 2 problems with this code, first I can't set my image. It's not showing on my listview.
What I do to achieve that is this :
(objListview.GetItem(z).RowObject as RowObjectModel).ImageToShow = ThumbnailImages.MyIcon;
my enum is like this :
public enum ThumbnailImages
{
NULL = 0,
MyIcon = 1,
MyIcon2 = 2,
MyIcon3 = 3,
MyIcon4 = 4,
MyIcon5 = 5
}
Second problem is I have literally no clue on how I can add a second image in the same column of same row. I'm not even sure if this is possible.. But I have to do it somehow so I'm open to any ideas.
EDIT :
Okay I found the solution to my first problem. I was not using the UpdateObject/UpdateObjects method. I marked all my items with proper images they should show and use this method and everything worked. Now all I need is to find a way to show 2 images at the same time in 1 cell.
EDIT 2 :
About my second problem I found this class --> ImagesRenderer
http://objectlistview.sourceforge.net/cs/ownerDraw.html#imagesrenderer
But I could not found any working solution so far and I don't have any clue on how this is working?

Now all I need is to find a way to show 2 images at the same time in 1 cell.
You can work around the requirement to show 2 images by showing 1 image that contains both. The example below does that. One note is that you should probably build a cache up front of all the combinations so you can return them at high speed rather than building them in the ImageGetter delegate
olv.ShowGroups = false;
//make 2 images
var img1 = new Bitmap(10, 10);
var g = Graphics.FromImage(img1);
g.FillRectangle(new SolidBrush(Color.Pink),2,2,8,8 );
var img2 = new Bitmap(10, 10);
var g2 = Graphics.FromImage(img2);
g2.FillRectangle(new SolidBrush(Color.Blue),2,2,8,8 );
var col1 = new OLVColumn();
col1.AspectName = "ToString";
col1.ImageGetter += delegate(object rowObject)
{
if(rowObject == "1")
return img1;
if(rowObject == "2")
return img2;
if (rowObject == "3")
{
var comboImg = new Bitmap(img1.Width + img2.Width, img1.Height + img2.Height);
using (var g3 = Graphics.FromImage(comboImg))
{
g3.DrawImage(img1,new Point(0,0));
g3.DrawImage(img2,new Point(img1.Width,0));
}
return comboImg;
}
return null;
};
olv.Columns.Add(col1);
olv.AddObject("1");
olv.AddObject("2");
olv.AddObject("3");
}

The solution I found thanks to #Thomas N was this --->
In my objectlistview initializer I did this :
item.Renderer = new ImageRenderer();
item.AspectGetter = delegate (object RowObj)
{
return ((RowObjectModel)RowObj).ImagesToShow;
};
item represent here column 0. I'm iterating all my columns to apply HeaderFormatStyle. I figure I could do this here too.
and before I do this initializer I also set my images
ImageList IList = new ImageList();
IList.Images.Add("NULL", Properties.Resources.Null);
IList.Images.Add("MyIcon", Properties.Resources.MyIcon);
IList.Images.Add("MyIcon2", Properties.Resources.MyIcon2);
IList.Images.Add("MyIcon3", Properties.Resources.MyIcon3);
IList.Images.Add("MyIcon4", Properties.Resources.MyIcon4);
IList.Images.Add("MyIcon5", Properties.Resources.MyIcon5);
objListview.SmallImageList = IList;
and all I have to do is calling my method I wrote inside my model class
public void AddThumbnailImage(ThumbnailImages tImage)
{
if (tImage == ThumbnailImages.NULL)
{
ImagesToShow.Clear();
}
else
{
if (!ImagesToShow.Contains((int)tImage))
ImagesToShow.Add((int)tImage);
}
}
I know my solution is very similar to yours Thomas but I just wanted to show how I did it :)

Related

How to fix: Why is MyComboBox.Items.Count = 0, if I add as DataSource an List<MyClass> with 1 and more Elements?

I need some help.
I want to add an List as DataSource to a ComboBox.
The List contains 1 and more elements from type "Zaehler".
I use 3 comboBoxes in my GUI. Two times it works. I create a List Element and Add Elements of T. After this I set this List as DataSource. If I check with the debugger it says that the comboBox.Items = List..Count = comboBox.DataSource.Count.
private void LadeZaehlerDaten()
{
//NEUER ZÄHLER
List<Zaehler> zaehlerArten = new List<Zaehler>();
zaehlerArten.Add(new StromZaehler(1, "Stromzähler"));
zaehlerArten.Add(new GasZaehler(2, "Gaszähler"));
cb_ZaehlerArt.DataSource = zaehlerArten;
cb_ZaehlerArt.DisplayMember = "Name";
cb_ZaehlerArt.Sorted = true;
cb_ZaehlerArt.DropDownStyle = ComboBoxStyle.DropDownList;
Zaehler z = (Zaehler)cb_ZaehlerArt.SelectedItem;
// ... more code
}
This code works correctly... I have zaehlerArten with 2 Elements and in the ComboBox I have 2 Items bzw. DataSource.Count = 2.
after this I create a new Zaehler and add this to List zaehlerList that will contains all correct Zaehler.
This one goes wrong....
private void LadeVertragsDaten()
{
//NEUER VERTRAG
cb_VertragZaehler.DataSource = zaehlerList;
cb_VertragZaehler.DisplayMember = "Name"; //Property in Zaehler
cb_VertragZaehler.ValueMember = "ZaehlerNr"; //Property in Zaehler
//cb_VertragZaehler.Sorted = true;
cb_VertragZaehler.DropDownStyle = ComboBoxStyle.DropDownList;
if (cb_VertragZaehler.Items.Count < 1)
{
return;
}
else
{
Zaehler auswahl = (Zaehler)cb_VertragZaehler.SelectedItem;
}
}
If I check with the debugger ... it says das cb_VertragZaehler.Items is 0 but DataSource and zaehlerList count 2.
In my opinion I didn't do anything different. It should work the same like it does with LadeZaehlerDaten()
Since the Items of the ComboBox be 0 I can't use the information of this "Zaehler".
I did say DisplayMember is Name ... even through I did hope to use something like ZaehlerNr and Name ... booth are Properties of the class Zaehler.
Could someone say why it works in LadeZaehlerDaten() but not in LadeVertragsDaten()?
Picture: DebuggerInformation
And I really do not know why..
The list you try to assing should be immutable. Try to create a copy of it with cb_VertragZaehler.DataSource = new List<Zaehler>(zaehlerList);

Selecting the shortest item string from dropdownlist in C# Asp.net

I have multiple dynamically generated dropdownlists bound with database. I want the shortest string value to be shown at index 0 in each dropdown.
The sample code is:
DropDownList ddlTemplate = new DropDownList();
ddlTemplate.ID = "ddlTemplate|" + j.ToString();
ddlTemplate.AppendDataBoundItems = true;
ddlTemplate.DataTextField = "TemplateName";
ddlTemplate.DataValueField = "TemplateName";
ddlTemplate.Width = Unit.Pixel(200);
ddlTemplate.AutoPostBack = true;
ddlTemplate.DataSource = null;
ddlTemplate.DataSource = dsMultipleTemplate.Tables[j].DefaultView;
ddlTemplate.DataBind();
If it can be achieved through database query please guide me.
Thanks
As you arnt answering to the comment, maybe you are looking for something like that:
List<int> stringLength = new List<int> { }; // storing every length
foreach (string entry in ddlTemplate.Items)
{
stringLength.Add(entry.Length); // saving each string-length
}
int index = stringLength.FindIndex(a => a == stringLength.Min()); // get index of lowst length
ddlTemplate.SelectedIndex = index; // set selected value to index from above
This way, your item wouldnt be at index 0, but it would be selected. Placing it to index 0 is very basic. I guess you can do this on your own.

DynamicDataDisplay Line Graph plotter with multiple data sources?

I am trying to plot multiple curves in different color on my graph. I am currently using one plotter (not sure if that will work, and that is why I am posting a thread here), and here is my code:
if (_dataXChA != null && _dataXChA.Length > 1)
{
EnumerableDataSource<double> xChA = new EnumerableDataSource<double>(_dataXChA);
xChA.SetXMapping(xVal => xVal);
if (_dataYChA != null && _dataYChA.Length == _dataXChA.Length)
{
EnumerableDataSource<double> yChA = new EnumerableDataSource<double>(_dataYChA);
yChA.SetYMapping(yVal => yVal);
CompositeDataSource dsChA = new CompositeDataSource(xChA, yChA);
((LineGraph)plotter.Children.ElementAt(startIndex)).DataSource = dsChA;
plotter.FitToView();
}
}
if (_dataXChB != null && _dataXChB.Length > 1)
{
EnumerableDataSource<double> xChB = new EnumerableDataSource<double>(_dataXChB);
xChB.SetXMapping(xVal => xVal);
if (_dataYChB != null && _dataYChB.Length == _dataXChB.Length)
{
EnumerableDataSource<double> yChB = new EnumerableDataSource<double>(_dataYChB);
yChB.SetYMapping(yVal => yVal);
CompositeDataSource dsChB = new CompositeDataSource(xChB, yChB);
((LineGraph)plotter.Children.ElementAt(startIndex)).DataSource = dsChB;
//LineGraph lgChA = plotter.AddLineGraph(dsChB, _dataBrushColorChB, 1, "Data");
plotter.FitToView();
}
}
The first curve should be in green, and the second curve should be in red. plotter is CharterPlotter But when I look at the graph,I only got one curve. Then I looked at the data, it seems the curve displays the data from second data source, but the color of the curve is green.
The constructor assigns the color like this:
LineGraph lgChA = plotter.AddLineGraph(dsChA, _dataBrushColorChA, 1, "Data");
LineGraph lgChB = plotter.AddLineGraph(dsChB, _dataBrushColorChB, 1, "Data");
where,
_dataBrushColorChA = Colors.Green;
_dataBrushColorChB = Colors.Red;
Basically, I only update the data points each time when event occurs, because I have tried AddLineGraph(), but it turned out to be very slow,
so I only update the data points.
So, anyone give me any pointers? How can I handle this multiple data source situation?
It looks like you are setting the data source for the same plotter child at startIndex for both channels:
((LineGraph)plotter.Children.ElementAt(startIndex)).DataSource = dsChA;
...
((LineGraph)plotter.Children.ElementAt(startIndex)).DataSource = dsChB;
The second assignment would cause the DataSource to be overridden by dsChB, which would make it only display one line.
Maybe the index should be different for A and B?

How do you add EmptySpaceItems and LayoutControlItems with equal widths to a LayoutControlGroup with DevExpress?

NOTE: All controls described in this question are DEVEXPRESS controls.
I am attempting to programatically add both LayoutControlItems and EmptySpaceItems to a LayoutControlGroup on a DevExpress LayoutControl.
The requirements for my project require that I have a LayoutControlGroup panel that is dependent on a set of filter items chosen from another control on the layout control. If there are no filters chosen, than none of the `LayoutControlItems are shown. If one or more of the filters are chosen that I add one or more of the controls to the group based on the selection.
The way that I attempt to do this is the following:
1) in the designer for the LayoutControl I have already created the LayoutControlGroup with the LayoutControlItems. There are 6 total, and each LayoutControlItem contains a PanelControl that contains a ListBoxControl
2) When the form is initalized I hide each of the LayoutControlItems from the LayoutControlGroup using the LayoutControlItem.HideFromCustomization() method.
3) After the user selects a filter or set of filters I run the following code attempting to restore the control items to the group from left to right.
this.layoutGroupScenarioPortfolios.BeginUpdate();
LayoutControlItem layoutControlToAdd;
LayoutControlItem lastLayoutControlItem = null;
for (int loop = 0; loop < selectedFilters.Length; loop++)
{
layoutControlToAdd = LayoutControlItemFactoryUtil(selectedFilters[loop]);
if (layoutControlToAdd == null)
{
continue;
}
if (loop < 1)
{
layoutControlToAdd.RestoreFromCustomization(this.layoutControlGroupSelectedFilters);
}
else
{
layoutControlToAdd.RestoreFromCustomization(lastLayoutControlItem, DevExpress.XtraLayout.Utils.InsertType.Right);
}
lastLayoutControlItem = layoutControlToAdd;
}
for (int loop = 0; loop < numOfEmptySpaceItemsNeeded; loop++)
{
layoutControlToAdd = new EmptySpaceItem(this.layoutControlGroupSelectedFilters)
{
Owner = this.layoutControlGroupSelectedFilters.Owner
};
layoutControlToAdd.RestoreFromCustomization(lastLayoutControlItem, DevExpress.XtraLayout.Utils.InsertType.Right);
lastLayoutControlItem = layoutControlToAdd;
}
this.layoutControlGroupSelectedFilters.TextVisible = true;
this.layoutGroupScenarioPortfolios.EndUpdate();
As you can see from the code one loop adds the appropriate ListControlBox to the group. The second loop tries to add empty space items to make sure that the list box control does not take up the entire group. By the end of this code there should be 6 items spanning the group control, each with the same width in the control.
The problem is that the first control added takes up half of the group box's space while the other 5 items are equally fitted into the remaining half of the group box.
In the first loop, is the RestoreFromCustomization() method with one parameter the correct method to use?
I would suggest to place the controls at runtime. LayoutControl will manage the LayoutControlGroups and EmptySpaceItems.
Here is the code I had written to place user controls into the LayoutControl at runtime:
LayoutControlItem lastItem = null;
int RowWidth = 0;
public void AddMyControl()
{
MyControl myControl = new MyControl("");
myControl.Name = Guid.NewGuid().ToString();
LayoutControlItem item = new LayoutControlItem();
item.Name = Guid.NewGuid().ToString();
item.Text = "";
MyLayoutControl.BeginUpdate();
//We need to determine where to insert the new item. Right or Below. If there is
//space on the right we insert at Right else we just add the item.
if(lastItem == null || lastItem != null && (MyLayoutControl.Width - UserControlWidth) < RowWidth)
{
MyLayoutControl.AddItem(item);
RowWidth = item.MinSize.Width;
}
else
{
MyLayoutControl.AddItem(item, lastItem, DevExpress.XtraLayout.Utils.InsertType.Right);
}
item.Control = myControl;
RowWidth += item.MinSize.Width;
lastItem = item;
item.Name = " ";
MyLayoutControl.BestFit();
MyLayoutControl.EndUpdate();
}
If you just need left to right controls, flowlayoutpanel will suit better. Sometimes LayoutControl is tough to work with. I had eventually go with flowlayoutpanel as it is much simpler to work with.

Adding an Element to an Array

Ok, I cannot get this. I've looked at it and I don't see why it's out of bounds. I get the error at paypalItems[paypalItems.Length] = new PaymentDetailsItemType
PaymentDetailsItemType[] paypalItems = new PaymentDetailsItemType[order.OrderItems.Count];
for (int i = 0; i < order.OrderItems.Count; i++)
{
paypalItems[i] = new PaymentDetailsItemType
{
Name = order.OrderItems[i].Name,
Amount = ApiUtility.CreateBasicAmount(order.OrderItems[i].Price),
Description = order.OrderItems[i].Name,
Number = order.OrderItems[i].Sku,
};
}
// paymentItems now has 1 item...now to the if statement:
if (giftCardsTotal != 0)
{
// add Coupons & Discounts line item
paypalItems[paypalItems.Length] = new PaymentDetailsItemType
{
Name = "Gift Cards",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Gift Cards"
};
}
UPDATED: I changed the size of the array..now it's all good. No need for the -1
PaymentDetailsItemType[] paypalItems = new PaymentDetailsItemType[order.OrderItems.Count + 1];
for (int i = 0; i < order.OrderItems.Count; i++)
{
paypalItems[i] = new PaymentDetailsItemType
{
Name = order.OrderItems[i].Name,
Amount = ApiUtility.CreateBasicAmount(order.OrderItems[i].Price),
Description = order.OrderItems[i].Name,
Number = order.OrderItems[i].Sku,
};
}
// paymentItems now has 1 item...now to the if statement:
if (giftCardsTotal != 0)
{
paypalItems[paypalItems.Length -1] = new PaymentDetailsItemType
{
Name = "Certificates",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Certificates"
};
}
I think you might be better off using a List<>, so you would declare:
List<PaymentDetailsItemType> paypalItems = new List<PaymentDetailsItemType>();
Then when you iterate through order.OrderItems, just do a paypalItems.Add()
Finally on your if(giftCardsTotal != 0) conditional just do a:
paypalItems.Add(new PaymentDetailsItemType...);
This way you don't have to worry about off by one array indexing issues. Here would be the rewritten code (I use var for my convenience):
var paypalItems = new List<PaymentDetailsItemType>();
foreach (var orderitem in order.OrderItems)
{
paypalItems.Add(new PaymentDetailsItemType
{
Name = orderitem.Name,
Amount = ApiUtility.CreateBasicAmount(orderitem.Price),
Description = orderitem.Name,
Number = orderitem.Sku,
});
}
if (giftCardsTotal != 0)
{
// add Coupons & Discounts line item
paypalItems.Add(new PaymentDetailsItemType
{
Name = "Gift Cards",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Gift Cards"
});
}
Per John Saunders' suggestion (in the comments), here's a Linq alterative to the variable declaration and first loop:
var paypalItems =
(from orderitem in order.OrderItems
select new PaymentDetailsItemType
{
Name = orderitem.Name,
Amount = ApiUtility.CreateBasicAmount(orderitem.Price),
Description = orderitem.Name,
Number = orderitem.Sku
}).ToList();
Addition based on comment: If you need an Array when you're done, call:
paypalItems.ToArray()
Arrays are zero-based in C#. Using array[array.Length] will always fail. You want Length-1.
In addition, I see that you're trying to expand the array. You can't do that! Once an array is instantiated, it's length cannot change.
If you need a collection that can expand, use List<PaymentDetailsItemType>.
Because they are 0-indexed, so first one is the 0 and last one is length-1.
This is true for almost any programming language..
It seems that first you fill up an array by trasforming elements from another one and then you want to replace last one. Maybe you intended to append an element to the end?
In that case you should build it larger:
PaymentDetailsItemType[] paypalItems = new PaymentDetailsItemType[order.OrderItems.Count+1];
then fill it as you did:
for (int i = 0; i < order.OrderItems.Count; i++)
{
...
}
then set the last one:
paypalItems[paypalItems.Length-1] = ..
paypalItems[paypalItems.Length] =
should be
paypalItems[paypalItems.Length - 1] =
This:
paypalItems[paypalItems.Length]
Will always be outside the bounds of the array as the array index starts at 0. If you want to store something in the last element of the array do:
paypalItems[paypalItems.Length-1] = ...
It looks like you're trying to append to the array by simply using the next index. Perhaps you learned this from exposure to a language like javascript or python, where "arrays" are really complex objects. Real arrays don't work like that.
Instead, you should try using the .Add() method of List<PaymentDetailsItemType>.
You need to change the size of array before add a new array item.
if (giftCardsTotal != 0)
{
// Increase the size
Array.Resize(ref paypalItems, paypalItems.Length + 1);
// add Coupons & Discounts line item
paypalItems[paypalItems.Length -1] = new PaymentDetailsItemType
{
Name = "Gift Cards",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Gift Cards"
};
}
Length starts from 1 and index from 0. So you should try:
paypalItems[paypalItems.Length - 1]
You are initializing the array to the length of order.OrderItems.Count then after filling it up with data, you are trying to add an additional item to the array. This won't work like this. You have allocated a static size to the array here, you can't add an additional item to that without some sort of reallocation.
You need to create a dynamically allocated array or use a List<T>
To add to the other answers, an Array in .NET is a low-level data type that maps directly to an allocated sequence of bytes in memory. Thus, you cannot add items to an array if it's already full. Maybe what you're looking for is to use a List<T>:
var paypalItems = new List<PaymentDetailsItemType>(order.OrderItems.Count);
// specifying that count is optional, but will increase performance because array space will have to be reallocated less often
// ...
paypalItems.Add(new PaymentDetailsItemType
{
Name = "Gift Cards",
Amount = ApiUtility.CreateBasicAmount(giftCardsTotal),
Description = "Gift Cards"
});
paypalItems[paypalItems.Length] would access one position above the allocated space. If you want the last position you need paypalItems[paypalItems.Length-1]
If you want to append an item use a List<> instead of an array.

Categories