C# add a click event to grid childs - c#

How can I add a click event to child objects I have created in my Code Behind?
String[] imageNames = System.IO.Directory.GetFiles("Assets/Images/Gallery");
foreach (String image in imageNames)
{
Uri source = new Uri("ms-appx:///" + image);
ImageSource imgSource = new BitmapImage(source);
Image myImage = new Image();
myImage.Source = imgSource;
gallery.Children.Add(myImage);
}
The above code gets all the images from the gallery folder and adds them to a variablesizedwrapgrid. I want to add a click event on each of these (to basically allow a user to save them to the device they are using)
Thanks

1)
myImage.PointerReleased += Img_PointerReleased;
private void Img_PointerReleased(object sender, PointerRoutedEventArgs e)
{
// do your job
}
2) or write UserControl wrapping Image that inherits from Button and add proper VisualStates if you don't want to have default button animations - this way you will be able to use Clicked event

Related

I'm lost at how to configure my code so that , when i click the radio button a certain image appears

I have to create a small pizza delivery program in C# using Visual Studio 2019 Community Edition :
It has 3 Radio Buttons ( for 3 different pizza's), A Textblock for text ( to show the ingredients), and an image to show the type of pizza.
So I want that when I click on one of those 3 Radio Buttons, a certain text & image appears.
The Radio Buttons and TextBlock is ok, but the image I'm lost at how to properly configure it using the code behind.
Can anyone check the code, and maybe enlighten me?
https://ideone.com/e.js/MjEBnd
private void radiobtnHawai_Checked(object sender, RoutedEventArgs e)
{
string Hawai = "Ananas, Kip, Kaas";
lbl1.Text = Hawai;
Image Hawai.jpg = new Image();
BitmapImage bi3 = new BitmapImage();
bi3.BeginInit();
bi3.UriSource = new Uri("smiley_stackpanel.PNG", UriKind.Relative);
bi3.EndInit();
Hawai.jpg.Stretch = Stretch.Fill;
Hawai.jpg.Source = bi3;
}
Here is an Extra Image : https://i.stack.imgur.com/iiHRn.png
Thanks in Advance,
If more information is needed, please don't hesitate to ask.
Suppose you have a image control defined like this
<Image Name="ImageViewer1" Height="400" Width="400" />
On your radio checked command , you have to assign the source of "ImageViewer1".
For example, in your case it will look like this
private void radiobtnHawai_Checked(object sender, RoutedEventArgs e)
{
string Hawai = "Ananas, Kip, Kaas";
lbl1.Text = Hawai;
BitmapImage bi3 = new BitmapImage();
bi3.BeginInit();
bi3.UriSource = new Uri("smiley_stackpanel.PNG", UriKind.Relative);
bi3.EndInit();
ImageViewer1.Stretch = Stretch.Fill;
ImageViewer1.Source = bi3;
}
Also make sure that, smiley_stackpanel.PNG, exists in your Environment.CurrentDirectory.
By specifying relative path it will look images from the path where your exe resides

Can't Add Tab Page To TabControl Inside The Constructor Of My WinForms Application

I have a C# Form application that has a TabControl in the main form. This TabControl is used to display multilple TabPages that contain a CustomControl. This CustomControl is just a Panel with a few buttons and a PictureBox.
Here is a picture of my app when it starts up. As you can see the tab control (the white area) is empty:
If the user clicks the "Add Image" button they are presented with an OpenFileDialog to select the image then the addImage method is called with the selected file:
private void doAddImage()
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = Constants.Global.IMAGE_FILE_FILTER();
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string imageFileName = openFileDialog.FileName;
addImage(imageFileName);
}
}
private void addImage(string imageFileName)
{
// Create a new bitmap and image preview custom control. Then create a new tab
// page and add the custom control to the tab page.
Bitmap bitMap = new Bitmap(imageFileName);
ImagePreviewCustomControl previewControl = new ImagePreviewCustomControl(bitMap);
previewControl.Dock = DockStyle.Fill;
TabPage tabPage = new TabPage(Path.GetFileNameWithoutExtension(imageFileName));
tabPage.Controls.Add(previewControl);
// Insert the new tab page to the right of the currently selected tab page
int selectedTabIndex = imagesTabControl.SelectedIndex;
imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex + 1;
}
As you can see, in the addImage method I create the Bitmap, CustomControl, and TabPage and then insert it into the TabControl.
I start my application, click the "Add Image" button, everything works just fine.
Here is a picture with a tab page added:
While I am testing my app I don't want to have to add an image manually using the OpenFileDialog every time so in my constructor I just call addImage with some fixed image file name that I want to test with:
public ImageViewerApp()
{
InitializeComponent();
addImage(#"C:\MyImages\Calculator-3-icon.png");
}
The problem I am having is that when I try to add the image in my constructor it doesn't show up in the TabControl. The application starts up blank (like the first picture).
As stated above when the application is already running and I click the "Add Image" button it gets added just fine.
I found a property in the TabControl class called Created which states:
"Gets a value indicating whether the control has been created"
So to try and figure out what's going on I write the value of Created to the console just before I call addImage in the constructor. (I have a custom console for debugging my Form applications.)
public ImageViewerApp()
{
InitializeComponent();
TestConsole.WriteLine(imagesTabControl.Created);
addImage(#"D:\Development\Work\Other\Stardock\Start8\_downloaded\Calculator-3-icon.png");
}
The value of Created just before the call to addImage in the constructor is:
False
I put another console output inside the addImage method:
private void doAddImage()
{
TestConsole.WriteLine(imagesTabControl.Created);
OpenFileDialog openFileDialog = new OpenFileDialog();
...
...
}
The value of Created after the app has started and the user presses the "Add Image" button is:
True
Why is it that the TabControl is not Created inside my constructor (even after the InitializeComponent() call) and the once the application is running it is Created?
=UPDATE========================================================================
Based on the suggestion by Hans Passant I have added the following code to my addImage method:
int selectedTabIndex = -1;
if (imagesTabControl.TabCount > 0)
{
selectedTabIndex = imagesTabControl.SelectedIndex;
}
else
{
selectedTabIndex = imagesTabControl.SelectedIndex + 1;
}
imagesTabControl.TabPages.Insert(selectedTabIndex, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex;
This doesn't work.
===============================================================================
=UPDATE2=======================================================================
int selectedTabIndex = imagesTabControl.SelectedIndex;
if (imagesTabControl.TabCount == 0) selectedTabIndex = -1;
imagesTabControl.TabPages.Insert(selectedTabIndex, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex;
This causes the following Exception:
{"InvalidArgument=Value of '-1' is not valid for 'index'.\r\nParameter name: index"}
===============================================================================
=UPDATE3=======================================================================
I tried the folllowing code:
int selectedTabIndex = imagesTabControl.SelectedIndex;
if (imagesTabControl.TabCount == 0) selectedTabIndex = -1;
imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex + 1;
This one doesn't throw an exception but again no tab page added after calling
addImage in the constructor.
===============================================================================
=UPDATE4=======================================================================
I have kindof given up on adding an image in the constructor. So instead I am using an enum RunMode and a variable RUN_MODE of that type. Then, if RUN_MODE == RunMode.TESTI call a method to add a random image when I click the button. (The OpenFileDialog is not used. I just parse through all the image files in the fixed directory IMAGE_DIRECTORY.
enum RunMode { NORMAL, TEST }
private static string IMAGE_DIRECTORY = #"D:\\Work\Images";
...
...
private void doAddImage()
{
if (RUN_MODE == RunMode.TEST)
{
addRandomImage();
return;
}
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = Constants.Global.IMAGE_FILE_FILTER();
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string imageFileName = openFileDialog.FileName;
addImage(imageFileName);
}
}
private void addRandomImage()
{
string[] allFiles = Directory.GetFiles(IMAGE_DIRECTORY);
List<string> imageFileNames = new List<string>();
foreach (string file in allFiles)
{
bool isImageFile = Constants.Global.IMAGE_EXTENSIONS.Contains(Path.GetExtension(file));
if (isImageFile)
{
imageFileNames.Add(file);
}
}
int randomIndex = new Random().Next(imageFileNames.Count);
addImage(imageFileNames.ElementAt(randomIndex));
}
This works. Now when I click the "Add Image" button during TEST_MODE I skip the
OpenFileDialog and just add a random image.
I would like to understand the issues with TabControl but at this point I just
need to continue development. My current solution works great.
As I person who like to understand everything I would like to use other people's
suggestions so I will keep monitoring this question for a solution.
===============================================================================
JonP's answer gave me the idea to just wait for the window handle to be created before inserting the tab, so I tried some events occuring between Form construction and Tab Control display.
I found it to work with both the Load or Shown events:
Right-click on the Form (the root, not child controls) in the Designer view > Properties > Events (flash icon) > Behavior > enter a method name for the Load or Shown event and confirm. To generate a Load event callback you can also double-click on the Form itself. This should generate something like this:
this.Load += new System.EventHandler(this.Form1_Load);
// or
this.Shown += new System.EventHandler(this.Form1_Shown);
Setup the tabs in the callback:
private void Form1_Load(object sender, EventArgs e)
{
// Add image (this will call imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage))
// This must be done on Load event because Insert requires
// the window handle, which is not ready in the constructor
addImage(#"path_to_image.png");
}
I have had this problem too and have found a workaround; I think it must be a bug with Insert():
Don't use Insert(), it usually does nothing, use Add() instead; this reliably adds a TabPage to the end of the collection.
After adding it swap it with the tab position where you actually want it.
imagesTabControl.TabPages.Add(tabPage);
// Now swap the two tabs:
imagesTabControl.TabPages[imagesTabControl.TabCount - 1] = imagesTabControl.TabPages[selectedTabIndex + 1];
imagesTabControl.TabPage[selectedTabIndex + 1] = tabPage;
Your mileage may vary of course :-)
Stop Press! An even better fix is to read the class's Handle member before calling Insert():
var handle = imagesTabControl.Handle;
Insert() works perfectly after you do that. Obvious isn't it???? The help page for Handle has this possible relevant Remark showing that the object actually does something when you read Handle:
The value of the Handle property is a Windows HWND. If the handle has not yet been created, referencing this property will force the handle to be created.
You could remove the TabControl from the designer and then instead just manually create the TabControl programmatically and add it to the Form immediately after InitializeComponent(). Then after you create the TabControl, call addImage(). Something like:
InitializeComponent();
TabControl tc = new TabControl();
tc.Location = new Point(10, 10);
tc.Size = new Size(100, 100);
tc.Visible = true;
tc.Anchor = (AnchorStyles.Bottom | AnchorStyles.Right | AnchorStyles.Left | AnchorStyles.Top);
this.Controls.Add(tc)
addImage("c:\pathToImage\image.bmp");

Global appBar, add other buttons to this appbar for a specific page

I add an appbar with 3 buttons in App.xaml.cs to put it on each page but I have a page where I would like to add another button in addition.
What I do, it's I get the appbar with my 3 defaults buttons from App.xaml.cs, then I add my other button. The problem is when it's added and when I change the page, the button I added stay visible... Thus, it's a problem with the reference of the object because each page reference the same appbar.
I wonder if it's possible to copy this appbar for only the page with 4 buttons...(Icloneable? but I don't know how :/) What do you think?
I should also mention that some buttons use navigation to go another page.
Here is my code:
App.xaml.cs
private ApplicationBar _appBar;
public ApplicationBar AppBar { get { return _appBar; } } //property called in other page
//Method called in the constructor
private void BuildLocalizedApplicationBar()
{
// Set the page's ApplicationBar to a new instance of ApplicationBar.
_appBar = new ApplicationBar();
// Create a new button and set the text value to the localized string from AppResources.
var appBarButtonScan = new ApplicationBarIconButton(new Uri("/Assets/AppBar/White/appbar.qr.png", UriKind.Relative));
appBarButtonScan.Click += AppBarButtonScanOnClick;
appBarButtonScan.Text = AppResources.Scan;
var appBarButtonSearch = new ApplicationBarIconButton(new Uri("/Assets/AppBar/White/appbar.search.png", UriKind.Relative));
appBarButtonSearch.Click += AppBarButtonSearchOnClick;
appBarButtonSearch.Text = AppResources.Search;
var appBarButtonFacebook = new ApplicationBarIconButton(new Uri("/Assets/AppBar/White/appbar.facebook.png", UriKind.Relative));
appBarButtonFacebook.Click += AppBarButtonFacebookOnClick;
appBarButtonFacebook.Text = AppResources.MyAccount;
_appBar.Buttons.Add(appBarButtonScan);
_appBar.Buttons.Add(appBarButtonSearch);
_appBar.Buttons.Add(appBarButtonFacebook);
// Create a new menu item with the localized string from AppResources.
ApplicationBarMenuItem appBarMenuSettings = new ApplicationBarMenuItem(AppResources.SettingsTitle);
_appBar.MenuItems.Add(appBarMenuSettings);
}
In the page where I would like to have one button in addition:
private void BuildLocalizedApplicationBar()
{
App _app = Application.Current as App; //in my page, it's an attribute that I initialize in my constructor.
ApplicationBar = _app.AppBar; //get the appbar with 3 buttons from App.xaml.cs
// Create new buttons and set the text value to the localized string from AppResources.
ApplicationBarIconButton appBarButtonTagPlace = new ApplicationBarIconButton(new Uri("/Assets/AppBar/White/appbar.heart.outline.png", UriKind.Relative));
appBarButtonTagPlace.Text = AppResources.TagThisPlaceTitle;
appBarButtonTagPlace.Click += AppBarButtonTagPlaceOnClick;
ApplicationBar.Buttons.Add(appBarButtonTagPlace);
}
Thank you in advance
You could remove the button when leaving the page that has the extra button.
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
ApplicationBar.Buttons.Remove(appBarButtonTagPlace);
base.OnNavigatedFrom(e);
}

Clickable image grid in windows form?

If this is a dumb question, forgive me. I have a small amount of experience with C#, but not to this degree yet.
I have a series of images that I want to put into a grid with space around each image, also text beneath them and I want them to be clickable, so when they're clicked they hilite, and double click runs an event. The best example I have for this is the user interface of the program ACDSee. I've googled this for hours, and haven't come up with anything applicable. Is this difficult or simple? Can anyone give me an example, or point me in the right direction?
Cheers.
It doesn't seem to be very difficult. I would suggest the following steps:
Add a new "User Control" to your project for image thumbnails. It can contain a docked PictureBox and a Label or LinkLabel at its bottom.
For the space around each thumbnail simply play with the Padding property of the user control.
For the so called grid that is going to hold the thumbnails, use a FlowLayoutPanel, and simply add instances of the above mentioned user-control to this panel.
For visual representation of being selected, change the background color of the user-control instance to blue (for example), and back to control-face when deselected. It is recommended to implement an IsSelected property for the user-control as well.
To emulate thumbnail selection, handle the Click event of the user-control and assign the events for all thumbnail instances to a single event-handler method. Store a global reference to the already selected thumbnail, name it e.g., SelectedThumbnail initialized with null. In the event-handler body compare the sender with the global SelectedThumbnail, and update it if required. If the user-control associated with the sender is not selected (i.e., its background is not blue, or IsSelected is false) make it selected, or change its background. Otherwise change the background to its default color (e.g., control-face).
The Click event handler body looks something like this:
MyThumbnailControl ctrl = sender as MyThumbnailControl;
if(ctrl == null) return;
if(ctrl == SelectedThumbnail) return; // selected again
if(ctrl != SelectedThumbnail)
{
ctrl.IsSelected = true;
ctrl.BackColor = Color.Blue;
// it's better to set the back-color in the IsSelected property setter, not here
SelectedThumbnail.IsSelected = false;
SelectedThumbnail.BackColor = Color.Control;
SelectedThumbnail = ctrl; // important part
}
It's also recommended that all thumbnail instances that are going to be added to the so-called grid, be referenced in a separate array too. Therefore changing selection with arrow-keys would be possible with simple index calculations.
Further Notes: I assumed that the user-control that is to be created is named MyThumbnailControl, just a random name to refer to that control. When you create a new user-control, the wizard generates a class for you with your desired name (e.g., MyThumbnailControl), you can define a property inside it named IsSelected and implement its getter and setter. See this for a tutorial. After defining the user-control you can instantiate instances from its corresponding class. Also by global reference, I meant a variable at the form (or any parent control) level. To keep it simple we can add a reference of the selected thumbnail in the form that is going to hold the grid and thumbnails: MyThumbnailControl selectedThumb = null; or something like this in the body of the form.
Here is something, I just fixed you.
Create a C# project name CreateImageList and in the Form1 add the following 5 controls with their default name i.e. Panel1, PictureBox1, Label1, Button1, Button2:
How it works:
When the page load it create an imageList objects and load all .jpg images from a folder you provide
ImageList Images are set into the PictureBox control and when user clicks "Button1" the picturebox shows next image in ImageList and when user clicks "Button2" the PictureBox shows previous image from ImageList.
The Label1 shows the currentImage counter from the ImageList Arrage. If you want to write something specific, you can create an array of text and sync with your image counter.
When user click on PictureBox the a border is create to show Picture highlighted
When user Double Click on PictureBox a MessageBox appears shows DoubleClick event.
Now, you can use the following code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace CreateImageList
{
public partial class Form1 : Form
{
private int currentImage = 0;
protected Graphics myGraphics;
ImageList iPicList = new ImageList();
public Form1()
{
InitializeComponent();
DirectoryInfo dirImages = new DirectoryInfo("C:\\2012");
iPicList.ImageSize = new Size(255, 255);
iPicList.TransparentColor = Color.White;
myGraphics = Graphics.FromHwnd(panel1.Handle);
foreach (FileInfo file in dirImages.GetFiles())
{
if (file.Extension == ".jpg")
{
Image myImage = Image.FromFile(file.FullName);
iPicList.Images.Add(myImage);
}
}
if (iPicList.Images.Empty != true)
{
panel1.Refresh();
currentImage = 0;
// Draw the image in the panel.
iPicList.Draw(myGraphics, 1, 1, currentImage);
// Show the image in the PictureBox.
pictureBox1.Image = iPicList.Images[currentImage];
label1.Text = "Image #" + currentImage;
}
}
private void showImage(int imgIndex)
{
// Draw the image in the panel.
iPicList.Draw(myGraphics, 1, 1, currentImage);
// Show the image in the PictureBox.
pictureBox1.Image = iPicList.Images[currentImage];
label1.Text = "image #" + currentImage;
panel1.Refresh();
}
private void button1_Click(object sender, EventArgs e)
{
if (iPicList.Images.Count - 1 > currentImage)
{
currentImage++;
}
else
{
currentImage = 0;
}
showImage(currentImage);
}
private void button2_Click(object sender, EventArgs e)
{
if (iPicList.Images.Count - 1 >= currentImage)
{
if (currentImage == 0)
currentImage = iPicList.Images.Count-1;
else
currentImage--;
}
else
{
currentImage = iPicList.Images.Count;
}
showImage(currentImage);
}
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
MessageBox.Show("Picture Box Double clicked");
}
private void pictureBox1_Click(object sender, EventArgs e)
{
panel1.Refresh();
myGraphics.DrawRectangle(Pens.Black, 0, 0, iPicList.Images[currentImage].Width + 1, iPicList.Images[currentImage].Height + 1);
pictureBox1.Image = iPicList.Images[currentImage];
}
}
}
The changes you need are:
Change the Following folder to a place where you have lots of jpg:
DirectoryInfo dirImages = new DirectoryInfo("C:\\2012");
Also if you are dealing with other kind of images, make change here:
if (file.Extension == ".jpg") // Change it to your image type.
If you don't want to use the the buttons to go up and down, you have several other options to host PictureBox control in scrollable Panel or list or something else.

dynamically handling events for an image

I'm currently working on a program where there are multiple "icons" dynamically added to a window. Each one of these "icons" (which is actually a image with a label underneath it) represents a device in a network. When the user double clicks on an icon, it needs to open a window where the user can change the properties of that specific device.
I already have the window created, along with the code to dynamically add images to a window. My problem is that since each icon is dynamically added, they use the same event handler. since each icon uses the same handler, it seems impossible to have each icon open its respective device.
Here is a part of the code which is run when a user adds a new device along with the event handler it uses:
//create new device
devices.Add(new Device(ipaddress, hn, un, pw, cm, lx, ly, tp, pl, nt, dn));
images.Add(new Image());
//create image for main window
images[images.Count - 1].Width = 50;
images[images.Count - 1].Height = 35;
images[images.Count - 1].Stretch = Stretch.Fill;
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri(deviceImages[tp], UriKind.Relative);
logo.CacheOption = BitmapCacheOption.OnLoad;
logo.EndInit();
images[images.Count - 1].Source = logo;
images[images.Count - 1].Cursor = Cursors.Hand;
images[images.Count - 1].Margin = new System.Windows.Thickness(lx-25, ly-25, 0, 0);
images[images.Count - 1].VerticalAlignment = System.Windows.VerticalAlignment.Top;
images[images.Count - 1].HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
images[images.Count - 1].MouseDown += new MouseButtonEventHandler(deviceIcon_MouseDown);
ConnexMainWindow.grid1.Children.Add(images[images.Count - 1]);
public void deviceIcon_MouseDown(object sender, MouseButtonEventArgs e)
{
ConnexDeviceWindow deviceWindow = new ConnexDeviceWindow();
deviceWindow.Show();
}
As you can see, I'm not currently passing the device window the device since there isn't really any way to do so from the event handler.
My question is: Is there a way to dynamically create an event handler, for each image i add, so that i can pass the function the proper device that each image represents?
One common strategy to identify the control which fired the event is to use the Tag property of the control to store some information.
I don't know what your device model looks like, but let's assume the ip-address is unique among all the devices. You can attach that to the Image control:
images[images.Count - 1].Tag = ipaddress
In your event handler you can grab that tag to find the device (assuming the devices collection is available on class-level):
public void deviceIcon_MouseDown(object sender, MouseButtonEventArgs e)
{
Image image = e.Source as Image;
if (image != null)
{
string ipAddress = (string)image.Tag;
Device device = devices.FirstOrDefault(d => d.IpAddress == ipAddress);
if (device != null)
{
ConnexDeviceWindow deviceWindow = new ConnexDeviceWindow(device);
deviceWindow.Show();
}
}
}

Categories