I'm using a ScrollableControl in my C# project and I'd like to know how to map the arrow keys to vertical/horizontal scrolling.
EDIT : my picture box gets the focus, and i managed to map the keys to scroll. The issue here is that when i hit an arrow key, it scrolls one time and then loses the focus to give it to a button next to the Scrollviewer. I'd like the scrollviewer NOT to lose that focus
This is my code, the second paragraph is the interesting one here.
private void drawMap(IGame game)
{
System.Windows.Forms.PictureBox pictureBox = new System.Windows.Forms.PictureBox();
pictureBox.Width = (int)Math.Sqrt((double)game.Map.grid.Count) * 50; pictureBox.Height = (int)Math.Sqrt((double)game.Map.grid.Count) * 50;
pictureBox.Paint += new System.Windows.Forms.PaintEventHandler(game.Map.afficher);
pictureBox.MouseEnter += pictureBoxFocus;
pictureBox.Click += pictureBoxFocus;
pictureBox.Click += mapClicked;
System.Windows.Forms.ScrollableControl sc = new System.Windows.Forms.ScrollableControl();
sc.Controls.Add(pictureBox);
sc.AutoScroll = true;
windowsFormsHost1.Child = sc;
}
Thank you in advance :)
PLUS : my scrolling algo is kinda dirty and don't works very well so i was wondering if there was an "easy way" to do it.
private void sc_PreviewKeyDown(object sender, System.Windows.Forms.PreviewKeyDownEventArgs e)
{
System.Windows.Forms.ScrollableControl sc = (System.Windows.Forms.ScrollableControl)sender;
switch (e.KeyValue)
{
case (int)System.Windows.Forms.Keys.Down:
sc.VerticalScroll.Value += 50;
break;
case (int)System.Windows.Forms.Keys.Up:
if(sc.VerticalScroll.Value - 50 < 0)
sc.VerticalScroll.Value = 0;
else sc.VerticalScroll.Value -= 50;
break;
case (int)System.Windows.Forms.Keys.Right:
sc.HorizontalScroll.Value += 50;
break;
case (int)System.Windows.Forms.Keys.Left:
if (sc.HorizontalScroll.Value - 50 < 0)
sc.HorizontalScroll.Value = 0;
else sc.HorizontalScroll.Value -= 50;
break;
}
windowsFormsHost1.Child.Focus();
}
Related
I have a custom text box and I'm developing a notepad app. I want to dynamically write the zoom factor of the text box to the label. so I need to use the textbox mousewheel event but it doesn't light up so it doesn't go inside the mousewheel. what should I do ?
first image for here
second image for here
this.txtBoxKryptonText.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.txtBoxKryptonText_MouseWheel);
private void txtBoxKryptonText_MouseWheel(object sender, MouseEventArgs e)
{
int mousedeltaval = e.Delta / 120;
if (mousedeltaval == 1) //mousewheel up move
{
txtBoxKryptonText.ZoomFactor += 0.1F;
statusbarZoomState += 10;
toolStripStatusZoom.Text = "%" + statusbarZoomState;
}
else if (mousedeltaval == -1) //mousewheel down move
{
txtBoxKryptonText.ZoomFactor -= 0.1F;
statusbarZoomState -= 10;
toolStripStatusZoom.Text = "%" + statusbarZoomState;
}
}
Code looks ok to me.
Place your mouse pointer very close to the edge of the textbox and you'll see it works.
If you want to handle the events over the entire area you should probably do something like:
this.txtBoxKryptonText.ContainedControl.MouseWheel
+= new System.Windows.Forms.MouseEventHandler(this.txtBoxKryptonText_MouseWheel);
I'm trying to design a button that has the DockChanged EH that knows the height & width of its paren't container (panel) and adjusts its metrics accordingly. E.g. button has text and icon, but if button width is in a panel that is too small, it will just show its icon and disable the text, etc.
Here's the method i'm trying to invoke the method with:
InnerPanel.DockChanged += HandleDockChanged;
Here's the method i'm trying to invoke the method on:
private void HandleDockChanged(EventArgs args)
{
//sorry for magic numbers
if (Parent.Height < Height || Parent.Width < Width)
{
TextLabel.Enabled = false;
InnerPanel.Width = ButtonWidth;
InnerPanel.Height = ButtonHeight;
Padding = new Padding(1);
}else
{
TextLabel.Enabled = true;
InnerPanel.Width = ButtonWidth * 2;
InnerPanel.Height = ButtonWidth * 2;
}
}
I'm making a program that will make buttons on the screen from a for loop. This is important because the user needs to have access to the number of buttons, and could change with every run. This is the code i have so far:
public Form1()
{
InitializeComponent();
int top = 5;
int left = 5;
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Height = 50;
button.Left = left;
button.Top = top;
this.Controls.Add(button);
left += button.Width + 2;
}
}
What i want is basically something like this:
Button b+i = new Button();
Its like when combining two strings, i want the name of the button on the first run in the loop to be b0, then b1, then b2, and so on.
I use Visual Studio, and InitializeComponent() goes to the editor generated code to make the window and stuff. nothing but the window is made there.
Thank you for your help!
Worrying about the variable names is the wrong way to approach this problem. There are several alternatives:
Use a list
List<Button> buttons;
public Form1()
{
InitializeComponent();
buttons = new List<Button>();
int top = 5;
int left = 5;
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Height = 50;
button.Left = left;
button.Top = top;
this.Controls.Add(button);
buttons.Add(button);
left += button.Width + 2;
}
}
//now instead of 'b1', it's 'buttons[1]'
Which you could also create with the OfType() method:
var buttons = this.Controls.OfType<Button>().ToList();
These can be done in combination with a FlowLayoutPanel or TableLayoutPanel to simplify the code:
public Form1()
{
InitializeComponent();
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Height = 50;
FlowLayoutPanel1.Controls.Add(button); //panel handles Left/Top location
}
}
The panel also has the advantage of helping your app scale at different dpi's or screen/window sizes.
Any of which could also be adapted to start thinking in terms of connecting to a datasource (and reduce the code):
var buttons = Enumerable.Range(0, 10).Select(b => new Button {
Height = 50,
Left = 5 + ( b * (BUTTONWIDTH + 2) ),
Top = 5,
Name = String.Format("Button{0}", b)
});
//buttons.ToList()
//or
//this.Controls.AddRange(buttons.ToArray())
//or
//FlowLayoutPanel1.Controls.AddRange(buttons.ToArray()) //Remove Left/Top code
But all of this is meaningless until you can get the buttons to actually do something. You need an event handler for (at least) the Click event:
foreach (var b in butons)
{
b.Click += (s,e) =>
{
//click code for all of the buttons goes here
// you can tell the buttons apart by looking at the "s" variable
};
}
since people (rightly) said 'use an array' here is code
public Form1()
{
InitializeComponent();
int top = 5;
int left = 5;
var buttons = new Button[10];
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Height = 50;
button.Left = left;
button.Top = top;
this.Controls.Add(button);
left += button.Width + 2;
buttons[i] = button;
}
}
I tried to Google how to make drag & drop for UIElements on a Canvas, but couldn't find anything that I'm looking for.
I got a C# WPF application with a Window. Inside the Window I got a Canvas where I can add Images to.
What I want is to be able to Drag & Drop the Images, while staying within the Canvas' borders.
I also want this to be in code, so not in the xaml.
I got this in the function where I add/update the Images to the Canvas. The TODO's should be replaced for the Drag & Drop events.
Image img = ImageList[i].Image;
img.Name = "Image" + i;
// TODO: Drag and Drop event for Image
// TODO: Check if Left and Top are within Canvas (minus width / height of Image)
Canvas.SetLeft(img, Left); // Default Left when adding the image = 0
Canvas.SetTop(img, Top); // Default Top when adding the image = 0
MyCanvas.Children.Add(img);
OnPropertyChanged("MyCanvas");
PS: Though this is for later, if someone has code to drag and drop multiple images at once as an additional bonus, I would appreciate it.
Thanks in advance for the help.
Fixed my problem below, by using the following code:
img.AllowDrop = true;
img.PreviewMouseLeftButtonDown += this.MouseLeftButtonDown;
img.PreviewMouseMove += this.MouseMove;
img.PreviewMouseLeftButtonUp += this.PreviewMouseLeftButtonUp;
private object movingObject;
private double firstXPos, firstYPos;
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
// In this event, we get the current mouse position on the control to use it in the MouseMove event.
Image img = sender as Image;
Canvas canvas = img.Parent as Canvas;
firstXPos = e.GetPosition(img).X;
firstYPos = e.GetPosition(img).Y;
movingObject = sender;
// Put the image currently being dragged on top of the others
int top = Canvas.GetZIndex(img);
foreach (Image child in canvas.Children)
if (top < Canvas.GetZIndex(child))
top = Canvas.GetZIndex(child);
Canvas.SetZIndex(img, top + 1);
}
private void PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
Image img = sender as Image;
Canvas canvas = img.Parent as Canvas;
movingObject = null;
// Put the image currently being dragged on top of the others
int top = Canvas.GetZIndex(img);
foreach (Image child in canvas.Children)
if (top > Canvas.GetZIndex(child))
top = Canvas.GetZIndex(child);
Canvas.SetZIndex(img, top + 1);
}
private void MouseMove(object sender, MouseEventArgs e) {
if (e.LeftButton == MouseButtonState.Pressed && sender == movingObject) {
Image img = sender as Image;
Canvas canvas = img.Parent as Canvas;
double newLeft = e.GetPosition(canvas).X - firstXPos - canvas.Margin.Left;
// newLeft inside canvas right-border?
if (newLeft > canvas.Margin.Left + canvas.ActualWidth - img.ActualWidth)
newLeft = canvas.Margin.Left + canvas.ActualWidth - img.ActualWidth;
// newLeft inside canvas left-border?
else if (newLeft < canvas.Margin.Left)
newLeft = canvas.Margin.Left;
img.SetValue(Canvas.LeftProperty, newLeft);
double newTop = e.GetPosition(canvas).Y - firstYPos - canvas.Margin.Top;
// newTop inside canvas bottom-border?
if (newTop > canvas.Margin.Top + canvas.ActualHeight - img.ActualHeight)
newTop = canvas.Margin.Top + canvas.ActualHeight - img.ActualHeight;
// newTop inside canvas top-border?
else if (newTop < canvas.Margin.Top)
newTop = canvas.Margin.Top;
img.SetValue(Canvas.TopProperty, newTop);
}
}
This code allows me to drag-and-drop the Images inside the Canvas, without leaving the Canvas itself.
Now I just need to be able to do two more things:
Fix a little bug where my Mouse slips of the Image when I drag them around to fast. This happens quite often, even when I'm not even moving the dragging image around THAT fast.. Fixed by using the solution mentioned in my other question.
Making it able to drag-and-drop multiple images at once, preferably by selecting multiple first, and then drag-and-drop the whole bunch of them while staying inside the Canvas.
Will make a new Question for this.
I was did a project that uses a chunk of your code and does drag and drop on canvas, look into it and see if there be any difference, dont really have the time to check
private void pinCanvas_PreviewMouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
{
// Point pt = e.GetPosition(pinCanvas);
// Curosor.Text = String.Format("You are at ({0}in, {1}in) in window coordinates", (pt.X / (96 / 72)) * 1/72, (pt.Y / (96 / 72)) * 1/72);
}
bool captured = false;
double x_shape, x_canvas, y_shape, y_canvas;
UIElement source = null;
string elementName;
double elementHeight, elementWidth;
private void pinCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
setCanvasSize();
source = (UIElement)sender;
elementName = ((Label)source).Name;
switch (elementName)
{
case "pinTextBox" :
elementHeight = pinActualHeight;
elementWidth = pinActualWidth;
break;
case "serialTextBox" :
elementHeight = serialActualHeight;
elementWidth = serialActualWidth;
break;
case "batchTextBox" :
elementHeight = batchActualHeight;
elementWidth = batchActualWidth;
break;
}
Mouse.Capture(source);
captured = true;
x_shape = Canvas.GetLeft(source);
x_canvas = e.GetPosition(Maincanvas).X;
y_shape = Canvas.GetTop(source);
y_canvas = e.GetPosition(Maincanvas).Y;
}
private void pinCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (captured)
{
double x = e.GetPosition(Maincanvas).X;
double y = e.GetPosition(Maincanvas).Y;
var xCond = Math.Round(appActivities.DIP2Inch(x_shape), 4).ToString();
var yCond = Math.Round(appActivities.DIP2Inch(y_shape), 4).ToString();
var name = ((Label)source).Name;
x_shape += x - x_canvas;
// if ((x_shape < Maincanvas.ActualWidth - elementWidth) && x_shape > 0)
// {
Canvas.SetLeft(source, x_shape);
switch (name)
{
case "pinTextBox" :
pinOffsetLeft.Text = xCond;
break;
case "serialTextBox" :
serialOffsetLeft.Text = xCond;
break;
case "batchTextBox" :
batchOffsetLeft.Text = xCond;
break;
}
// }
x_canvas = x;
y_shape += y - y_canvas;
// if (y_shape < Maincanvas.ActualHeight - elementHeight && y_shape > 0)
// {
Canvas.SetTop(source, y_shape);
switch (name)
{
case "pinTextBox":
pinOffsetTop.Text = yCond;
break;
case "serialTextBox":
serialOffsetTop.Text = yCond;
break;
case "batchTextBox":
batchOffsetTop.Text = yCond;
break;
}
// }
y_canvas = y;
}
}
private void pinCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
captured = false;
// MessageBox.Show((Canvas.GetTop(source)).ToString());
/* if (Canvas.GetTop(source) < 0)
{
Canvas.SetTop(source, 0);
}
if (Canvas.GetLeft(source) < 0)
{
Canvas.SetLeft(source, 0);
}
if (Canvas.GetLeft(source) > Maincanvas.ActualWidth - elementWidth)
{
// MessageBox.Show("Left Too Much " + (Canvas.GetLeft(source) * 1/96).ToString());
Canvas.SetLeft(source, Maincanvas.ActualWidth - elementWidth);
}
if (Canvas.GetTop(source) > Maincanvas.ActualHeight - elementHeight)
{
Canvas.SetTop(source, Maincanvas.ActualHeight - elementHeight);
} */
oneElemntTorched = true;
//MessageBox.Show(this.pinTextBox.ActualHeight.ToString() + ", " + this.pinTextBox.ActualWidth.ToString());
}
I have two controls on the same form. Both controls contain an ObjectListView control. The one listview was created with the graphical editor in visual studio. This one is not causing any issues. The other listview is created programmatically at run-time. I have defined an event handler for each control that gets called when the hot item changes and they are both firing when they should. Both event handlers call the same code to update a picturebox control. The problem is that the picturebox does not get updated when the programmatically defined listview is asking it to. I am positive the event handler is getting called because my code writes to a text file as well as updating the picture box. The text file gets updated but the picture box does not. I have tried updating, invalidating, and refreshing the PicutureBox as well as the parent form, but I just can not get it to update.
I am not sure if this is an ObjectListView issue or a standard WinForms problem. I realize my question is very vague but I am not sure how to clarify it without posting all my code. Any advice would be appreciated.
Here is the code that the event handler calls:
public void ShowBitmap(object sender, HotItemChangedEventArgs e, ObjectListView lv, string type)
{
ObjectListView olv = sender as ObjectListView;
if (sender == null)
{
return;
}
switch (e.HotCellHitLocation)
{
case HitTestLocation.Nothing:
break;
case HitTestLocation.Group:
break;
case HitTestLocation.GroupExpander:
break;
default:
if (e.HotColumnIndex == 0)
{
pictureBox1.Hide();
pictureBox1.BorderStyle = BorderStyle.FixedSingle;
int rowIndex = e.HotRowIndex;
string text = "";
if (type == "Main Parts")
{
TypedObjectListView<MainRadanProjectPartsPart> tlist = new TypedObjectListView<MainRadanProjectPartsPart>(lv);
text = tlist.Objects[rowIndex].Symbol;
}
else if (type == "Parts")
{
TypedObjectListView<RadanProjectPartsPart> tlist = new TypedObjectListView<RadanProjectPartsPart>(lv);
text = tlist.Objects[rowIndex].Symbol;
}
else if (type == "Nests")
{
TypedObjectListView<MainRadanProjectNestsNest> tlist = new TypedObjectListView<MainRadanProjectNestsNest>(lv);
text = tlist.Objects[rowIndex].FileName;
}
if (text != null)
{
Point screenCoords = Cursor.Position;
Point controlRelatedCoords = lv.PointToClient(screenCoords);
if (controlRelatedCoords.Y < oldCursorPosition.Y)
{
pictureBox1.Location = controlRelatedCoords;
int xPos = controlRelatedCoords.X;
int yPos = controlRelatedCoords.Y + 60;
pictureBox1.Location = new Point(xPos, yPos);
}
else if (controlRelatedCoords.Y > oldCursorPosition.Y)
{
pictureBox1.Location = controlRelatedCoords;
int xPos = controlRelatedCoords.X;
//int yPos = controlRelatedCoords.Y - pictureBox1.Height;
int yPos = controlRelatedCoords.Y - pictureBox1.Height + 30;
pictureBox1.Location = new Point(xPos, yPos);
}
pictureBox1.Show();
pictureBox1.BringToFront();
olvTreeViewMainParts.Focus();
lv.Focus();
pictureBox1.Visible = true;
DrawSymbol(text);
oldCursorPosition = controlRelatedCoords; // save the cursor position to track cursor direction between calls
}
else
{
DrawSymbol("");
}
}
else
{
pictureBox1.Hide();
}
break;
}
}
Here is the event handler for the programmaticaly defined listview:
// track the cursor as it moves over the items in the listview
private void olvPartsListView_HotItemChanged(object sender, HotItemChangedEventArgs e)
{
ShowBitmap(sender, e, olvPartsListView, "Parts");
}