WPF Dynamic Controls - c#

I want to iterate through all the files in a folder and dynamically create images controls for each JPEG file found. Once complete I want a form filled with dynamically created image controls (think of just about any photo viewing software such as Picasa that has a thumbnail view).
I want to be able to reorder these dynamically created images controls on the form by implementing some sort of drag drop event handler. I will not know how many images I will encounter and therefore cannot hardcode event handlers for each image control that might or might not exist. So I am looking for a way to dynamically add event handlers to dynamically created controls.
The method used in the code below is almost what I am looking for. The problem with the method below is that if I don't know the name of the control I could not hard code the event handler.
public partial class RoutedEventAddRemoveHandler {
void MakeButton(object sender, RoutedEventArgs e)
{
Button b2 = new Button();
b2.Content = "New Button";
// Associate event handler to the button. You can remove the event
// handler using "-=" syntax rather than "+=".
b2.Click += new RoutedEventHandler(Onb2Click);
root.Children.Insert(root.Children.Count, b2);
DockPanel.SetDock(b2, Dock.Top);
text1.Text = "Now click the second button...";
b1.IsEnabled = false;
}
void Onb2Click(object sender, RoutedEventArgs e)
{
text1.Text = "New Button (b2) Was Clicked!!";
}
}
Note I am looking for a solution in c# code not XAML. That is a solution using code like this to add controls:
// What I want
Fields.Add(new Field() { Name = "Username", Length = 100, Required = true });
not like this:
// What I do not want
<TextBox Width="100" Canvas.Left="50" Canvas.Top="20" />
Thanks

I would not do so much in codebehind. Only to get the files.
I would get an ObservableCollection where the string is the FullName of the file.
Then I would present it in a ListBox or ListView having the ItemSource bound to the collection and defining å good ItemTemplate for the control.
In the template, you can use a Converter to create å Source for the Image in the template.

Adding a small sample just to save you the pain of image loading in WPF code-behind.
void OnButtonClick(object sender, RoutedEventArgs routedEventArgs)
{
var files = Directory.GetFiles(#"C:\img");
foreach (var file in files)
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(file);
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
var img = new Image { Source = bitmap };
img.MouseDown += OnImageMouseDown;
//Add img to your container
}
}
void OnImageMouseDown(object sender, MouseButtonEventArgs e)
{
var img = sender as Image;
//Operate
}

Related

adding event to list of controls that are created programmatically

I'm generating a list of image controls in WPF .
Image img = new Image();
img.Source = GetPic(value);
img.Tag = cst.GetIdDriverde();
img.ToolTip = dtID.Rows[j][0];
img.Width = 130;
img.Height = 130;
lst.Add(img);
I want to add an event to each control.
How can I do that?
I agree with Mighty and Omid but if you run stubborn, here's a lambda
img.MouseLeftButtonUp += (se, a) => {/*YOUR CODE*/};
You could attach an event like you do it for any other object.
For example a MouseLeftButtonDown event.
Image img = new Image();
img.MouseLeftButtonDown += Img_MouseLeftButtonDown;
private void Img_MouseLeftButtonDown(object sender, MouseButtonEventArgs eventArgs)
{
//your logic
}
Have a look at the Image Class for the available events.
Hint
This would work but you should not add images like this at all. The better way would be to use a ItemsControl and using a DataTemplate. If you want to change your code let me know if you need some help.

Click on image and show message box depending on the clicked place

I have this idea of this world map image and when I click a country on it, it shows information of that country in a MessageBox for example does anyone have an idea how to do that?
I have a rectangle and a button and when i click the button it shows the image in the rectangle but i thought if i use polygons to shape the country's but I'm a little stuck.
I would like to have every country apart and maybe that the borders light up when clicked
You can do this pretty easily using WPF:
Find a nice World Map in SVG format. I used this one from Wikipedia:
Download and install Inkscape then open the SVG you've just downloaded. Inkscape has a nice feature that makes it possible to save an SVG as a XAML.
Import the ViewBox from the XAML file into your WPF window/etc:
For each Path in the XAML you can add a MouseEnter/MouseLeave event handler or you can use the same one for all the Paths
Sample code:
private void CountryMouseEnter(object sender, MouseEventArgs e)
{
var path = sender as Path;
if (path != null)
{
path.Fill = new SolidColorBrush(Colors.Aqua);
}
}
private void Country_MouseLeave(object sender, MouseEventArgs e)
{
var path = sender as Path;
if (path != null)
{
path.Fill = new SolidColorBrush(Colors.Black);
}
}
Now it's just a matter of changing colors/showing MessageBoxes etc.
GitHub
My first thought: You could bind a command to the view that will be triggered by a click on a position. If you're using WPF you can bind command parameters to the command to get the x and y of your click...
After that you have to handle the content of your messagebox and the highlighting of the borders depending on the position xy.
have fun :D
Option 1
There is a project on Code Project that someone created that defines hotspots that are clickable with events. You could use that to overlay your map and define the hotspots where you need them.
C# Windows Forms ImageMap Control
Option 2
You could bind to the MouseUp Event on the Image and use the following to see if it is in a Rectangle
private void mapMouseUp(object sender, MouseEventArgs e) {
Rectangle rect1 = new Rectangle(0, 0, 100, 100);
Rectangle rect2 = new Rectangle(0, 100, 100, 100);
if (rect1.Contains(e.Location)) {
// Do your stuff
} else if (rect2.Contains(e.Location)) {
// Do your stuff
}
}

Parameter to an image

How to add a parameter for an image to this variable?
var selectionDisplay = new SelectionDisplay(button.Label as string);
Thanks in advance!
EDIT:
I have this set of images and their respective code below (see pic1)
This is where the program gets the images to be displayed. The code for the buttons is this one:
var files = Directory.GetFiles(#".\GalleryImages");
foreach (var file in files)
{
FileInfo fileInfo = new FileInfo(file);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(file, UriKind.Relative);
bi.EndInit();
var button = new KinectTileButton
{
Label = System.IO.Path.GetFileNameWithoutExtension(file),
Background = new ImageBrush(bi)
};
this.wrapPanel.Children.Add(button);
}
This is where the program gets the images to be displayed.
The code for the buttons is this one:
private void KinectTileButtonclick(object sender, RoutedEventArgs e)
{
var button = (KinectTileButton)e.fake_fake_fakeource;
var selectionDisplay = new SelectionDisplay(button.Label as string);
this.kinectRegionGrid.Children.Add(selectionDisplay);
e.Handled = true;
Right now, when i click on of the images, the SelectionDisplay window pops up, which look like this (see pic2). What i want is that when I click an image the SelectionDisplay window should open with the respective image... meaning that if I click on the image with a dog, the window should open with the dog's image, not with other image.
I hope I've made myself clear and that you can help me.
http://i58.tinypic.com/8zl6h3.jpg
http://i57.tinypic.com/208fosy.png
is this the constructor you are talking about? is this where i should make changes? should i add something after "string itemid"?
public SelectionDisplay(string itemId)
{
this.InitializeComponent();
this.messageTextBlock.Text = string.Format(CultureInfo.CurrentCulture,Properties.Resources.SelectedMessage,itemId);
}
I see two approaches:
Just pass the image brush in your constructor. Its view->view, so you aren't breaking MVVM (and it looks like you aren't using that pattern anyways).
new SelectionDisplay(button.Label, button.Background);
Set the path as the "tag" of the button. The tag property is an object you can put whatever you want into (the framework does not use it, and so it is included for this very purpose). Then just pass the string to SelectionDisplay, and instantiate the image just like you are doing for the button:
var button = new KinectTileButton
{
Label = System.IO.Path.GetFileNameWithoutExtension(file),
Background = new ImageBrush(bi),
Tag = file
};
var selectionDisplay = new SelectionDisplay(button.Label as string, button.Tag as string);
FrameworkElement.Tag on MSDN (Note that Button derives from FrameworkElement, as do all controls, so it automatically has it as well!)
UPDATE
I see that SelectionDisplay is a UserControl in your project, so you just need to change its constructor to look like:
Numbers match above:
SelectionDisplay(string labelText, ImageBrush sourceImage)
SelectionDisplay(string labelText, string imagePath)
That is the source of the error you are getting, you have to modify the constructor to take the new parameter.
Please let me know if I can clarify anything.

Programmatically added controls not showing when added to a tab page

Up till now I have been just displaying my programmatically created controls to this.controls but now I want to add in tabbing functionality for large sets of data. I added in a tab control and in the code I have the programmatic controls added to the tabpage but I cannot get the controls to display... help what do I need to do get the controls to display
right now what i have is
private void Form1_Load(object sender, EventArgs e)
{
panel = new Panel();
panel.Location = position;
panel.BorderStyle = BorderStyle.Fixed3D;
panel.Width = 240;
panel.Height = 210;
company = new Label();
company.Location = new Point(panel.Location.X + 10, panel.Location.Y + 10);
company.Text = tempServer.Value.companyName;
company.Font = new Font(company.Font.FontFamily, 12, FontStyle.Bold);
tabs.TabPages["1"].Controls.Add(company);
this.Controls.Add(tabs);
this.Controls.SetChildIndex(tabs, this.Controls.Count);
}
Edit(to help clarify)
I have an application which reads from a database for each tuple in the data base my WinForm application creates a new panel which is then populated with various information with dynamically created labels. the position is then offset and the next panel is created. I was informed that i need to now have my application support tabs. each tab will only show so many panels. my problem accured when i tried to add these dynamically created panels to the tab control instead of this.control. when i did so the panels and their information was no longer being drawn and I cant figure out how to make the panels display
You didn't set Text for your label so you didn't see any thing, try this:
company = new Label(){Text = "some text here"};
The whole code:
private void Form1_Load(object sender, EventArgs e) {
company = new Label{Text = "some text here"};
tabs.TabPages["1"].Controls.Add(company);
this.Controls.Add(tabs);
}

How to get the name of a control under the mouse pointer ( without making an event handler for each control )?

I have an mdichild, and an eventhandler for draganddrop so when I drop an image file in my form, a picturebox ( name = dpic ) is created with that image.
I have another eventhandler which is for dpic_Click, so when I click on the image, my form's text is the name of that image.
After the first time I drop an image, another dpic is created, because you can't have two cotrols with the same name. C# automatically changes the name and that makes my event handlers only work for the last image I dropped in. I think if I could make an event handler for my mdichild that gets the name of the control that is under the mouse pointer I could simply change back the image I am pointing at.
UPDATE
Here is my code , I made an event handler for droping in my mdichild :
void mdiChild_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
dpic = new PictureBox() ;
string[] filepath = (string[])e.Data.GetData(DataFormats.FileDrop);
Image image = Image.FromFile(filepath[0]);
dpic.Image = image;
dpic.Tag = Path.GetFileName(filepath[0]);
this.ActiveMdiChild.Controls.Add(dpic);
dpic.ContextMenuStrip = this.contextMenuStrip1;
this.ActiveMdiChild.Refresh();
dpic.BringToFront();
this.ActiveMdiChild.ActiveControl = dpic;
dpic.Click += new EventHandler(dpic_Click);
// _____this helped me do it_________________________________________________
foreach (Control c in this.ActiveMdiChild.Controls)
{
c.Click += new EventHandler(c_Click);
}
// ________________________________________________________________________
}
}
What you are looking for is a sender. The sender will tell which image was clicked and will allow you to get its name.
PictureBox picSender = (PictureBox)sender;
label1.Text = picSender.Name;
EDIT : You put that in the pic_Click event
I don't understand exactly what you want to do here, possibly layering new pictureboxes with dropped images on the form?
If that is so you can use a
List<PictureBox> picboxes = new List<PictureBox>();
and where you do:
dpic = new PictureBox() ;
change to
PictureBox dpic = new PictureBox() ;
picboxes.Add(dpic);
this.Controls.Add(dpic);
But please note that you cannot have unlimited controls declared.

Categories

Resources