|
Mr. VB.NET wrote: That is the book I just purchased last week. Good so we're on the same track.
You'll enjoy it!
It's one of those rare techie books that you can read more-or-less cover to cover.
Kevin
|
|
|
|
|
|
I have a deployment project, with an Installer class to do my custom actions. In it's Install() override I show a form.
My problem is I cannot seem to make my form change it's localization value and be displayed in french. Here is basicly what I want to do in my dialog:
public Form1()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-CA");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr-CA");
InitializeComponent();
}
Why won't this display Form1 in french? If I call this routine from any other class but my Installer class it works fine.
Even if I run my deployment project in french, my Form1 will STILL not flip to french.
I know I need a seperate deployment project for both languages, but was hoping to use the same Installer Lib for both languages and just flip it's forms' culture settings....
Any insight on this would be helpful. Thanks!
-- modified at 11:32 Wednesday 14th June, 2006
|
|
|
|
|
I'm trying to create (using VC# 2005 Express and .NET2) a simple application that monitors the rate that bytes are received by a serial port. I've written a class that opens the serial port, counts the incoming bytes, and every second updates a property called "Rate" which is the number of bytes received in the last second.
Here's the class:
class PortMonitor : INotifyPropertyChanged<br />
{<br />
public event PropertyChangedEventHandler PropertyChanged;<br />
<br />
private SerialPort port;<br />
private UInt64 count;<br />
private UInt64 rate;<br />
private Thread thread;<br />
<br />
public PortMonitor ()<br />
{<br />
count = 0;<br />
rate = 0;<br />
<br />
port = new SerialPort("COM9",38400);<br />
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);<br />
port.Open();<br />
<br />
thread = new Thread(new ThreadStart(Run));<br />
thread.Start();<br />
}<br />
<br />
public UInt64 Rate<br />
{<br />
get { return rate; }<br />
}<br />
<br />
private void Run ()<br />
{<br />
while(port.IsOpen)<br />
{<br />
count = 0;<br />
Thread.Sleep(1000);<br />
rate = count;<br />
NotifyPropertyChanged("Rate");<br />
}<br />
}<br />
<br />
private void port_DataReceived (object sender,SerialDataReceivedEventArgs e)<br />
{<br />
count+=Convert.ToUInt64(port.BytesToRead);<br />
port.DiscardInBuffer();<br />
}<br />
<br />
private void NotifyPropertyChanged (string property)<br />
{<br />
if(PropertyChanged != null)<br />
PropertyChanged(this,new PropertyChangedEventArgs(property));<br />
}<br />
}
At the user interface end of things I've got a form with a label on it. I want to bind the text of the label to the rate property of my monitoring object. I see that the recomendation for .NET2 is to use a BindingSource inbetween the label and the monitor.
Here's the UI:
PortMonitor monitor;<br />
BindingSource source;<br />
<br />
public Form1 ()<br />
{<br />
InitializeComponent();<br />
<br />
monitor = new PortMonitor();<br />
source = new BindingSource();<br />
source.DataSource = monitor;<br />
<br />
label1.DataBindings.Add("Text",source,"Rate");<br />
}
But this throws an InvalidOperationException as soon as the monitor class tries to notify the BindingSource that the Rate property has changed. I guess this is a variation of the "one thread can't call methods on the UI thread" exception.
What do I need to do to get this working?
Iain
|
|
|
|
|
Use a delegate.
Start the application off with the main form that just has the controls you want updated. Spin a thread off to do the work, in that thread there will be a delegate which will "notify" the main form's method of choice to process the data. Note you must set up a delegate type in the main form which the thread adheres to.
Note when you communicate with that control you must check for invoke.required and take appropriate action, which amounts to recalling the same routine via the invoke method. This ensures inter-thread communication and allows for the control to "always" receive and display the update.
When I first started learning about delegates I found them to be more difficult than the java modes of interprocess communications, however, once I cracked the surface open I found them to be rather easy. There are other ways to do this such as using static variables, but the deletegate is the best way hands down.
|
|
|
|
|
Just to clarrify: I should write my own event handling code in the form, which listens to PropertyChanged events from the monitor object, and then calls methods (via Invoke) on the label to update the text?
Something like...
public partial class Form1 : Form<br />
{<br />
PortMonitor monitor;<br />
<br />
public Form1 ()<br />
{<br />
InitializeComponent();<br />
<br />
monitor = new PortMonitor();<br />
monitor.PropertyChanged += new PropertyChangedEventHandler(monitor_PropertyChanged);<br />
}<br />
<br />
public void monitor_PropertyChanged (object sender,PropertyChangedEventArgs e)<br />
{<br />
if(InvokeRequired)<br />
{<br />
BeginInvoke(new PropertyChangedEventHandler(monitor_PropertyChanged), sender, e);<br />
}<br />
else<br />
{<br />
label1.Text=monitor.Rate;<br />
}<br />
}<br />
}
This seems like a knarly way of pushing data out to the UI, as it bypasses the BindingSource and negates the usefullness of the DataBindings in the Label. Isn't the BindingSource meant to be in the middle there handling all this inter-thread malarky?
I really like the simplicity of a one liner like:
progressBar1.DataBindings.Add("Value",myBindingSource,"FileTransferProgress");
Isn't there some way I can handle the invokation stuff in the NotifyPropertyChanged method of my monitoring class? Something like:
private void NotifyPropertyChanged (string property)<br />
{<br />
if(PropertyChanged != null)<br />
{<br />
Control target = (Control)PropertyChanged.Target;<br />
if(target.InvokeRequired)<br />
{<br />
target.BeginInvoke(new PropertyChangedEventHandler(PropertyChanged),this,new PropertyChangedEventArgs(property));<br />
}<br />
else<br />
{<br />
PropertyChanged(this,new PropertyChangedEventArgs(property));<br />
}<br />
}<br />
}
Would that, or something similar, work?
Iain
|
|
|
|
|
Start of with a delegate definition in the main form (A).
ex. public delegate void cmdFinished(string str);
Class (A) Spins off a thread passing the delgate which points to a method in the main form to send the update to.
The other class (B) which should be a thread has this:
ex. public Form1.cmdFinished cmdFinished;
Class (B) does has a constructor which passes in the deletegate. You might say it is encapsulated.
ex. public classConstrustor(Form1.cmdFinished incmdfinished, string inusername, string inpassword, string incomputername, string indomain)
Class (B) does it's stuff and then issues a callback
ex. cmdFinished("MSG:Attempting to Connect to remote location...");
This call will call the function to process this data in the main form.
The main form must check whether or not invoke is required on the control (a form restriction).
private void updateDataGridView1(string[] instr)<br />
{<br />
<br />
if (dataGridView1.InvokeRequired)<br />
{ <br />
Form1.updatedataGridView1 view1 = new Form1.updatedataGridView1(this.updateDataGridView1);<br />
base.Invoke(view1, new object[] { instr });<br />
}<br />
else (Process the string array, updating the control etc.)<br />
<br />
|
|
|
|
|
iswoolley wrote: But this throws an InvalidOperationException as soon as the monitor class tries to notify the BindingSource that the Rate property has changed. I guess this is a variation of the "one thread can't call methods on the UI thread" exception.
Try using the AsyncOperation and AsyncOperationManager classes. Raise your NotifyPropertyChanged event by passing a delegate to the AsyncOperation object's Post method. The AsyncOperation will take care of marshaling it to the Form's thread provided that the AsyncOperation object was created on the same thread as the Form.
See my article[^] on using the SynchronizingContext , AsyncOperation and AsyncOperationManager classes.
Hope this helps.
|
|
|
|
|
Okay, I think with all your help, I've solved this one (or at least got it working at the moment). I decided to use the SynchronizationContext object, so modified my constructor to take one:
public PortMonitor (SynchronizationContext c)<br />
{<br />
if (c != null)<br />
context = c;<br />
else<br />
context = new SynchronizationContext();<br />
<br />
count = 0;<br />
rate = 0;<br />
<br />
port = new SerialPort("COM9",38400);<br />
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);<br />
port.Open();<br />
<br />
thread = new Thread(new ThreadStart(Run));<br />
thread.Start();<br />
}
Then when I want to raise an event I use:
private void NotifyPropertyChanged (string property)<br />
{<br />
if(PropertyChanged != null)<br />
{<br />
context.Post(new SendOrPostCallback(delegate(object state)<br />
{<br />
PropertyChanged(this,new PropertyChangedEventArgs(property));<br />
}),null);<br />
}<br />
}
And finally, in the UI when I create the PortMonitor object I pass into it a WindowsFormsSynchronizationContext:
public Form1 ()<br />
{<br />
InitializeComponent();<br />
<br />
monitor = new PortMonitor(WindowsFormsSynchronizationContext.Current);<br />
source = new BindingSource();<br />
source.DataSource = monitor;<br />
<br />
label1.DataBindings.Add("Text",source,"Rate");<br />
}
So hopefully now, all the events are raised in the appropriate context, but also non-UI threads can listen to events as well.
Thanks for your help.
Iain
|
|
|
|
|
Hi,
Can anybody tell which datatype of c# viz Float, double , decimal will be appropriate for calculating percentage (100%)
kumar
|
|
|
|
|
float is enough. It should be precise enough for most cases.
modified 12-Sep-18 21:01pm.
|
|
|
|
|
The float data type
float data type is the first of 3 data types that can store floating point numbers and actually this is the smallest of the 3 types. float variables store floating point numbers from 1.5 times 10 to the 45 th (±1.5 × 10-45 ) to 3.4 times 10 to the 38 th (±3.4 × 1038 ) in 32 bit. And this type has a precision to 7 numbers.
The double data type
double data type variables can store floating point numbers from 5 times 10 to the 324 th (±5.0 × 10-324 ) to 1.7 times 10 the 308 th (±1.7 × 10308 ) in 64-bit. And this type has a precision to 15-16 numbers.
The decimal data type
decimal data type variables can store 1 times 10 to the 28th 1.0 × 10-28 and 7.9 times 10 to the 28 th 7.9 × 1028 in 128 bit. If you think about this type you will note that it has a greater precision and a smaller range and that’s we exactly needs for financial calculations also note that decimal data type has a Precision of 28-29 significant digits.
|
|
|
|
|
One more quick thing on Decimal datatypes.
Although the C# language considers this a primitive datatype, the CLR does NOT. From a practical standpoint, this means that manipulating Decimal datatypes is slower than working with the other datatypes. Also, the checked and unchecked operators, and compiler switches have no effect on Decimal datatypes, which ALSO means that Decimal datatypes ALWAYS throw an OverflowException if the operation can't be done safely.
I was surprised by this, I am pretty sure I read it in Jeff Richter's book, and played with it some and he's right. I HATE it when that happens!
|
|
|
|
|
Hello!
I got a problem with the lines below. I don´t know how to use VirtualAllocEx in C# , because I must allocate a certain space for a struct and an item (both are pointers).
I´d like to know if anyone got any idea how I can do the same thing in c#.
This code is from: http://www.codeproject.com/threads/int64_memsteal.asp?df=100&forumid=29535&exp=0&select=727974&mpp=50#xx727974xx[^]
"Stealing Program's Memory"
LVITEM lvi, *_lvi;
char item[512], subitem[512];
char *_item;
HANDLE process;
_lvi=(LVITEM*)VirtualAllocEx(process, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
_item=(char*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT, PAGE_READWRITE);
Thank you!!
|
|
|
|
|
If you are trying to allocate memory in an unmanaged process, you can probably use PInvoke[^] to make it work. If the memory you need to allocate will be in another managed process, then those unmanaged APIs will not work. What you would need to do in that situation is, probably, use .NET remoting to communicate between the two managed processes.
Josh
|
|
|
|
|
Hi Josh, thanks for the reply!
What I´m trying to do is read a TreeView(Folder Browser Dialog) from another program.
By reading each item´s text I can select a especific Folder.
I noticed that usual codes did not catch anything from outside my program. For instance:
SubString Text = new SubString(255);
tvItem.pszText = Text;
SendMessage(TreeHandle, TVM_GETITEM, 0, ref tvItem);
This code works perfectly if the treeview is in your application, but SendMessage returns only false if the treeview is in another application(process).
Thank you
|
|
|
|
|
I have seen tabstrip Control Visual Studio Style 2005.
Can anyone tell me how i can get tabstripControl with tabs on downside.
|
|
|
|
|
SravanKrishna wrote: Can anyone tell me how i can get tabstripControl with tabs on downside
tabControl1.Alignment = TabAlignment.Bottom;
_____________________________
Success is not something to wait for, its something to work for.
|
|
|
|
|
|
Hi,
Can any body tell me please how can i use multi column dropdown box against a column in datagrid view. It means when i click on the button displayed on the right side of the column, then that multi column drop down be displayed.
Waiting for reply....
Regrads,
Shahid
Ever Respect the elders
|
|
|
|
|
Can someone point me in the right direction? I would like to have a button on a ToolStrip that drops down a single ToolStripMenuItem that has a TracBar instead of a standard text link. Is this possible or would this need to be done completely from scratch.
|
|
|
|
|
Hi All !
I want to get the value of the last Record (ID)From a table , for example if the Last ID=35 , how i can get the value of it from a table ?
thanks a lot .
s_mostafa_h
|
|
|
|
|
try this :
sqlDataAdapter1 = new SqlDataAdapter("select max(IdColumnName) from TableName", sqlConnection1);
DataSet ds = new DataSet();
sqlDataAdapter1.Fill(ds);
int MaxID = Int32.Parse(ds.Tables[0].Rows[0][0].ToString());
Tamimi - Code
|
|
|
|
|
I assume you're doing this because you want to then use that ID to create associated records in other tables?
If so, then write a stored proc that does the insert and then returns the ID of the record added using either @@IDENTITY or SCOPE_IDENTITY()...
In not (or not using SQL Server), then nevermind.
|
|
|
|
|
If you have added a record and want to find out the id that the record recieved:
Access: select @@identity
MySQL: select last_insert_id()
MSSQL: select scope_identity()
Getting the largest id after adding a record is a very very bad method to get it's id. It works flawlessly when you are testing the system by yourself, but in a multi user system you will get the wrong id sometimes as another user added a record at the same time. The more users, the more frequent the errors will be.
---
b { font-weight: normal; }
|
|
|
|