Moving a user control around within another user control - c#

I'm trying to write a tetris clone, and after doing some research I've come across an example that uses small user controls to form the block and a bigger user control that contains the grid.
Everything I've written already seems to work just fine (blocks are being generated and placed on the grid, i can even place them somewhere else if I change the code), but I can't seem to get the blocks to move while the program is running. The example I use does this by changing the control.left property of each of the blocks. I've tried this, debugged it and while the property changes, the block doesn't move.
I've searched around for about 4 hours now. I'm a novice programmer, so I know it's probably something stupid, but I cant find what it is.
Here's the methods I've written:
//Class TetrisGame.cs
public void MoveRight()
{
blok.MoveBlock("x", 1);
}
//Class Shape.cs
public void MoveBlock(string pos, int Amount)
{
if (pos == "x")
{
for (int i = 0; i < this.Shape().Count; i++)
{
((Blokje)this.Shape()[i]).MoveSide(1);
}
}
if (pos == "y")
{
for (int i = 0; i < this.Shape().Count; i++)
{
((Blokje)this.Shape()[i]).MoveDown(1);
}
}
//And, the code that should actually move the block in Block.cs:
public void MoveSide(int Step)
{
this.Left += (Step * 20);//Blocks are 20*20 pixels so should move in steps of 20 pixels
}
Shape is actually an arraylist which just contains the 4 Blocks. Block.cs is a partial class since it's the code behind the usercontrol that is the small squares, Shape.cs makes the shapes out of the blocks and tetrisgame is just the gamelogic
the Keypress event:
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
try
{
if (e.KeyChar == 'q')//left
{
if (!paused)
{
Game.MoveLeft();
}
}
else if (e.KeyChar == 'd')//right
{
if (!paused)
{
Game.MoveRight();
}
}
else if (e.KeyChar == 'p')//pause
{
if (paused)
{
tmrGame.Start();
}
else
{
tmrGame.Stop();
}
}
else if (e.KeyChar == 'z')//rotate
{
if (!paused)
{
Game.Rotate();
}
}
else if (e.KeyChar == 'h')//help
{
Help.Show();
}
else if (e.KeyChar == 'f')//save
{
}
else if (e.KeyChar == 's')//Drop
{
if (!paused)
{
Game.Drop();
}
}
}
catch
{
//no error message has to be displayed, this is just to prevent runtime Errors when pressing keys before the game has started
}
}

It seems that the "bigger user control that contains the grid" with it's children is not redrawn.
Change MoveSide to:
public void MoveSide(int Step)
{
this.Left += (Step * 20);
Update();
}
so everything is redrawn correctly.

Related

Pacman Collecting Coins

I tried two different way to collect coins and both didn't work. I don't know what I'm doing wrong. I'm coding in c#. Is there something I'm missing or is there something I'm supposed to do beforehand?
Here is method number 1:
//collecting coins
foreach(Control x in this.Controls)
{
if (x is PictureBox && x.Tag == "coin")
{
if (((PictureBox)x).Bounds.IntersectsWith(pacman.Bounds))
{
this.Controls.Remove(x); //remove that point
score++; // add to the score
}
}
}
and Here is method number 2:
//collecting coins
foreach(Control x in this.Controls)
{
if (x is PictureBox)
{
if ((string)x.Tag == "coin" && x.Visible == true)
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
score += 1;
x.Visible = false;
}
}
}
}
This is work in progress so the code is still missing some parts. Here is a bit of the source code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Pac_Man_Game_Clone
{
public partial class Form1 : Form
{
bool goup, godown, goright, goleft, isGameOver;
int score, playerSpeed, redGhostSpeed, yellowGhostSpeed, pinkGhostX, pinkGhostY;
public Form1()
{
InitializeComponent();
restGame();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void keyisdown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Up)
{
goup= true;
}
if(e.KeyCode == Keys.Down)
{
godown= true;
}
if(e.KeyCode == Keys.Left)
{
goleft= true;
}
if(e.KeyCode == Keys.Right)
{
goright= true;
}
}
private void keyisup(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up)
{
goup = false;
}
if (e.KeyCode == Keys.Down)
{
godown = false;
}
if (e.KeyCode == Keys.Left)
{
goleft = false;
}
if (e.KeyCode == Keys.Right)
{
goright = false;
}
}
private void mainGameTimer(object sender, EventArgs e)
{
txtScore.Text = "Score: " + score;
//moving pacman
if(goleft == true)
{
pacman.Left -= playerSpeed;
pacman.Image = Properties.Resources.left;
}
if(goright == true)
{
pacman.Left += playerSpeed;
pacman.Image = Properties.Resources.right;
}
if(godown == true)
{
pacman.Top += playerSpeed;
pacman.Image = Properties.Resources.down;
}
if(goup == true)
{
pacman.Top -= playerSpeed;
pacman.Image = Properties.Resources.Up;
}
//leaving the parameters
//left and right
if (pacman.Left < -10)
{
pacman.Left = 680;
}
if (pacman.Left > 680)
{
pacman.Left = -10;
}
//up and down
if (pacman.Top < -10)
{
pacman.Top = 550;
}
if (pacman.Top > 550)
{
pacman.Top = -10;
}
//collecting coins
foreach(Control x in this.Controls)
{
if (x is PictureBox)
{
if ((string)x.Tag == "coin" && x.Visible == true)
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
score += 1;
x.Visible = false;
}
}
}
//runs through wall
if ((string)x.Tag == "wall")
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
// run game over
}
}
//bumps to ghost
if ((string)x.Tag == "ghost")
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
// run game over
}
}
}
//moving ghosts
redGhost.Left += redGhostSpeed;
if (redGhost.Bounds.IntersectsWith(pictureBox1.Bounds || redGhost.Bounds.IntersectsWith(pictureBox2.Bounds))
{
redGhost += redGhostSpeed;
}
if (score == int.MaxValue)
{
//run game over
}
}
private void restGame()
{
txtScore.Text = "Score: 0";
score= 0;
redGhostSpeed = 5;
yellowGhostSpeed = 5;
pinkGhostX = 5;
pinkGhostY = 5;
playerSpeed = 8;
isGameOver= false;
pacman.Left = 7;
pacman.Top= 35;
redGhost.Left = 219;
redGhost.Top = 56;
yellowGhost.Left = 450;
yellowGhost.Top = 447;
pinkGhost.Left = 521;
pinkGhost.Top = 227;
foreach(Control x in this.Controls)
{
if(x is PictureBox)
{
x.Visible= true;
}
}
gameTimer.Start();
}
private void gameOver(string message)
{
}
}
}
Without having the full source code and the visual tree, I can only try to understand why this isn't working. To me looks like the pacman object isn't defined in the same parent as the coins.
The bounds property is relative to the parent control as coordinate origin.
It works well if each element in the collection of controls are in at the same level of the visual tree, with the same parent. If not, intersect will hardly be true because it is checking against two different coordinate origins, and even if returns true, the position on screen could not match.
As your pacman seems to be referred somewhere else than your collection, maybe your control does not have the same parent and will unlikely have the same origin for your pacman and the coin, and the IF...ELSE will never hit. Please be sure to use the same parent for the pacman and the coins.
Another solution is to draw the game objects on a canvas using the drawing primitives, and create ad hoc objects to store the drawing rectangles. This is the preferred solution as using GDI+ objects to draw game elements doesn't perform well. If you use the canvas instead, all you must do is to update the canvas on each drawing loop with the images of your game objects. This way, you will have no issues with the visual tree of the controls.
Edit: as stated in other comments, if you succeed to hit the intersection condition, in the first version of your code you will also face exception for removing items from the collection while iterating it using foreach. In this case, the solution is to iterate the list first and add the items to a new "removedItemsList" and then iterate this new list to remove the items from the controls collection without iterate it.
It's not so efficient, your second solution with visibility in my opinion is far better. It's not efficient for at least two motives: one because every time you remove a control the visual tree updated for each remaining control. Second, you must allocate a new list, and reiterate it every time you hit a coin. Visibility instead only invalidate the control render rectangle, and on the next draw routing it will be draw invisible.

Chart Horizontal Scroll with MouseWheel c# winform

i have a problem with my code that i cannot solve:
i have a stacked column chart with indexed x value for the two series that make the chart, i need to scroll horizontally the chart, so i have written this code:
(first in the initialization part)
this.CHART.MouseWheel += CHART_MouseWheel1;
(and then the function part)
private void CHART_MouseWheel1(object sender, MouseEventArgs e)
{
try
{
if (e.Delta > 0)
{
if (this.CHART.ChartAreas[0].AxisX.ScaleView.Position < this.CHART.ChartAreas[0].AxisX.Maximum)
{
this.CHART.ChartAreas[0].AxisX.ScaleView.Position = this.CHART.ChartAreas[0].AxisX.ScaleView.Position + 1;
}
}
else if (e.Delta < 0)
{
if (this.CHART.ChartAreas[0].AxisX.ScaleView.Position > this.CHART.ChartAreas[0].AxisX.Minimum)
{
this.CHART.ChartAreas[0].AxisX.ScaleView.Position = this.CHART.ChartAreas[0].AxisX.ScaleView.Position - 1;
}
}
}
catch { }
}
but for some reason my maximum value this.CHART.ChartAreas[0].AxisX.Maximum exceed the maximum number of the points in the series so i end up with something like this when i scroll to much:
chart visualization in runtime
and i cannot see any relation between my maximum value for the scrolling and the number of point in the series
i also think that i need to tell you that i have this.CHART.ChartAreas[0].AxisX.IsMarginVisible = true; enabled.
hope to solve this also because i am very close to finish my project.
ty all in advance
Hiii guys i found an answer to my problem by myself after trying lots of things, and the main things is that the series X values needs to be indexed, and that make a lot of things easier because you will now work with number of point and not with, in my case, a datetime value, soo that is the code:
private void CHART1_MouseWheel(object sender, MouseEventArgs e)
{
try
{
if (this.CHART1.Series["S1"].Points.Count > 10)
{
if (e.Delta > 0)
{
if (this.CHART1.ChartAreas[0].AxisX.ScaleView.Position < this.CHART1.ChartAreas[0].AxisX.Maximum - this.CHART1.ChartAreas[0].AxisX.ScaleView.Size - 1)
{
this.CHART1.ChartAreas[0].AxisX.ScaleView.Position = this.CHART1.ChartAreas[0].AxisX.ScaleView.Position + 1;
}
}
else if (e.Delta < 0)
{
if (this.CHART1.ChartAreas[0].AxisX.ScaleView.Position > 1)
{
this.CHART1.ChartAreas[0].AxisX.ScaleView.Position = this.CHART1.ChartAreas[0].AxisX.ScaleView.Position - 1;
}
}
}
}
catch (System.Exception ex)
{
throw ex;
}
}
i hope that i have helped same problem tyall

How do I implement a restart function after game over in my game?

I'm a beginner using Visual Studio to make a C# Windows Form. So I have a brick game (like the classic block game with ball and bricks) where if the player doesn't bounce the ball back, it's basically game over. However when this happens, the timer is just stopped and there's no way to restart. The code I have now just says to create a message box with "You lose" and you have to exit the program to play again. If you reach score 30 then that's a win and to play again you have to exit also.
I've tried googling this and the suggestions I see is if it's all set up already in their cases so implementing it to mine without having to re-do it all in someway is hard. I would like to make a simple implementation (or edit) where there is a play again function. How can I modify existing code to do this? Thank you dearly for any help.
This is the section of code that accounts for game-over if statement.
EDIT= Entire code provided.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Media;
using System.Reflection;
using System.IO;
namespace FinalProjectGame
{
public partial class FrmGame : Form
{
bool goLeft;
bool goRight;
int speed = 10;
int pBallx = 5;
int pBally = 5;
int score = 0;
public FrmGame()
{
InitializeComponent();
}
private void keyisdown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Left && btnGamer.Left > 0)
{
goLeft = true;
}
if (e.KeyCode == Keys.Right && btnGamer.Left + btnGamer.Width < 920)
{
goRight = true;
}
}
private void keyisup(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Left)
{
goLeft = false;
}
if (e.KeyCode == Keys.Right)
{
goRight = false;
}
}
private void TmrMainTimer_Tick(object sender, EventArgs e)
{
pBall.Left += pBallx;
pBall.Top += pBally;
lblScore.Text = "Score: " + score; //keeping score
if (goLeft) { btnGamer.Left -= speed; } //izquierda
if (goRight) { btnGamer.Left += speed; } //derecha
if (btnGamer.Left < 1)
{
goLeft = false; //disables "no-clip"
}
else if (btnGamer.Left + btnGamer.Width > 920)
{
goRight = false;
}
if (pBall.Left + pBall.Width > ClientSize.Width || pBall.Left < 0)
{
pBallx = -pBallx; //left, right wall bounce
}
if (pBall.Top < 0 || pBall.Bounds.IntersectsWith(btnGamer.Bounds))
{
pBally = -pBally; //top, bottom wall bounce
}
foreach (Control x in this.Controls)
//main code brickies subtraction
{
if (x is PictureBox && x.Tag == "blockies")
{
if (pBall.Bounds.IntersectsWith(x.Bounds))
{
this.Controls.Remove(x);
pBally = -pBally;
score++;
} //end of main
//ALT method foreach (Control x in this.Controls)
//{
if (!(x is PictureBox))
continue;
//this is needed if some specific property of the PictureBox is needed.
PictureBox ctl = (PictureBox)x;
if (ctl.Tag.ToString() != "blockies")
continue;
if (!pBall.Bounds.IntersectsWith(ctl.Bounds))
continue;
//this.Controls.Remove(x);
x.Visible = false;
pBally = -pBally;
score++;
//}
}
}//----
//This accounts for user score. Upon completing the game, the user wins. If the user does not capture the ball, it is automatically a game over.
if (score == 30)
{
gameOver();
MessageBox.Show("YES! WINNER!");
}
if (pBall.Top + pBall.Height > ClientSize.Height)
{
gameOver();
MessageBox.Show("SORRY YOU LOSE!");
}
//======
}
private void gameOver()
{
TmrMainTimer.Stop();
}
private void FrmGame_Load(object sender, EventArgs e) //main form load
{
//load the splash screen form that was made with design view
SplashScreen splash = new SplashScreen();
splash.Show();
//using system media to play the audio which is played upon start of the main form
SoundPlayer Sndplayr = new SoundPlayer(Properties.Resources.RoleMusic);
Sndplayr.Play();
}
}
}
If you want to restart that WinForms application, use Application.Restart(). You may close your game form and call restart in your static Main() method afterwards.
private void TmrMainTimer_Tick(object sender, EventArgs e)
{
...
if (pBall.Top + pBall.Height > ClientSize.Height)
{
gameOver();
MessageBox.Show("SORRY YOU LOSE!");
// close the game form
this.Close();
}
}
And in your startup code:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FrmGame());
// restart application
Application.Restart();
}
}
Edit:
The example above ist the easiest way to play that game from start. Of course, there are many other options:
As an extension, you can start your game form from a (maybe hidden) program startup form. If you register an event handler on the FrmGame.FormClosed event, you can restart that form again after the previous game was lost.
As many other guys suggested, a StartAgain() method, that resets your logic, is also an option.
Separate drawing logic (View) from game logic (Controller). For a such a simple game it is not necessary and overkill. But it is always a good idea to keep the things simple and clear. See the MVC pattern for your next project...

Making breakout game

My friends I made some parts of this game but I have two problems in this game.
1)Problem about distinguishing ball collision with obstacles
1-1)A first problem is related to complex guidelines that I used them for simulation of ball collision with board or ball collision with blocks. These guidelines are not accurate especially when the ball meets with block corner or bottom.
If it is not better for collision distinguish I use a better code. I wrote this code. Are you think that are there better way?
2)How I can do a work that if the ball collision with any obstacle, the obstacle report the collision.
My aim is about using of events.
Are you thinking that I make obstacles as runtime?
If I make as a runtime, how I can make collision event for them?
With best regards
private Point MouseDownLocation;
int step = 2;
int stepleft = 2;
bool flagBottom;
bool flagTop;
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 10;
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
ball.Top += step;
ball.Left += stepleft;
//board simulate collision
bool collisonX = ball.Location.X + ball.Width > board.Location.X && ball.Location.X < board.Location.X + board.Width;
bool collisonY = ball.Top + ball.Height == board.Location.Y || ball.Top + ball.Height - 1 == board.Location.Y;
//board2(button1) simulate collision
bool collisonX2 = ball.Location.X + ball.Width > board2.Location.X && ball.Location.X < board2.Location.X + board2.Width;
bool collisonY2 = ball.Top + ball.Height == board2.Location.Y || ball.Top + ball.Height - 1 == board2.Location.Y;
//Collision the ball with under buttons
bool collsionButtonY = ball.Top - ball.Height == board2.Location.Y || ball.Top - ball.Height == board2.Location.Y - 1;
//collision leftwall
bool leftWall = ball.Left == 0 || ball.Left == -1 || ball.Left == 1;
//collision rightwall
bool topWall = ball.Top == 0 || ball.Top == -1 || ball.Top == 1;
bool bottomWall = collisonX && collisonY;
bool toppWall = collisonX2 && collisonY2;
//collision
bool barrier = collisonX2 && collsionButtonY;
//rightwall
bool rightWall = ball.Left + ball.Width == this.ClientSize.Width || ball.Left + ball.Width == this.ClientSize.Width - 1;
// sidewall = collision rightwall or leftwall
bool sideWall = leftWall || rightWall;
//Check the ball hit the ground
bool check = ball.Top + ball.Height < this.ClientSize.Height;
//if topWall true,This means that the ball is hit to the topwall
if (topWall)
{
flagBottom = false;
flagTop = true;
if (stepleft > 0)
{
step = 2;
}
else if (stepleft < 0)
{
step = 2;
}
}
//if bottomWall true,This means that the ball is hit to the board
else if (bottomWall)
{
flagBottom = true;
flagTop = false;
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
//if barrier true and flagbottom true,This means that the ball is hit to the board2(button1)
else if (barrier && flagBottom)
{
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
//if toppWall true and flagTop true,This means that the ball is hit to The top button is hit
else if (toppWall && flagTop)
{
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
else if (sideWall)
{
//if leftwall true,This means that the ball is hit to the left side wall
if (leftWall)
{
if (flagTop)
{
stepleft = 2;
}
else if (flagBottom)
{
stepleft = 2;
}
}
//if rightWall true,This means that the ball is hit to the left side wall
else if (rightWall)
{
if (flagTop)
{
stepleft = -2;
}
else if (flagBottom)
{
stepleft = -2;
}
}
}
//check if ckeck==ture,this mean the ball is hit the ground
else if (!check)
{
timer1.Enabled = false;
}
}
private void board_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
MouseDownLocation = e.Location;
}
}
private void board_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
board.Left = e.X + board.Left - MouseDownLocation.X;
}
}
Define each "Wall" as an Object, this will increase your codes readablility. it will also allow you to define an Event for each wall, Listen to t. that way you know which wall has been hit
N.b. this is pseudo code. It wont compile :P
public class Wall
{
int X,Y,W,H;
//Define an event, add a listener to this, becuase we will fire this when there is a collision
public event EventHandler OnCollision;
public void CollisionCheck(Ball playerBall)
{
//1 Check for a collision with the "Ball" object
if(Ball.Rectangle().Intersects(this.Rectangle))
this.OnCollision(this, EventArgs.Empty); //Fire the event, null check might be requried
}
}
I do not know your game but (suspect 2D brick-like game)
Objects/Obstacles
all objects/obstacles can be simplified to rectangular objects
so make list of them with defined parameters like size and position
if they are movable/dropable then also speed and state...
type of object (affects color,scoring,capabilities...)
create member function like update(dt),draw()
create events you like OnHIt,OnCollision,...
for example (C++ pseudo code):
// game object types ...
enum _game_object_type_enum
{
_game_object_type_none=0,
_game_object_type_wall,
_game_object_type_brick1,
_game_object_type_brick2,
_game_object_type_brick3,
_game_object_type_bomb,
_game_object_type_joker1,
_game_object_type_joker2,
...
};
// game object class
class game_object
{
public;
int type; // type of object
float x,y,vx,vy,hx,hy; // position,speed,half size of rectangle
void update(float dt); // this call periodicaly in some timer updates positions,... and call events, dt is time passed
void draw(); // can add some rendering device context ...
};
// whole game class holds the game world/board/map and player(s) ...
class game_board
{
public;
game_object *go; int gos; // list of all objects in game
void update(float dt) { for (int i=0;i<gos;i++) go[i].update(dt); }
void draw() { for (int i=0;i<gos;i++) go[i].draw(); }
}
events and flow control
first define some events you need
either you use global function/pointers for that or as members
depends on your platform and to what you are used to
for example like this:
void OnCollisionFX(game_object o1,game_object o2)
{
// do something ...
}
void (*OnCollision)(game_object o1,game_object o2)=OnCollisionFX;
for player interactions only (like player controlled object collisions test only)
is better to handle this in game_object::update(dt) but you need to add player context
something like game_object::update(dt,plr)
where plr is pointer to player controlled object or player class
if you have massive interactivity between game objects (like brick/brick collisions)
then is better to handle this in game_board::update(dt)
because otherwise you will need to provide references for everything into update call
and that will quickly lead to heap/stack trashing and very slow performance
also more advanced multiple object collision/interaction approaches are better in main game class
here is an example for first case:
void game_object::update(float dt,game_object &plr)
{
// update position
x+=vx*dt;
y+=vy*dt;
// here you should make your own collision test of coarse
if (fabs(x-plr.x)<=hx+plr.hx)
if (fabs(y-plr.y)<=hy+plr.hy)
{
... do what you need like mirror or stop speed or clamp position ...
if (OnCollision) OnCollision(this,plr);
}
}
in second case you should check each object against each other
void game_board::update(float dt)
{
int i,j;
// update position
for (i=0;i<gos;i++)
{
go[i].x+=go[i].vx*dt;
go[i].y+=go[i].vy*dt;
}
// here you should make your own collision test of coarse
for (i=0;i<gos;i++)
for (j=i+1;j<gos;j++) // the lower indexes are already tested
if (fabs(go[i].x-go[j].x)<=go[i].hx+go[j].hx)
if (fabs(go[i].y-go[j].y)<=go[i].hy+go[j].hy)
{
... do what you need like mirror or stop speed or clamp position ...
if (OnCollision) OnCollision(go[i],go[j]);
}
}
performance
you can improve performance by use of type property
for example if some game objets are static then the do not need to update position
if some are indestructible then there can be also some processing avoided and so on ...
[notes]
dt/fps/speed should be combined
so in each frame your player controlled object or any moving object does not move further
then the half size of smallest object
if this is not true then you need better collision test
use line intersection algorithm
last position and actual position gives you one line
and object edge gives you the other one
if booth objects are moving then that is even more complicated :)

Enabling/Disabling Moveup/MoveDown buttons on a ListView

with a form like this:
I wrote this piece of code to take care of enable/disable logic for moveup/down buttons when they click on at item ( we don't care about Avaiable list on the left, we just care about Selected list on the right)
private void SelectedLV_SelectedIndexChanged(object sender, EventArgs e)
{
// what to do wth move up button
if (SelectedLV.SelectedIndices.Count == 1 && SelectedLV.SelectedItems[0].Index > 0)
{
MoveUpBtn.Enabled = true;
}
else
{
MoveUpBtn.Enabled = false;
}
//what to do with move down button
if (SelectedLV.SelectedIndices.Count == 1 && SelectedLV.SelectedItems[0].Index < SelectedLV.Items.Count - 1)
{
MoveDownBtn.Enabled = true;
}
else
{
MoveDownBtn.Enabled = false;
}
}
I think it works fine for that scenario but my question is what about when we click off of Selected Listview, What is good logic to handle that and Disable Both Moveup/Down buttons?
I don't want them be enabled when we are not inside SelectedListView...
Also if you notice any issue with the code I pasted please let me know.
Thanks
You are about to shoot your foot with the focus requirement. These kind of UI updates are best done with the Application.Idle event, it only runs when nothing important is happening. And can help to eliminate a lot of event handlers. Like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
Application.Idle += Application_Idle;
this.FormClosed += delegate { Application.Idle -= Application_Idle; };
}
void Application_Idle(object sender, EventArgs e) {
bool focusOk = this.ActiveControl == SelectedLV;
bool selectOk = SelectedLV.SelectedIndices.Count == 1;
int index = selectOk ? SelectedLV.SelectedIndices[0] : -1;
MoveUpBtn.Enabled = focusOk && selectOk && index > 0;
MoveDownBtn.Enabled = focusOk && selectOk && index < SelectedLV.Items.Count-1;
}
}
Don't forget to set the focus back in the buttons' Click event handler. And don't forget about the ListView.HideSelection property. Set it to False so that focus doesn't matter anymore.
The problem is once you click on the Move buttons, then you are outside of the SelectedListView control, so the logic should really be based on if you have a correct index value or not:
private void SelectedLV_SelectedIndexChanged(object sender, EventArgs e)
if (SelectedLV.SelectedIndicies.Count == 0) {
MoveUpBtn.Enabled = false;
MoveDownBtn.Enabled = false;
} else {
// normal processing
}

Categories

Resources