|
Hi,
that still is too complex to my taste.
This is what works for me:
1.
I created my own Rect class, which basically is a rectangle, however it hides all its details from the Form/Panel/PictureBox.
Having a class, however simple it initially is, allows me:
- to treat the thing as an object;
- to make the code more readable;
- to add, at a later time, extra features, e.g. a more elaborate paint behavior without affecting the caller's code.
2.
There is no redundant data, reducing the probability of logic errors.
3.
My MouseDown and MouseUp handlers are extremely short, and my MouseMove handler, which holds all the logic, clearly has two parts (mouse up and mouse down).
using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace RectMove {
public partial class Form1 : Form {
Rect rect;
bool m_mouseDown = false;
Rect movingRect = null;
Point prevMouseLoc;
public Form1() {
InitializeComponent();
this.DoubleBuffered = true;
}
private void Form1_Load(object sender, EventArgs e) {
rect = new Rect(200, 100, 100, 50);
}
private void panel1_Paint(object sender, PaintEventArgs e) {
Graphics g = e.Graphics;
rect.Paint(g);
}
private void panel1_MouseDown(object sender, MouseEventArgs e) {
m_mouseDown = true;
prevMouseLoc = e.Location;
}
private void panel1_MouseUp(object sender, MouseEventArgs e) {
m_mouseDown = false;
}
private void panel1_MouseMove(object sender, MouseEventArgs e) {
if (m_mouseDown) {
if (movingRect != null) {
Point mouseLoc = e.Location;
movingRect.Move(prevMouseLoc, mouseLoc);
prevMouseLoc = mouseLoc;
Invalidate(true);
}
} else {
movingRect = null;
if (rect.Contains(e.Location)) movingRect = rect;
}
Console.WriteLine("movingRect=" + movingRect);
}
}
public class Rect {
private static Pen pen=Pens.Red;
private Rectangle rect;
public Rect(int x, int y, int w, int h) {
rect = new Rectangle(x, y, w, h);
}
public override string ToString() {
return "Rect" + rect.Location+rect.Size.ToString();
}
public void Move(Point oldLoc, Point newLoc) {
rect.X += newLoc.X - oldLoc.X;
rect.Y += newLoc.Y - oldLoc.Y;
}
public bool Contains(Point pt) {
return rect.Contains(pt);
}
public void Paint(Graphics g) {
g.DrawRectangle(pen, rect);
}
}
Note: I don't clear movingRect after a move, as one could move a rectangle, then release and press the mouse button again without moving the mouse at all, so the rectangle IMO should continue its move.
modified 28-Apr-20 10:55am.
|
|
|
|
|
I followed your steps, of course without using a class, now the move function determines whether to draw a new rectangle or move it, but the moving action is not happening. Resizing we will back to it later:
public partial class Form3 : Form
{
Rectangle rect;
Point StartXY;
Point EndXY;
int x = 0;
int y = 0;
int height = 0;
int width = 0;
bool m_mouseDown = false;
bool m_movingRect = false;
Pen rectPen = new Pen(Color.Red, 1);
public Form3()
{
InitializeComponent();
this.DoubleBuffered = true;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics gObj = e.Graphics;
rect = new Rectangle(x, y, height, width);
rectPen.DashStyle = DashStyle.Dash;
gObj.DrawRectangle(rectPen, rect);
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
m_mouseDown = true;
if (rect.Contains(e.Location))
{
m_movingRect = true;
Console.WriteLine("m_mouseDown");
}
StartXY = e.Location;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (rect.Contains(e.Location))
this.Cursor = Cursors.SizeAll;
else
this.Cursor = Cursors.Default;
if (m_mouseDown && rect.Contains(e.Location))
{
rect.X += e.X - StartXY.X;
rect.Y += e.Y - StartXY.Y;
StartXY = e.Location;
Console.WriteLine("pictureBox1_MouseMove StartXY " + StartXY.X);
Console.WriteLine("pictureBox1_MouseMove StartXY " + StartXY.Y);
Console.WriteLine("pictureBox1_MouseMove rect " + rect.X);
Console.WriteLine("pictureBox1_MouseMove rect " + rect.Y);
}
if (m_mouseDown && !rect.Contains(e.Location))
{
EndXY = e.Location;
x = Math.Min(StartXY.X, EndXY.X);
y = Math.Min(StartXY.Y, EndXY.Y);
height = Math.Abs(StartXY.X - EndXY.X);
width = Math.Abs(StartXY.Y - EndXY.Y);
}
Invalidate(true);
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (!m_movingRect)
{
EndXY = e.Location;
}
m_mouseDown = false;
m_movingRect = false;
Invalidate();
}
}
|
|
|
|
|
Hi,
1.
you have too many variables, this is called data redundancy. In particular you have both x,y,width,height and rect; in some parts you operate on x,y in others on rect.X and rect.Y, and that is why it does not behave as you would hope.
The rule is: avoid redundancy; there isn't anything positive about redundancy, it adds variables and code, and it just makes it harder to pinpoint logic errors.
Using a separate class helps in achieving this, or at least makes it harder to break the rule.
2.
To make matters worse, you change your data model (your "business logic") inside the Paint handler, where it says
rect=new Rectangle(x,...) .
You should never modify your business model inside a Paint handler; a Paint handler should behave as an observer, and not as a participant.
Reason: you don't know when a Paint handler will be executed:
(a) calling Invalidate tells the system your business model has changed and a repaint is required, so a repaint message is queued, but not executed right away (e.g. several calls to Invalidate may result in a single repaint);
(b) a Paint handler will also run when something happened to your window, e.g. when a pop-up dialog (may be from another app or from Windows itself) temporarily had hidden (part of) your window.
The only kind of variables your Paint handler should ever modify are the ones that are needed by the Paint handler itself, so it would be OK to write if (pen==null) pen=new Pen(Color.Red); assuming pen isn't part of your business stuff.
3.
I counted the number of lines in your code and mine, excluding empty lines, lines with a single bracket, comments, and Console.WriteLine lines; my code (Form+Rect) is 43 lines, yours 50. Which tells me using a class is the right way to go: it does not add to the code, and it supports what is known as "separation of concerns": let each piece of code take care of what matters to it without being troubled with details that don't matter there. Example: my form tells the Rect to paint itself or to move itself without caring how that is done, whereas the Rect knows how to paint or move itself without knowing why it should.
modified 29-Apr-20 9:01am.
|
|
|
|
|
Hi, all....
I am trying to execute the code below, but returns error due to date comparison :
<pre0>
cmd.CommandText = @"update TabFx set Date_xyz= @fer, Descrip=@descr where Date_xyz=" + Convert.ToDateTime(DataGridView1.SelectedRows[0].Cells[0].Value)
cmd.Parameters.AddWithValue("@fer", Convert.ToDateTime(DGV1.SelectedRows[0].Cells[0].Value));
cmd.Parameters.AddWithValue("@descr", DataGridView1.SelectedRows[0].Cells[1].Value);
cmd.ExecuteNonQuery();
Date_xyz is as field type DateTime in a MSAccess Table
How can I do this compare?
Thanks in advance!
|
|
|
|
|
Hi,
you are using a mix of parameter substitution (which is good) and direct string concatenation (which is bad).
When concatenating (which is bad) SQL expects dates or datetimes in a specific format and inside quotes.
Why don't you use AddWithValue() for the date as well?
Some examples[^]
|
|
|
|
|
Thanks for reply Luc...but the problem happens in the SQL command, when compare the field data (from the database) with the DataGridView cell that contains a date (sorry for the bad English...)...it returns error : "Wrong data type in criteria"
I don't know how to write the comparison...
the line is :
cmd.CommandText = @"update TabFx set Ferx =@fer, Descrip=@descr where Ferx="
+ Convert.ToDateTime(DGV1.SelectedRows[0].Cells[0].Value);
|
|
|
|
|
You can use a parameter in the WHERE part of your SQL statement just like you do in the SET part, so it could look like
CommandText = "... WHERE Ferx=@Ferx";
...
cmd.Parameters.AddWithValue("@Ferx", Convert.ToDateTime(DataGridView1.SelectedRows[0].Cells[0].Value));
Warning: IIRC you must provide the parameters (i.e. the calls to AddWithValue and the like) in the same order as the parameters appear in your SQL statement, since OleDb+Access does not really care about the parameter names!
|
|
|
|
|
ok Luc...I used your tip and it Works....thank you very much for the help
|
|
|
|
|
you're welcome
|
|
|
|
|
|
Thank you Richard for the reading suggestion....I'll be Reading this....
|
|
|
|
|
Hi All,
I have a WinSCP Directory and have files in it. I need to get the date as 01_MMM (MMM represents the current month example- 01_APR and for May it should return 01_MAY so on and so forth) and I need to append this string '01_MMM' to the name of the file.
Please let me know how can I achieve that using C# Only.
Thanks,
Sriram
|
|
|
|
|
The System.IO namespace has lots of classes which you can use. There is some code as a good starting point here, list - Getting all file names from a folder using C# - Stack Overflow[^].
Social Media - A platform that makes it easier for the crazies to find each other.
Everyone is born right handed. Only the strongest overcome it.
Fight for left-handed rights and hand equality.
|
|
|
|
|
Thank you for your response but this is not in the regular windows directory. This directory is a remote path. I am connecting to this WinSCP directory by giving hostname,username and password.
EnumerateRemoteFiles is what I am using to read the file names but I am unable to find a function to rename them in remote directory.
|
|
|
|
|
Sriram Valluri wrote: WinSCP directory
I think what you mean then is that it is an ftp directory. Just google how to rename ftp files via c#.
Social Media - A platform that makes it easier for the crazies to find each other.
Everyone is born right handed. Only the strongest overcome it.
Fight for left-handed rights and hand equality.
|
|
|
|
|
|
below is my code.
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = "ap*****",
UserName = "****",
Password = "******",
SshHostKeyFingerprint = "*******"
};
using (Session session = new Session())
{
session.ExecutablePath = @"WinSCP.exe path";
session.Open(sessionOptions);
List<RemoteFileInfo> files =
session.EnumerateRemoteFiles(
MonitorDirectory, FileSearchPattern, EnumerationOptions.None)
.ToList();
DateTime now = DateTime.Today;
ReportMonth = now.ToString("MMM").ToUpper();
foreach (RemoteFileInfo fileInfo in files)
{
------------------------------have to do renaming of the file here---------------------------
if (fileInfo.FullName.Contains(GetClientID))
{
if (fileInfo.Length > ThresholdValue)
{
FileModifiedDate = fileInfo.LastWriteTime.ToString("yyyyMM", CultureInfo.InvariantCulture);
if (GetReportDateYM == FileModifiedDate || fileInfo.FullName.Contains(ReportMonth))
{
FileName = fileInfo.FullName;
Dts.Variables["User::FileName"].Value = FileName;
Dts.Variables["User::FileDate"].Value = FileModifiedDate;
Dts.TaskResult = (int)ScriptResults.Success;
break;
}
}
}
So here I have a directory in remote server and I am accessing it through WinSCP tool. requirement is to rename the files insider this remote directory. I can read each and every file name but I am not able to find rename function here.
|
|
|
|
|
Hi,
I have no experience with WinSCP, however browsing the documentation I'm now convinced what you need is here[^].
Google is your friend, treat him well.
|
|
|
|
|
Thank you Luc Pattyn. will go through the same.
|
|
|
|
|
Dear all,
I am sorry by now, I want to use Multicombobox in datagridview,
I have access file have two table :ItemAll, Pur in acccess file.Column Items in datagridview1 is Combobox,
1- I want to create column of items as multicombobox ,when click on culumn Items , its doplist table ItemAll have two column :Items,NameItem.
2-In datagridview , when click multicombobox anh selcect Items column in combobox , In columm datagridview will receive data .
I have added Multicombobox.cs, MulticomboboxPopup in project, I use dataset ACCSDataset.
Thank you
My email:[DELETED]@gmail.com
modified 27-Apr-20 1:25am.
|
|
|
|
|
Never post your email address in any forum, unless you really like spam! If anyone replies to you, you will receive an email to let you know.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I am programing and application for work which requires a certain level of access rights to users. Once logged in I get the access level number 1-10 which is then put onto a splash screen in a hidden txt box.
on the closure of the splash screen i would like it to go to a menu for that access right.
This is the code I am using
private void tmr_splash_Tick(object sender, EventArgs e)
{
prb_splash.Increment(1);
if (prb_splash.Value == 100)
tmr_splash.Stop();
if (prb_splash.Value == 100)
this.Hide();
if (prb_splash.Value == 100 & (!txt_number.Text.Contains("10")))
{
frm_Artemis_admin aa = new frm_Artemis_admin();
aa.ShowDialog();
}
else
if (prb_splash.Value == 100 & (!txt_number.Text.Contains("09")))
{
frm_Employees_edit aa = new frm_Employees_edit();
aa.ShowDialog();
}
The application runs but even though I have changed the access rights to 9 to test it its still going to the admin menu?
If anyone can help that would be great.
Many Thanks :)
|
|
|
|
|
This is going to be dependent on data to a large degree - and we don't have any access to that.
So, it's going to be up to you.
Fortunately, you have a tool available to you which will help you find out what is going on: the debugger. If you don't know how to use it then a quick Google for "Visual Studio debugger" should give you the info you need.
Put a breakpoint on the first line in the function, and run your code through the debugger. Then look at your code, and at your data and work out what should happen manually. Then single step each line checking that what you expected to happen is exactly what did. When it isn't, that's when you have a problem, and you can back-track (or run it again and look more closely) to find out why.
Sorry, but we can't do that for you - time for you to learn a new (and very, very useful) skill: debugging!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
"9" is not the same as "09" when searching a text string.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
This is way too simplistic, you need to build up a framework for managing your security.
Your users credentials and rights (0-9) need to be stored in a class that all your forms can access.
When you instantiate a form you need to be able to check that class and apply the restrictions to the form as it is constructed (in WPF by binding the enable/visible values).
Instead of 10 levels the standard is to use Roles where a user may have multiple roles.
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|