Set a name for each ImageSource in a list - c#

I call an API and get from there an id, a name and an URL for images...
I display them in a flipview and I used to convert them, saved them in a folder, convert them back and show them...
So I thought it would be much easier if I show them directly from their URL.
Now, when the user clicks (taps) on the image, it has to go to another page to show the detail of that image (and it was working fine, when saving the pic, since I named them by the id (id.png))
is there anyway I can name the ImageSource to be this id, or give it like a property (Title or Name)?
var pics = from special in GlobalVariables.Special
where special.special == "1"
select new { id = special.id, name = special.name, image = special.banner_image, featured = special.special };
foreach (var item in pics)
{
await savePicToDisk(item.image, item.name, item.id, item.featured);
}
So, then, instead of save them:
List<ImageSource> listOfImages = new List<ImageSource>();
string url = "http://52.8.2.140" + picAddress;
ImageSource urlOfPic = new BitmapImage(new Uri(url, UriKind.Absolute));
listOfImages.Add(urlOfPic);
Then, where I have to show them, I just bind it to the flipview:
flipView1.DataContext = Classes.Special.listOfImages;

The Item_Click event's arguments have a property ClickedItem (in some cases you may also need OriginalSource), which you can use to point to your item in a collection. If item's class has a property responsible for Name/Id/other you can freely pass that when navigating, other solution may be passing an index of selected item in the collection. Sample code;
private void ItemClick(object sender, ItemClickEventArgs e)
{
var item = e.ClickedItem as ItemClass;
if (item != null)
Frame.Navigate(typeof(DetailPage), item.ID);
// if your item contains a Name/Id/other you can pass that when navigating
// you can also pass index of your item in collection if you need
}

Related

How to create a dynamic list of buttons on MainPage in Xamarin.Forms?

I'm creating an application to scan barcode tickets. When you start the app a list of available shows has to be shown on the screen. To get all the available shows I'm using a webservice which returns me a List<Event>. How do I create a list of buttons with each button representing a show/event from inside the xaml.cs? When clicking the button a new page will be shown where the user can scan the tickets from that show. I'm pretty new to Xamarin.Forms and I quite don't understand how to use the paging/content views. I already searched a lot but the closest to what I need was this: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/get-started-with-xaml?tabs=vswin
Unfortunatly it only shows how to add a certain amount of controls. And not a dynamicly generated amount.
Many thanks in advance!
In xaml insert a stacklayout where you want your buttons to appear. Remember you can also play whith its Orientation and Spacing properties. So:
<StackLayout x:Name="MyButtons"/>
Then in code-behind generate your dinamic buttons list. Put the code in constructor AFTER InitializeComponent(); or somewhere else:
var myList = new List<*Event or something*>(); //your list here
MyButtons.Children.Clear(); //just in case so you can call this code several times np..
foreach (var item in myList)
{
var btn = new Button()
{
Text = item.*your property*, //Whatever prop you wonna put as title;
StyleId = item.*your ID property* //use a property from event as id to be passed to handler
};
btn.Clicked += OnDynamicBtnClicked;
MyButtons.Children.Add(btn);
}
Add a handler:
private void OnDynamicBtnClicked(object sender, EventArgs e)
{
var myBtn = sender as Button;
// who called me?
var myId = myBtn.StyleId; //this was set during dynamic creation
//do you stuff upon is
switch (myId)
{
case "1": //or other value you might have set as id
//todo
break;
default:
//todo
break;
}
}

Images in the first column of a listview in C# WinForms

I'm with a little problem on a project.
As you can see in the image, I have a ListView with some data pulled from a List of objects from the class person. This class also has an attribute that keep the path of an image chosen by the user, which is supposed to show on the first column of the ListView, where it says teste.
I've tried the following code:
ImageList imgs = new ImageList();
imgs.ImageSize = new Size(40, 40);
foreach (user list in Global.userslist)
{
imgs.Images.Add(Image.FromFile(list.Photo));
}
listview1.SmallImageList = imgs;
foreach (user list in Global.userslist)
{
imageList1.Images.Add(Image.FromFile(list.Photo));
listview1.Items.Add(new ListViewItem(new string[] { "teste", Convert.ToString(list.Id), lista.Name, list.Birthday.ToString("dd/MM/yyyy") }));
}
You should set ImageIndex or ImageKey property for the item to show the image.
You can pass the index or key in constructor of ListViewItem. Also you can assign the value using the ImageIndex or ImageKey property.
Example
In your code, you can set the image key when adding them to ImageList:
imgs.Images.Add(list.Id.ToString(), Image.FromFile(list.Photo));
Then when creating items, use the ImageKey:
listview1.Items.Add(new ListViewItem(new string[] { ... ... }, list.Id.ToString()));

The BindingList Datasource of a Combobox refreshes correctly but the Combobox displays items in the wrong order

I have a BindingList< KeyValuePair < string, string > > that is bound to a ComboBox control. Based on some conditions, the BindingList will be added a new KeyValuePair. Now, the Newly added item shows up at index 0 of the Combobox, instead of at the end.
While debugging, I found that the BindingList has got the right order. (i.e, the new KeyValuePair is appended)
Also, I check the SelectedValue of the ComboBox in it's SelectedIndexChanged handler and it seems to be not of the ListItem that got selected. Instead, it is that of the supposed ListItem, if the ComboBox had got the right order as in its DataSource, - the BindingList..
The code is a small part of a large project.. Plz let me know if the question is not clear. I can put the relevant parts of the code as per our context.
How could something like this happen? What can I do differently?
I have this class something like this.
public class DropdownEntity
{
//removed all except one members and properties
private string frontEndName
public string FrontEndName
{
get {return this.frontEndName; }
set {this.frontEndName= value; }
}
//One Constructor
public DropdownEntity(string _frontEndName)
{
this.FrontEndName = _frontEndName;
//Removed code which initializes several members...
}
//All methods removed..
public override string ToString()
{
return frontEndName;
}
}
In my windows form, I have a tab control with several tabs. In one of the tabs pages, I have a DataGridView. The user is supposed to edit the cells and click on a Next - button. Then, some processing will be done, and the TabControl will be navigated to the next tab page.
The next tab page has the combobox that has the problem I mentioned. This page also has a back button, which will take back.. the user can modify the gridview cells again.. and click on the next button. This is when the order gets messed up.
I am posting here the Click event handler of the Next Button.. Along with the class, with the rest of the code removed.
public partial class AddUpdateWizard : Form
{
//Removed all members..
BindingList<KeyValuePair<string, string>> DropdownsCollection;
Dictionary<string, DropdownEntity> DropdownsDict;
//Defined in a partial definition of the class..
DataGridView SPInsertGridView = new DataGridView();
ComboBox DropdownsCmbBox = new ComboBox();
Button NextBtn2 = new Button();
Button BackBtn3 = new Button();
//Of course these controls are added to one of the panels
public AddUpdateWizard(MainForm mainForm)
{
InitializeComponent();
DropdownsDict = new Dictionary<string, DropdownEntity>();
}
private void NextBtn2_Click(object sender, EventArgs e)
{
string sqlArgName;
string frontEndName;
string fieldType;
for (int i = 0; i < SPInsertGridView.Rows.Count; i++)
{
sqlArgName = "";
frontEndName = "";
fieldType = "";
sqlArgName = SPInsertGridView.Rows[i].Cells["InsertArgName"].Value.ToString().Trim();
if (SPInsertGridView.Rows[i].Cells["InsertArgFrontEndName"].Value != null)
{
frontEndName = SPInsertGridView.Rows[i].Cells["InsertArgFrontEndName"].Value.ToString().Trim();
}
if (SPInsertGridView.Rows[i].Cells["InsertArgFieldType"].Value != null)
{
fieldType = SPInsertGridView.Rows[i].Cells["InsertArgFieldType"].Value.ToString().Trim();
}
//I could have used an enum here, but this is better.. for many reasons.
if (fieldType == "DROPDOWN")
{
if (!DropdownsDict.ContainsKey(sqlArgName))
DropdownsDict.Add(sqlArgName, new DropdownEntity(frontEndName));
else
DropdownsDict[sqlArgName].FrontEndName = frontEndName;
}
else
{
if (fieldType == "NONE")
nonFieldCount++;
if (DropdownsDict.ContainsKey(sqlArgName))
{
DropdownsDict.Remove(sqlArgName);
}
}
}
//DropdownsCollection is a BindingList<KeyValuePair<string, string>>.
//key in the BindingList KeyValuePair will be that of the dictionary.
//The value will be from the ToString() function of the object in the Dictionary.
DropdownsCollection = new BindingList<KeyValuePair<string,string>>(DropdownsDict.Select(kvp => new KeyValuePair<string, string>(kvp.Key, kvp.Value.ToString())).ToList());
DropdownsCmbBox.DataSource = DropdownsCollection;
DropdownsCmbBox.DisplayMember = "Value";
DropdownsCmbBox.ValueMember = "Key";
//Go to the next tab
hiddenVirtualTabs1.SelectedIndex++;
}
private void BackBtn3_Click(object sender, EventArgs e)
{
hiddenVirtualTabs1.SelectedIndex--;
}
//On Selected Index Changed of the mentioned Combobox..
private void DropdownsCmbBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (DropdownsCmbBox.SelectedValue != null)
{
if (DropdownsDict.ContainsKey((DropdownsCmbBox.SelectedValue.ToString())))
{
var dropdownEntity = DropdownsDict[DropdownsCmbBox.SelectedValue.ToString()];
DropdownEntityGB.Text = "Populate Dropdowns - " + dropdownEntity.ToString();
//Rest of the code here..
//I see that the Datasource of this ComboBox has got the items in the right order.
// The Combobox's SelectedValue is not that of the selected item. Very Strange behavior!!
}
}
}
}
The very first time the user clicks the Next Button, it's fine. But if he clicks the Back Button again and changes the Data Grid View cells.. The order will be gone.
I know, it can be frustrating to look at. It's a huge thing to ask for help. Any help would be greatly appreciated!
Please let me know if you need elaboration at any part.
Thanks a lot :)
I think you have two problems here.
First, if you want to retain the order of the items you should use an OrderedDictionary instead of a regular one. A normal collection will not retain the order of the items when you use Remove method. You can see more info about this related to List here.
You could use such dictionary like this:
DropDownDict = new OrderedDictionary();
// Add method will work as expected (as you have it now)
// Below you have to cast it before using Select
DropDownCollection = new BindingList<KeyValuePair<string, string>>(DropDownDict.Cast<DictionaryEntry>().Select(kvp => new KeyValuePair<string, string>(kvp.Key.ToString(), kvp.Value.ToString())).ToList());
The second problem could be that you change the display name (FrontEndName) of already existing items, but the key is preserved. When you add a new item, try to remove the old one that you're not using anymore and add a new item.
The Sorted Property of the Combobox is set to True! I didn't check that until now. I messed up. Terribly sorry for wasting your time Adrian. Thanks a lot for putting up with my mess here.. :)

How to set ListViewItem's default image if image key could not be found

Is there a built in way to use a default image when the ListViewItem's ImageKey could not be found?
I have an ImageList:
car.png
house.png
default.png
And a ListViewItem
var item = new ListViewItem("Item1");
item.ImageKey = "computer.png";
By default the ListView does not display an image in this case. Is there a possibility to display "default.png"
This should do it (though there may be a more elegant way). You will likely need to adapt this to suit how you are populating your ListView. The basic code is like this:
string imageKey = "DefaultKey";
string someOtherKey = "SomeOtherKey";
if (lv.SmallImageList.Images.ContainsKey("SomeOtherKey"))
{
imageKey = someOtherKey;
}
var item = new ListViewItem("Item1");
item.ImageKey = imageKey;
Note that, depending on how you are populating your list, this might be better pulled out into a function which returns the appropriate key:
string getImageKey(string candidateKey)
{
if (lvAzureDirectory.SmallImageList.Images.ContainsKey(candidateKey))
{
return candidateKey;
}
else
{
return "DefaultKey";
}
}

How to add a listViewItem with its own unique image

C#'s ListView has the follow add methods available for adding an entry
public virtual ListViewItem Add(ListViewItem value)
public virtual ListViewItem Add(string text)
public virtual ListViewItem Add(string text, int imageIndex)
public virtual ListViewItem Add(string text, string imageKey)
public virtual ListViewItem Add(string key, string text, int imageIndex)
public virtual ListViewItem Add(string key, string text, string imageKey)
Scenario: I have a ListView and wish to dynamically add ListViewItems with their own unique images in the first column. Furthermore these images can be updated depending upon state changes
Question: How would you do you do this?
Code I'm working with
private void AddToMyList(SomeDataType message)
{
string Entrykey = message.ID;
//add its 1 column parameters
string[] rowEntry = new string[1];
rowEntry[0] = message.name;
//make it a listviewItem and indicate its row
ListViewItem row = new ListViewItem(rowEntry, (deviceListView.Items.Count - 1));
//Tag the row entry as the unique id
row.Tag = Entrykey;
//Add the Image to the first column
row.ImageIndex = 0;
//Add the image if one is supplied
imagelistforTypeIcons.Images.Add(Entrykey, message.marker.markerIcon);
//finally add it to the device list view
typeListView.Items.Add(row);
}
There are two things you need to do
Add image to ImageList if it isn't already in it
Create new ListViewItem and assign image from previous point to it
It could go like this, based on your code:
// Add markerIcon to ImageList under Entrykey
imagelistforTypeIcons.Images.Add(Entrykey, message.marker.markerIcon);
// Use icon from ImageList which is stored under Entrykey
ListViewItem row = new ListViewItem(rowEntry);
row.ImageKey = Entrykey;
// Do whatever else you need afterwards
row.Tag = Entrykey;
....
Problem with code in your question (without actually trying it out) looks to be in ImageIndex you are assigning.
you are adding new image to one image list, but assigning an image to ListViewRow from a different one
you are providing image index in constructor but setting it to 0 afterwards (why?)
you are providing wrong image index in the first place, because you calculated index of last image in the image list, before adding the new image.
So your code could also be fine like this:
// Add markerIcon to ImageList under Entrykey
imagelistforTypeIcons.Images.Add(Entrykey, message.marker.markerIcon);
// Use icon from ImageList which is stored under Entrykey
ListViewItem row = new ListViewItem(rowEntry);
row.ImageIndex = imagelistforTypeIcons.Items.Count - 1;
// Do whatever else you need afterwards
row.Tag = Entrykey;

Categories

Resources