滚动窗口内容以及控件中的多重撤销和重做






4.09/5 (2投票s)
2005年5月13日
2分钟阅读

35115

465
在窗口和控件中滚动内容以及多重撤销和重做。
引言
在 Pocket PC 编程中,我们总是需要在窗体上放置大量的控件。控件的数量通常非常大,以至于会超出窗体的高度,我们应该滚动窗体以便可以看到所有的信息。此外,很多时候我们需要撤销和重做之前的操作。同时,我们想要将一个字段的内容复制到另一个字段,因此 “复制、剪切、粘贴、清除、全选” 这些命令非常常用。此演示展示了一个包含上述功能的示例。
滚动窗体和输入面板阴影
我们可以使用 “VScrollBar
” 和 “Panel
” 来滚动窗口。 我们可以处理 “vScrollBar1_ValueChanged
” 事件并编写以下代码
this.pnlDetails.Top=0-this.vScrollBar.Value;
我们必须将所有需要在窗口滚动时更改位置的控件都放在面板中,这样我们只需要更改面板的位置即可。
当 InputPanel
显示或隐藏时,它将引发 “inputPanel2_EnabledChanged
” 事件,我们在此处更改 vScrollBar
的高度。
private void inputPanel2_EnabledChanged(object sender, System.EventArgs e)
{
if (inputPanel2.Enabled == true)
{
this.vScrollBar.Height=inputPanel2.VisibleDesktop.Height;
}
else
{
this.vScrollBar.Height=OriginalHeight;
}
}
多重撤销/重做
我们使用两个堆栈 (stkUndo
和 stkRedo
) 来处理撤销和重做操作,当用户撤销操作时,stkUndo
将推送一个包含窗体所有字段的快照,并且 stkRedo
将弹出一个元素。
快照结构体
它将充当要推送和弹出的元素。
struct Snapshot
{
//a struct as a form's snapshot,when undo click this struct will
//be push to redo stack pop from undo stack,and when redo click
//this struct will be push to undo stack pop from redo stack.
public string Field1;
public string Field2;
public string Field3;
public string Field4;
public string Field5;
public string Field6;
public string Field7;
public string Field8;
public string Field9;
public string Field10;
public string Field11;
public string Field12;
public int ScrollValue;
public TextBox tbfocused;
}
撤销和重做的子程序
当用户发送 “撤销” 命令时,我们应该执行以下操作
- 将
SnapShot
推送到stkUndo
并从stkRedo
弹出。 - 调用
getSnapshot
例程。
相反,当用户发送 “重做” 命令时,我们应该执行其他操作
- 将
SnapShot
推送到stkRedo
并从stkUndo
弹出。 - 调用
getSnapshot
例程。
在控件失去焦点时,我们应该确保快照是否已更改,如果已更改,我们应该调用 “setSnapshot
” 例程并将其推送到 stkUndo
。
private void setSnapshot(ref Snapshot sp)
{
//write value to the snapshot from the form's control which
//hold the undo or redo operation
sp.Field1=this.textBox1.Text;
sp.Field2=this.textBox2.Text;
sp.Field3=this.textBox3.Text;
sp.Field4=this.textBox4.Text;
sp.Field5=this.textBox5.Text;
sp.Field6=this.textBox6.Text;
sp.Field7=this.textBox7.Text;
sp.Field8=this.textBox8.Text;
sp.Field9=this.textBox9.Text;
sp.Field10=this.textBox10.Text;
sp.Field11=this.textBox11.Text;
sp.Field12=this.textBox12.Text;
}
private void getSnapshot(Snapshot sp)
{
//read the value from snapshot,and update the
//control this value.
this.textBox1.Text=sp.Field1;
this.textBox2.Text=sp.Field2;
this.textBox3.Text=sp.Field3;
this.textBox4.Text=sp.Field4;
this.textBox5.Text=sp.Field5;
this.textBox6.Text=sp.Field6;
this.textBox7.Text=sp.Field7;
this.textBox8.Text=sp.Field8;
this.textBox9.Text=sp.Field9;
this.textBox10.Text=sp.Field10;
this.textBox11.Text=sp.Field11;
this.textBox12.Text=sp.Field12;
}
private bool CompareSnapshot(Snapshot sp)
{
//compare the snapshot with the form,
//when all items are equal it return true,
//else return false.
if (this.textBox1.Text!=sp.Field1)
return false;
if (this.textBox2.Text!=sp.Field2)
return false;
if (this.textBox3.Text!=sp.Field3)
return false;
if (this.textBox4.Text!=sp.Field4)
return false;
if (this.textBox5.Text!=sp.Field5)
return false;
if (this.textBox6.Text!=sp.Field6)
return false;
if (this.textBox7.Text!=sp.Field7)
return false;
if (this.textBox8.Text!=sp.Field8)
return false;
if (this.textBox9.Text!=sp.Field9)
return false;
if (this.textBox10.Text!=sp.Field10)
return false;
if (this.textBox11.Text!=sp.Field11)
return false;
if (this.textBox12.Text!=sp.Field12)
return false;
return true;
}
剪贴板
我们应该实现 “剪切、复制和粘贴” 命令,因此我们应该使用剪贴板。在 .NET Compact Framework 中,我们不能直接使用剪贴板,我们应该使用 P/Invoke。
API 声明
[DllImport("Coredll.dll")]
private static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("Coredll.dll")]
private static extern bool CloseClipboard();
[DllImport("Coredll.dll")]
private static extern bool EmptyClipboard();
[DllImport("Coredll.dll")]
private static extern bool IsClipboardFormatAvailable(uint uFormat);
[DllImport("Coredll.dll")]
private static extern IntPtr GetClipboardData(uint uFormat);
[DllImport("Coredll.dll")]
private static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
[DllImport("coredll", EntryPoint="LocalAlloc", SetLastError=true)]
private static extern IntPtr LocalAllocCE(int uFlags, int uBytes);
private static IntPtr LocalAlloc(MemoryAllocFlags uFlags, int uBytes)
{
IntPtr ptr = IntPtr.Zero;
ptr = LocalAllocCE((int)uFlags,uBytes);
return ptr;
}
private static IntPtr StringToPointer(string val)
{
if(val == null)
return IntPtr.Zero;
IntPtr retVal = LocalAlloc(MemoryAllocFlags.LPtr, (val.Length + 1) * 2);
if(retVal == IntPtr.Zero)
throw new OutOfMemoryException();
Marshal.Copy(val.ToCharArray(), 0, retVal, val.Length);
return retVal;
}
public static void SetClipboardText(string text)
{
IntPtr hClipboard = IntPtr.Zero;
IntPtr hInstance=IntPtr.Zero;
Clipboard.OpenClipboard(hInstance);
hClipboard =
Clipboard.LocalAlloc(MemoryAllocFlags.LPtr,
(int)((text.Length + 1) * Marshal.SystemDefaultCharSize));
hClipboard = Clipboard.StringToPointer(text);
Clipboard.EmptyClipboard();
Clipboard.SetClipboardData((uint)ClipboardFormats.UnicodeText, hClipboard) ;
Clipboard.CloseClipboard();
}
public static string GetClipboardText()
{
IntPtr hInstance=IntPtr.Zero;
Clipboard.OpenClipboard(hInstance);
IntPtr buffer = Clipboard.GetClipboardData((uint)ClipboardFormats.UnicodeText);
string text = System.Runtime.InteropServices.Marshal.PtrToStringUni(buffer);
Clipboard.CloseClipboard();
return text;
}
public static bool IsClipboardTextAvailable()
{
return IsClipboardFormatAvailable((uint)ClipboardFormats.UnicodeText);
}
注意
在 .NET Compact Framework 中,ContextMenu
中存在一个已知的错误。“Menu.Add
” 应该在 “menuItem4.Text = "-";
” 之后,因此在程序中我们应该更改 “InitializeComponent
”
//
// menupUndo
//
this.menupUndo.Text = "Undo";
this.menupUndo.Click += new System.EventHandler(this.menuUndo_Click);
//
// menupRedo
//
this.menupRedo.Text = "Redo";
this.menupRedo.Click += new System.EventHandler(this.menuRedo_Click);
//
// menuItem1
//
this.menuItem1.Text = "-";
//
// menupCut
//
this.menupCut.Text = "Cut";
this.menupCut.Click += new System.EventHandler(this.menuCut_Click);
//
// menupCopy
//
this.menupCopy.Text = "Copy";
this.menupCopy.Click += new System.EventHandler(this.menuCopy_Click);
//
// menupPaste
//
this.menupPaste.Text = "Paste";
this.menupPaste.Click += new System.EventHandler(this.menuPaste_Click);
//
// menupClear
//
this.menupClear.Text = "Clear";
this.menupClear.Click += new System.EventHandler(this.menuClear_Click);
//
// menupSelectAll
//
this.menupSelectAll.Text = "Select All";
this.menupSelectAll.Click += new System.EventHandler(this.menuSelectAll_Click);
//
// contextMenu1
//
this.contextMenu1.MenuItems.Add(this.menupUndo);
this.contextMenu1.MenuItems.Add(this.menupRedo);
this.contextMenu1.MenuItems.Add(this.menuItem1);
this.contextMenu1.MenuItems.Add(this.menupCut);
this.contextMenu1.MenuItems.Add(this.menupCopy);
this.contextMenu1.MenuItems.Add(this.menupPaste);
this.contextMenu1.MenuItems.Add(this.menupClear);
this.contextMenu1.MenuItems.Add(this.menupSelectAll);
this.contextMenu1.Popup += new System.EventHandler(this.contextMenu1_Popup);