سؤال

I want to prevent the user from moving the winform. How do you lock or freeze the winform's location? So, that no matter what they do, it can't be moved. I think, for win32 you have a frozen option for windows. When this option is set, you only see the outline of the windows being moved but the actual window is still in its original location. I am trying to do a similar thing with winform.

EDIT: Here is a procedure to capture window message for position change in win32:

//Frozen is a user-defined boolean variable
procedure TVIewFrm.WMPosChanging(var Msg: TMessage);
var
  wp:PWINDOWPOS;
begin
  if Frozen then
  begin
    wp := PWINDOWPOS(Msg.lParam);
    wp^.flags := wp^.flags or SWP_NOMOVE;
  end;
  inherited;
end;

That is a working procedure and that is what I am trying to do with the WinForm. So far you all posted a work around not really the solution I am looking.

هل كانت مفيدة؟

المحلول 5

Although some of you came close, it just didn't work for me. Your answers were more or less work around. I was looking for a straight forward solution.

I figured out my issue. Although my solution works flawlessly, it doesn't draw and drag an outline of the winform. I probably have to implement code similar to LarsTech to achieve that.

Here is my working code:

//declared within a form class under protected
method WndProc(var m:Message); override;

//and is defined as follows.
method MainForm.WndProc(var m: Message);
const WM_NCLBUTTONDOWN = 161;
const WM_SYSCOMMAND = 274;
const HTCAPTION = 2;
const SC_MOVE = 61456;
begin
    if ((m.Msg = WM_SYSCOMMAND) and (m.WParam.ToInt32 = SC_MOVE)) then
    begin
        exit;
    end;

    if ((m.Msg = WM_NCLBUTTONDOWN) and (m.WParam.ToInt32 = HTCAPTION)) then
    begin
        exit;
    end;
    inherited WndProc(var m);
end;

Thank you all for your answers.

نصائح أخرى

Try this:

Public Class UnmovableForm

    Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
        '' Remove the Move command from the system menu so the window becomes unmovable
        Call RemoveMenu(GetSystemMenu(Me.Handle, False), SC_MOVE, MF_BYCOMMAND)
        MyBase.OnHandleCreated(e)
    End Sub

    Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As IntPtr, ByVal nPosition As Integer, ByVal wFlags As Integer) As Integer
    Private Declare Function GetSystemMenu Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal bRevert As Boolean) As IntPtr
    Private Const MF_DISABLED As Integer = 2
    Private Const MF_BYCOMMAND As Integer = 0
    Private Const SC_MOVE As Integer = &HF010
End Class

Hope this solves your problem.

In the Move event of the form, just set the location back to where you want it to be.

Better answer in regards to your needs:

Private Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Integer, ByVal uParam As Integer, ByRef lpvParam As String, ByVal fuWinIni As Integer) As Integer

Private Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Integer, ByVal uParam As Integer, ByRef lpvParam As Long, ByVal fuWinIni As Integer) As Integer

Private Const SPI_GETDRAGFULLWINDOWS = 38
Private Const SPI_SETDRAGFULLWINDOWS = 37
Private Const SPIF_SENDWININICHANGE = 2

Private Sub frmMain_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Move
Dim result As Long
result = SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, 1&, vbNullString, SPIF_SENDWININICHANGE)
Me.Location = New Point(0, 0)
result = SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, 0&, vbNullString, SPIF_SENDWININICHANGE)

End Sub

Should now be able to set the Me.Location = New Point(0,0) to your initial location (grabbed at MouseDown maybe?)

You can try this in your form:

public partial class TestForm : Form {

  private const int HT_CAPTION = 0x2;
  private const int WM_NCLBUTTONDOWN = 0xA1;

  [DllImportAttribute("user32.dll")]
  public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

  public TestForm() {
    InitializeComponent();
    this.ControlBox = false;
  }

  protected override void WndProc(ref Message m) {
    if (m.Msg == Win32.WM_NCLBUTTONDOWN) {
      Form moveForm = new Form();
      moveForm.FormBorderStyle = FormBorderStyle.None;
      moveForm.StartPosition = FormStartPosition.Manual;
      moveForm.ShowInTaskbar = false;
      moveForm.TransparencyKey = Color.Lime;
      moveForm.BackColor = Color.Lime;
      moveForm.SetBounds(this.Left, this.Top, this.Width, this.Height);
      moveForm.Paint += moveForm_Paint;        
      moveForm.Show();
      SendMessage(moveForm.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
      moveForm.Paint -= moveForm_Paint;
      moveForm.Close();
    } else {
      base.WndProc(ref m);
    }
  }

  void moveForm_Paint(object sender, PaintEventArgs e) {
    using (Pen p = new Pen(Color.Gray, 7)) {
      p.Alignment = System.Drawing.Drawing2D.PenAlignment.Center;
      e.Graphics.DrawRectangle(p, ((Form)sender).ClientRectangle);
    }
  }
}

It intercepts the non-client area left mousedown button, pops a transparent form up that draws a gray rectangle around the borders, and sends a message to move the form around as-if it was the form you clicked on.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top