This message was edited by pingpong at 2003-10-3 10:16:3
:
1. I am using a RichTextBox in an application so that I can change the colour of text and use several other features, however, I do not want the user to be able to paste anything other than text into the control. I wrote some code so that when the user clicked on the 'Edit' menu that contained the Paste MenuItem it would check to see if the clipboard only contained text or not and disable the Paste MenuItem if it didn't. The MenuItem had the Shortcut.CtrlV shortcut associated with it however, when the MenuItem was disabled the RichTextBox went back to it's old Ctrl+V behaviour and the user is able to paste whatever they want into the control.
: Is it possible to make the RichTextBox only accept text when the user wants to paste?. I was thinking that perhaps I could make a new class that inherits from the RichTextBox and overides the Paste routine, however, I am not quite sure how to do this(if it is even possible).
: I would be grateful if someone could help me with this problem.
:
Subclass the rich edit control. In its wndproc, listen to ctrl-v (and shift-insert), then either pass them to the base or ignore them:
class MyRichTextBox : RichTextBox
{
// edit. Forgot about this GetKeyState
[DllImport("User32")]
private static extern short GetKeyState(int vk);
// GetKeyState to check if CTRL or SHIFT is down at any time.
// you can probably get away with using this API and instead
// define 2 booleans in your class, bool shiftIsDown and
// bool controlIsDown. Set em up as false by default.
// Then in WndProc, also check for WM_KEYDOWN/WM_KEYUP for VK_SHIT
// and VK_CONTROL, set the booleans accordingly, then when a
// WM_KEYDOWN/VK_Z comes along, you only to check it like this:
// if(m.WParam.ToInt32() == VK_Z && controlIsDown) { ... }
protected override void WndProc(ref Message m)
{
const int WM_KEYDOWN = 0x0100;
const int VK_SHIFT = 0x10;
const int VK_CONTROL = 0x11;
const int VK_V = 0x56;
const int VK_INSERT = 0x2D;
if(m.Msg == WM_KEYDOWN)
{
// need to check CTRL-V and SHIFT-INSERT
if((m.WParam.ToInt32() == VK_V && (GetKeyState(VK_CONTROL) & 0x8000) == 0x8000) ||
(m.WParam.ToInt32() == VK_INSERT && (GetKeyState(VK_SHIFT) & 0x8000) == 0x8000))
{
// paste!
if(IsClipboardFormatNotText())
return; // dont call the base, copy operation is ignored.
}
base.WndProc(ref m);
}
You need to write that IsClipboardFormatNotText method yourself. Should be easy.
:
2. Is it possible to create a class that overrides a method from another class, but is still able to call the original method from within the new method?
Dont follow you, you mean the class is derived from the class with the method? then yes, use the "base" keyword:
class Base
{
public virtual void SomeFunc() {};
}
class Derived : Base
{
public override void SomeFunc()
{
// do work...
// call base
base.SomeFunc();
// do more work...
}
}
And it doesnt have to be virtual (if you dont want it to). In this case, replace override in Derived with "new".
:
:
3. While trying to perform some file I/O with the above RichTextBox I encountered several problems.
: First I decided to use the RichTextBox.SaveFile() method however I stopped that because I could not change the text encoding and it did not throw any exceptions so I could not tell the user whether the disk wall full or if another process was using the file.
: I then decided that I would use the StreamWriter class due to the fact that I can easily pick any encoding and because it throws exceptions when a problem is encountered.
: However the StreamWriter in my program does not seem to 'give up' the file that it uses and if I try to access the same file twice with a StreamWriter I get an error stating that the file is already being used by another process even though I had already finished with it. I have a feeling that the problem lies in the way that I have structured my code.
: Do I actually need to call the StreamWriter.Close() method when I am finished with the stream becuase when it says that the file is already in use and I try to close the stream in the finally{} section it throws another exception stating that the disk is full. No matter what I do I cannot make the StreamWriter 'give up' the file so that I can use it again. Here is the source code that I am currently using.
:
:
: private void SaveAs(object sender, EventArgs e)
: {
: SaveFileDialog dlgSaveAs = new SaveFileDialog();
: dlgSaveAs.Filter = "Text File (*.txt)|*.txt";
:
: if(dlgSaveAs.ShowDialog() == DialogResult.OK)
: {
: StreamWriter stream = null;
:
: try
: {
: stream = new StreamWriter(dlgSaveAs.FileName,
: false, Encoding.UTF8);
: stream.Write(this.Controls[0].Text);
: }
: catch(IOException ioe)
: {
: MessageBox.Show(ioe.Message, "RaiEdit");
: }
: finally
: {
: //does this try block need to be here?
: try
: {
: if(stream != null)
: {
: stream.Close();
: }
: }
: catch(IOException)
: {
: }
: }
: }
:
: return;
: }
:
:
: Should I not be using a StreamWriter or am I just using it incorrectly. Can somebody help me with this problem?
Your code looks right. You are closing the stream when you are done. If you dont, it causes that "used by another process" exception.
Try adding a stream.Flush() after your last write. Dont know what happens if the buffer gets fulled.
And your code would look more compact if you use "using" instead of that double try/catch you have:
try
{
using(stream = new StreamWriter(dlgSaveAs.FileName, false, Encoding.UTF8))
{
stream.Write(this.myRichTextBox1.Text);
stream.Flush();
}
}
catch(IOException ioe)
{
MessageBox.Show(ioe.Message, "RaiEdit");
}
:
:
4. After programming with the Win32 API and using Notepad on winXP I have a desire to add a combobox to a SaveFileDialog so that the user can choose the encoding of the text that is saved. I am not sure how I would go about doing this, I was thinking that perhaps I could create a new class that inherits from the SaveFileDialog and in the constructor it create an extra combobox and makes the form large. Is it possible to do this or is there a better solution (hopefuly I won't have to delve back into the Win32 API like with the 'FindText' dialog). I hope that someone can help me with this problem.
No you cannot inherit from SaveFileDialog, its defiend as sealed.
In Win32, the OPENFILENAME structure supports a hook procedure. That's what people use to add their own controls, change the behavor, intercept stuff, etc for a file open/save common dialog.
The .NET version has a HookProc that is supposed to do that, great yes? No! They defined it as protected!! With the class is sealed, there's no way to access it.
So, either create your own Save file dialog from scratch in .NET, or wrap the Win32 OPENFILENAME/GetSaveFileName in a .NET class. Just dont make it sealed :).
:
:
5. Is it possible to place a menu within a resource file and load it into the program. I am sick of writing 'new MenuItem(...)' 30-40 times when I create my programs MainMenu.
I have no idea. I use VS.NET to create my menus.
:
:
6. Can someone tell me what [STAThread] means and why I have to put it in front of my Main() method? When I was debugging my application it kept coming up with errors whenever I tried to copy or paste inside a RichTextBox. It told me to put [STAThread] in front of my Main() method and when I did it solved the problem.
You need to either set put STAThread or MTAThread before your main. Basically this means that your application is gonna use either single or multi threaded apartment. If you are not going to use COM controls in your app then you can safely ignore this. Just pick one (STAThread is the default and somehow makes your code run faster since nothing will be thread safe by default).
If you are using COM, then depends on the threading apartment the component is using. Set your main accordingly.
:
:
7. Although this question is not directly related to C# it is still a programming question. What is the standard mehod for assigning version numbers to programs with windows programs seem to have four version numbers: minor, major, build number etc. Are there any standard methods for assigning these values or am I free to put whatever I want in there such as 'monkeygenerator v1000.69.3.1412'.
Might as well use the .NET standard. Check out the AssemblyVersion attribute in MSDN.