|
In C#, you can only use the string type.
See Calling a Delphi DLL from a C# .NET application - Stack Overflow[^] and be sure to read the entire thing. There are links you're going to have to follow and read.
Depending on what your Delphi code is doing, you may need to rewrite it to support being called from an external caller.
|
|
|
|
|
Quote: I think the issue is about the type of parameters
Why? the error message was pretty clear, it said Quote: 'Unable to load DLL test.dll
which may not be entirely accurate, it would better be "unable to load DLL test.dll or some of its dependencies" (that is other DLL's your test.dll might be relying on).
Don't worry about your parameter types right now, first make sure you have all the required DLL files are in a location where the .NET executable can find them. Maybe start looking here[^].
BTW: your DLL files will need to have the same 32-bit/64-bit choice your .NET code has.
FYI: AFAIK there also is Delphi.NET which would mean you could recompile your Delphi code (assumed available) and use its output as a regular .NET DLL, without any P/Invoke stuff.
|
|
|
|
|
Tested example[^]
Should work.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
I am planning a different approach - have written half of the code, but it is not ready for testing yet. In my case, it is one subsystem written in C++, others in C#.
Rather than messing around with P/invoke and all sorts of parameter transfer, synchronization and whathaveyou, I run it as two processes. The two subsystems have limited, and structurally very simple, data interchange. I find it far easier to exchange those data through a named pipe. The data format is application specific, but as these two subsystems belong to the same application, it is like an internal API with no more need to adhere to a standard than any other internal interface.
I like strong isolation between subsystems and modules. It gives greater freedom within each subsystem/module, and it keeps the architecture clean. And it makes the system flexible: If I later want to replace that C++ subsystem with one written in Cobol, say , I could do so without any effect on the C# part. Well, if I could access that Cobol code through the same P/invoke interface, it might be similar, but now I don't have to worry about that at all.
I am considering the same approach even when the subsystems are all in C#: Threads are fair enough, but do not provide the same isolation as separate processes. When different tasks really are independent (such as one monitoring external equipent/events, the other one interacting with the user; the only common data are the summary reports from the monitor process), they might as well be implemented and run as completely separate entities. Two simple entities are better than one complex.
|
|
|
|
|
I'm storing a file in a mysql table in a Longblob.
Now i would like to create a sha256 as a "footprint" for this file, so i can verify if the file exists already in my database.
As a test i've created this code
private byte[] ObjectToByteArray(Object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
private void button5_Click(object sender, EventArgs e)
{
byte[] bookData = null;
byte[] bookDataSha = null;
book bog = getBookById("6");
bog.GetEbookHash(string.Format(@"H:\calibre\{0}\", bog.path), 6);
using (var db = new MySqlConnection(@"server = xxxxxxx"))
{
MySql.Data.MySqlClient.MySqlDataReader myData;
db.Open();
MySqlCommand comm = db.CreateCommand();
comm.CommandText = "select content from bookContent where id='6' and type='epub'";
myData = comm.ExecuteReader();
while (myData.Read())
{
bookData = this.ObjectToByteArray(myData["content"]);
bookDataSha = Sha256.ComputeHash(bookData);
}
db.Close();
}
if (bog.EpubHash == bookDataSha)
{
MessageBox.Show("success");
}
MessageBox.Show(bog.getEbookHashStr(bog.EpubHash)+" - "+bog.getEbookHashStr(bookDataSha));
}
My problem is that the 2 sha256's isnt equal.
I've found this Generate a SHA-256 encrypted hash[^]
and when i upload the file i test on, it creates the same sha256 as my code for the file does.
But when i read the data from the longblob and creates a sha256 it is different.
The strange part, is that if i use my website to download the same longblob and saves it as a file... FC cant find any diffeneces.
What do i do wrong ?
Thanks in advance
Yours
Wilco
|
|
|
|
|
Hi,
I'm not familiar with the MySql connector, and I tend not to store files in databases (it does not make much sense to me, it only inflates the DB size). However I noted what follows:
at the bottom of your code there is a while loop, wherein you call Sha256.ComputeHash .
That piece of code looks very suspicious: what remains is just the SHA256 of the last loop iteration, so either you only have one iteration (and the while should be an if), or your logic is wrong (you should collect all the data and then calculate SHA256 on the whole thing).
You could try with a small file, say less than 1KB. Or you could track the while loop behavior, either by adding an output statement, or by using a debugger...
|
|
|
|
|
Hi Luc
You are abosolute right. This example was copied from some where else i my code...
I've changed it to a IF, but change in the hash value.
I thought i would run this by the community to see if anybody have had a problem like this before....
I'll just lay it to side, and later look into the byte array differences... there has to be some, since the sha256 values are different..
Thanks for your response
Yours
Wilco
|
|
|
|
|
The usual method for this is to store the file and the hash in the database, then you only need to compare the hash rather than recompute each time.
The better method is to store the file in the file system and only store the filename and path with the hash in the database.
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
Hi Mycroft
That is the plan, when i come there... but first step is to be able to compare the 2 hash values.
If i upload a file to the database with a hash, it's ok, but for database maintenance purpose i would like to be able to recalculate the value "on the fly", with out having to save all 3000+ files one at a time to recalculate hash value.
And i just can wrap my brain around the difference... basicly its an array of bytes - both the longblob and the filestream.
As for saving the file to database... this a give premis for this task. I have very limited space in the OS environment, but unlimited space in the database.
Yours
Wilco
|
|
|
|
|
Check the length of the blob that you are saving, vs. the length of the one you are reading. If you suspect the sha256-hash, then replace it with another hashing algo.
As for "not storing files in a db" in support of exposing the filesystem; I would advise against it. Modern databases are fast enough to work as a file-system, and are used as such.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
Hello, I'm new to the forum and new to C# and programming in general so any help with this is appreciated.
I have two arrays of strings. sTime holds the string TimePosition and the second holds a text string.
I have an Audio file playing using mediaPlayer.
I am trying to sample the mediaPlayer position to trigger an event when it reached a desired time.
There will be multiple sTimes that will be at random positions throughout the Audio File.
Each time the mediaPlayer.position compares to the sTime it will display the text string associated with the sTime.
Think Teleprompter or Karaoke Player.
I think mediaPlayer is not robust enough the capture every millisecond to compare, so I miss the event.
I could try comparing to see if position is greater or equal to 10.000 but I'll miss 10.678 but this code never triggers the MessageBox.
It also would be more efficient if I knew how to capture the mediaPlayer.position directly and compare it to a variable without all the wasted conversion time. But I don't.
Thanks for any help.
lblLength.Content = mediaPlayer.NaturalDuration.TimeSpan.TotalSeconds;
mediaPlayer.Play();
When the mediaPlayer.position
string Position = String.Format("{0:r}", mediaPlayer.Position.TotalSeconds);
void timer_Tick(object sender, EventArgs e)
{
if (mediaPlayer.Source != null)
{
lblStatus.Content = mediaPlayer.Position.TotalSeconds;
var ucontent = lblStatus.Content;
string eTime = ucontent.ToString();
string tTime;
tTime = "10.000";
if (String.Equals(eTime, tTime))
{
MessageBox.Show("position = " , eTime);
}
}
else
lblStatus.Content = "No file selected...";
}
|
|
|
|
|
You need to dig deeper into the Media Player or "Media Element" class. There's a "Media Timeline" class (and "Storyboard" class) that seem to have some bearing on what you're doing.
You may have to "chunk" your way through the media source with multiple time lines of starting position and duration (if there's no appropriate events to capture or you're not into WPF).
How to: Control a MediaElement by Using a Storyboard - WPF | Microsoft Docs
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
|
|
|
|
|
I read this source code then I built my form to draw a rectangle and make it able to resize/ move it, some how, the logic I follow is wrong, because the mouse when it moves up the small rectangles then the mouse cursor should change, it is some times change and others not, even in the console I can see the mouse cursor should apply. Also if I try to resize it then a new rectangle drawn. My form source code:
public partial class Form2 : Form
{
private enum ResizableRect
{
RightUp,
RightMiddle,
RightBottom,
LeftUp,
LeftMiddle,
LeftBottom,
UpMiddle,
BottomMiddle,
None
};
private int m_resizableRectSize = 6;
private ResizableRect m_resizableRectNodeSelected = ResizableRect.None;
Rectangle rect;
Point StartXY;
Point EndXY;
int x = 0;
int y = 0;
bool m_isMouseDown = false;
bool m_movingRect = false;
public Form2()
{
InitializeComponent();
this.DoubleBuffered = true;
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
{
Graphics gObj = panel1.CreateGraphics();
Pen rectPen = new Pen(Color.Red, 2);
rectPen.DashStyle = DashStyle.Dash;
x = Math.Min(StartXY.X, EndXY.X);
y = Math.Min(StartXY.Y, EndXY.Y);
int height = Math.Abs(StartXY.X - EndXY.X);
int width = Math.Abs(StartXY.Y - EndXY.Y);
rect = new Rectangle(x, y, height, width);
gObj.DrawRectangle(rectPen, rect);
foreach (ResizableRect pos in Enum.GetValues(typeof(ResizableRect)))
{
gObj.DrawRectangle(new Pen(Color.Red), GetResizableRectNode(pos));
}
}
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
m_resizableRectNodeSelected = GetNodeSelectable(e.Location);
StartXY = e.Location;
m_isMouseDown = true;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
this.Cursor = GetResizableRectCursorType(GetNodeSelectable(e.Location));
if (rect.Contains(new Point(e.X, e.Y)))
{
this.Cursor = Cursors.SizeAll;
}
else
{
switch (m_resizableRectNodeSelected)
{
case ResizableRect.LeftUp:
rect.X += e.X - EndXY.X;
rect.Width -= e.X - EndXY.X;
rect.Y += e.Y - EndXY.Y;
rect.Height -= e.Y - EndXY.Y;
break;
case ResizableRect.LeftMiddle:
rect.X += e.X - EndXY.X;
rect.Width -= e.X - EndXY.X;
break;
case ResizableRect.LeftBottom:
rect.Width -= e.X - EndXY.X;
rect.X += e.X - EndXY.X;
rect.Height += e.Y - EndXY.Y;
break;
case ResizableRect.BottomMiddle:
rect.Height += e.Y - EndXY.Y;
break;
case ResizableRect.RightUp:
rect.Width += e.X - EndXY.X;
rect.Y += e.Y - EndXY.Y;
rect.Height -= e.Y - EndXY.Y;
break;
case ResizableRect.RightBottom:
rect.Width += e.X - EndXY.X;
rect.Height += e.Y - EndXY.Y;
break;
case ResizableRect.RightMiddle:
rect.Width += e.X - EndXY.X;
break;
case ResizableRect.UpMiddle:
rect.Y += e.Y - EndXY.Y;
rect.Height -= e.Y - EndXY.Y;
break;
default:
if (m_isMouseDown)
{
rect.X = rect.X + e.X - EndXY.X;
rect.Y = rect.Y + e.Y - EndXY.Y;
}
break;
}
}
if (m_isMouseDown)
{
EndXY = e.Location;
panel1.Invalidate();
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
EndXY = e.Location;
m_isMouseDown = false;
m_movingRect = false;
Invalidate();
}
private Rectangle DrawResizableRectNode(int x, int y)
{
return new Rectangle(x - m_resizableRectSize / 2, y - m_resizableRectSize / 2, m_resizableRectSize, m_resizableRectSize);
}
private ResizableRect GetNodeSelectable(Point p)
{
foreach (ResizableRect r in Enum.GetValues(typeof(ResizableRect)))
{
if (GetResizableRectNode(r).Contains(p))
{
Console.WriteLine("GetNodeSelectable: " + r.ToString());
return r;
}
}
return ResizableRect.None;
}
private Rectangle GetResizableRectNode(ResizableRect p)
{
switch (p)
{
case ResizableRect.LeftUp:
return DrawResizableRectNode(rect.X, rect.Y);
case ResizableRect.LeftMiddle:
return DrawResizableRectNode(rect.X, rect.Y + rect.Height / 2);
case ResizableRect.LeftBottom:
return DrawResizableRectNode(rect.X, rect.Y + rect.Height);
case ResizableRect.BottomMiddle:
return DrawResizableRectNode(rect.X + rect.Width / 2, rect.Y + rect.Height);
case ResizableRect.RightUp:
return DrawResizableRectNode(rect.X + rect.Width, rect.Y);
case ResizableRect.RightBottom:
return DrawResizableRectNode(rect.X + rect.Width, rect.Y + rect.Height);
case ResizableRect.RightMiddle:
return DrawResizableRectNode(rect.X + rect.Width, rect.Y + rect.Height / 2);
case ResizableRect.UpMiddle:
return DrawResizableRectNode(rect.X + rect.Width / 2, rect.Y);
default:
return new Rectangle();
}
}
private Cursor GetResizableRectCursorType(ResizableRect resizableRectPoint)
{
Cursor rectPositionCursor;
switch (resizableRectPoint)
{
case ResizableRect.LeftUp:
rectPositionCursor = Cursors.SizeNWSE;
break;
case ResizableRect.LeftMiddle:
rectPositionCursor = Cursors.SizeWE;
break;
case ResizableRect.LeftBottom:
rectPositionCursor = Cursors.SizeNESW;
break;
case ResizableRect.BottomMiddle:
rectPositionCursor = Cursors.SizeNS;
break;
case ResizableRect.RightUp:
rectPositionCursor = Cursors.SizeNESW;
break;
case ResizableRect.RightBottom:
rectPositionCursor = Cursors.SizeNWSE;
break;
case ResizableRect.RightMiddle:
rectPositionCursor = Cursors.SizeWE;
break;
case ResizableRect.UpMiddle:
rectPositionCursor = Cursors.SizeNS;
break;
default:
rectPositionCursor = Cursors.Default;
break;
}
Console.WriteLine("GetResizableRectCursorType: " + rectPositionCursor.ToString());
return rectPositionCursor;
}
}
|
|
|
|
|
Hi,
unfortunately your code already contains a lot of details, making it hard to pinpoint what exactly is the problem. IMHO one should always work on smaller pieces and get them to run satisfactorily before adding to them.
So I will limit my reply to a number of comments, which taken together really indicate I'm not so happy with the current code:
1.
It seems you want a hovering mouse to show what would happen if the mouse were clicked in its current position; that should consist of:
- deciding which if any rectangle is hovered over;
- deciding how it is hit (i.e. in the size handles or in the body).
As size handles overlap the actual rectangle, one must be careful in what order the Contains() logic is applied. I would probably use a slightly larger rectangle and check that first, assuming a move is intended, and on a hit then check whether any of the size handles is hit (which would overrule the move).
2.
Once the mouse goes down, the decision (from #1) should be frozen, and data should be set up to initiate the actual move/resize.
3.
Back in the mouse move handler, the actual action should happen until mouse up is reached.
4.
As a consequence:
- the MouseMove handler should have two completely distinct halves, one for the decision process (mouse still up), one for the execution (mouse down); a single bool (set/cleared by MouseDown/MouseUp) would decide between the halves.
- the MouseDown handler shouldn't do much at all.
5.
If I were creating something like this, I would start from scratch, and initially keep it as simple as possible.
I would also choose variable and method names carefully, e.g. DrawResizableRectNode isn't OK as it does not draw at all.
Added later, two smaller issues I forgot to mention:
6.
There is no need to create a Graphics object explicitly; you get it for free as one of the properties of the PaintEventArgs in a Paint handler.
7.
You should keep Paint handlers as lean as possible, in particular you should create the drawing objects (Pens, Fonts, ...) you need only once, and save them in class level variables for reuse. In your case, that applies to rectPen.
And if you fail to keep them around, it is your duty to dispose of them (by calling their Dispose method or applying a using statement), in order to avoid Windows problems such as handle shortages.
Hope this helps,
modified 27-Apr-20 20:15pm.
|
|
|
|
|
Hi,
Your notes are helpful to help where to look in my code, but still I can't get it work
I started from scratch and made the first step is just to move the rectangle, my issue now is to calculate the new starting XY, but it seems resize the rectangle when mouseUp:
<pre>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))
{
if (e.X > StartXY.X)
{
EndXY.X += e.X - StartXY.X;
EndXY.Y += e.Y - StartXY.Y;
}
else
{
EndXY.X += Math.Abs(e.X - StartXY.X);
EndXY.Y += Math.Abs(e.Y - StartXY.Y);
}
StartXY = e.Location;
Console.WriteLine("pictureBox1_MouseMove");
}
if (m_mouseDown && !rect.Contains(e.Location))
{
EndXY = e.Location;
}
Invalidate();
}
Complete code:
public partial class Form1 : 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 Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics gObj = e.Graphics;
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);
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");
}
else
{
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))
{
if (e.X > StartXY.X)
{
EndXY.X += e.X - StartXY.X;
EndXY.Y += e.Y - StartXY.Y;
}
else
{
EndXY.X += Math.Abs(e.X - StartXY.X);
EndXY.Y += Math.Abs(e.Y - StartXY.Y);
}
StartXY = e.Location;
Console.WriteLine("pictureBox1_MouseMove");
}
if (m_mouseDown && !rect.Contains(e.Location))
{
EndXY = e.Location;
}
Invalidate();
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (!m_movingRect)
{
EndXY = e.Location;
}
m_mouseDown = false;
m_movingRect = false;
Invalidate();
}
}
|
|
|
|
|
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
|
|
|
|
|
|