|
led mike wrote: Get real.
That's every bot's dilemma, isn't it?
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Damn near pulled muscle laughing at that one!
led mike
|
|
|
|
|
Do you have any advice or comments to my original question?
regards,
George
|
|
|
|
|
I do not quite understand what do you mean "Get real"? Could you say some other words please?
regards,
George
|
|
|
|
|
Whatever dude. Disagree with me all you want, you have a far better grasp of the subject than I do.
led mike
|
|
|
|
|
Hi led mike,
Could you provide some technical advice or comments please?
have a good weekend,
George
|
|
|
|
|
Hi alll,
How to scroll a listview with out scroll bar. I know
ListBox1.EnsureVisible(index) will do the job, but since i have disabled Scrollable property using
ListBox1.Scrollable = false EnsureVisible is not doing the job.
is there any other way to scroll listview with scrollable propery set to false
Regards
Vayanans
|
|
|
|
|
I don't think of any idea in c# windows application. But if you could explain your scenario a bit, perhaps i could be able to give you any suggestion.
Ahsan Ullah
Senior Software Engineer
|
|
|
|
|
hi
I dont want to use scroll bar to scroll the listview. i have two buttons for scrolling u and down
is there is any way to do so...?
Regards
Vayanans
|
|
|
|
|
you should make a user control like listview by using textboxes for example. Then put your own buttons for moving it up or down.
Ahsan Ullah
Senior Software Engineer
|
|
|
|
|
..and why not resort to setting the scrollable for a second?
bool oldVal = ListBox1.Scrollable;
ListBox1.Scrollable = true;
ListBox1.EnsureVisible(index);
ListBox1.Scrollable = oldVal;
|
|
|
|
|
Put the list box on a panel. Make the list box tall enough to display all the items at the same time. Make you buttons move the list box up and down so what ever part of the panel you want visible can be seen in the panel.
Here's a sample of what I mean using a label. Just create a new winforms app, and paste this over the form1 definition:
public partial class Form1 : Form
{
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
public Form1()
{
InitializeComponent();
this.panel1 = new System.Windows.Forms.Panel();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.panel1.Controls.Add(this.label1);
this.panel1.Location = new System.Drawing.Point(93, 12);
this.panel1.Size = new System.Drawing.Size(60, 50);
this.panel1.TabIndex = 0;
this.button1.Location = new System.Drawing.Point(12, 12);
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Up";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.scrollUp);
this.button2.Location = new System.Drawing.Point(12, 41);
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 0;
this.button2.Text = "Down";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.scrollDown);
this.label1.Location = new System.Drawing.Point(0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(60, 186);
this.label1.TabIndex = 1;
this.label1.Text = "This is a label with some text that goes on for ages and ages to " +
"demonstrate how it is possible to manually scroll a control using a panel.";
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.panel1);
this.ClientSize = new System.Drawing.Size(169, 75);
}
private void scrollUp(object sender, EventArgs e)
{
label1.Top += 10;
if (label1.Top > 0)
{
label1.Top = 0;
}
}
private void scrollDown(object sender, EventArgs e)
{
label1.Top -= 10;
if (label1.Top < panel1.Height-label1.Height)
{
label1.Top = panel1.Height - label1.Height;
}
}
}
imon
|
|
|
|
|
BeginReceive is used in my class for receiving data over TCP/IP.
When reaching the callback of BeginReceive, the class fires an event and puts the received data in the EventArgs.
I use the class in a Form that displays received data. But I can't show the data without Invoke.
Does anyone know how to fire the Event without the necessity of Invoke outside the class?
class1 (receives TCP/IP data)
{
public event EventHandlerDataReceived DataReceived;
private byte[] recPacket = new byte[32000];
private void WaitForData()
{
sockClient.BeginReceive(recPacket, 0, recPacket.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), null);
}
private void OnDataReceived(IAsyncResult asyn)
{
sockClient.EndReceive(asyn)
OnDataReceived(this, new DataReveivedEventArgs(recPacket)
}
public void OnDataReceived(object sender, DataReveivedEventArgs e)
{
if (DataReceived != null) { DataReceived(this, e); }
}
class2 (Form)
{
class1 tcpClass = new class1();
public class2()
{
tcpClass.DataReceived += new tcpClass.EventHandlerDataReceived(tcpClass_DataReceived);
}
private void tcpClass_DataReceived(object sender, DataReveivedEventArgs e)
{
txtData.Text = e.Data.ToString();
}
}
|
|
|
|
|
No, you have to use Invoke.
GUI controls can only be accessed from the GUI thread. Here you are trying to access it from another thread.
A nice readable way to do this would be have a separate method to perform the update.
public void UpdateTextBox(String data)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<string>(UpdateTextBox), data);
return;
}
txtData.Text = data;
} This is a pretty standard pattern.
Simon
|
|
|
|
|
Isn't it possible to place an Invoke in the function that fires the event?
In a Form can be used InvokeRequired and BeginInvoke.
But in my TCP class I can't find any possibility for Invoke.
|
|
|
|
|
Kurt wrote: Isn't it possible to place an Invoke in the function that fires the event?
Not really because the class that is firing the event doesn't know what thread it should be invoking on.
The form is a GUI control, so it knows what thread the GUI thread is.
The class that is creating the event shouldn't be forced to raise the event on the GUI thread, that would be bad design, sometimes you might not want it on the GUI thread, particularly if you are doing things in the background.
It is the form that should be responsible for transferring the control to the GUI thread when updating controls.
Simon
|
|
|
|
|
First: Thank you for yor help!
Hmm, I thought of making a DLL, so the users can double click the event in the property window and fill in individual code. But the user would be forced to use invoke.
We can use so many different controls in our projects and use their events without invoke. Do all those controls doesn't use asynchronous processes?
|
|
|
|
|
Kurt wrote: Hmm, I thought of making a DLL, so the users can double click the event in the property window and fill in individual code. But the user would be forced to use invoke.
Yes, they would, but this is how winforms works so they should understand that. All GUI controls must be accessed from the GUI thread, so any calls coming from a different thread must use invoke to transfer control to the GUI thread.
Kurt wrote: We can use so many different controls in our projects and use their events without invoke. Do all those controls doesn't use asynchronous processes?
All GUI controls only use the GUI thread, so their events are all raised on the GUI thread, so it isn't a problem.
The difference with your code is that the event is coming from an callback provided by your sockClient object. This is only natural, incoming data could come in at any point, so the object watching for the data must be doing it on a different thread, otherwise it would block the GUI. So when it triggers the callback, it's coming from a different thread, that is why an invoke onto the GUI thread is required.
Simon
|
|
|
|
|
You could add a property to the class of type ISynchronizeInvoke. Then when you create the instance, assign the form to that property. When raising the event, you can check InvokeRequired and perform a BeginInvoke on the ISynchronizeInvoke object.
|
|
|
|
|
Hi Kurt,
The System.ComponentModel namespace contains the AsyncOperation class which enables a thread to raise events on the GUI thread. I won't try and modify your code as my knowledge of network programming is minimal but instead I present a simple example showing the basics.
using System;
using System.ComponentModel;
using System.Threading;
namespace WorkerThreadEvent {
class EventThread {
private AsyncOperation operation;
public event EventHandler<ProgressChangedEventArgs> ProgressChanged;
private void OnProgress(Object progress) {
EventHandler<ProgressChangedEventArgs> handler = ProgressChanged;
if (handler != null) {
ProgressChangedEventArgs args = new ProgressChangedEventArgs((int)progress, null);
handler(this, args);
}
}
public void Run() {
operation = AsyncOperationManager.CreateOperation(null);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), null);
}
private void ThreadProc(Object state) {
try {
for (int i = 1; i <= 100; i++) {
Thread.Sleep(100);
operation.Post(new SendOrPostCallback(OnProgress), i);
}
} finally {
operation.OperationCompleted();
}
}
}
}
The only real changes to standard event coding are
1) Creation of an AsyncOperation
2) Use of the operation's Post method to marshal the event to the thread that called AsyncOperationManager.CreateOperation(null)
3) Ending the operation correctly when it no longer needed
You can incorporate this class in a simple winforms app and you'll find that the ProgressChanged event is raised on the GUI thread and there will be no need to use invoke to update the display.
I use the AsyncOperation quite often now as it really simplifies UI coding in a multithreaded programme and I'm sure that many more people would too if only the documentation on MSDN was better. An example like the one above might help!
Alan.
By the way I think that the technique I have shown is similar to the way that the BackgroundWorker class marshals events to the GUI thread.
And it would be remiss of me not to reference this excellent article by Leslie Sanford.
http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx[^]
modified on Friday, October 24, 2008 2:29 PM
|
|
|
|
|
I searched for ISynchronizeInvoke and found a complete solution for thread safe events instead.
This solution is from http://www.gmbsg.com/works/index.php?title=Events_threadsicher_aufrufen_in_.NET[^]
public static class ThreadSafe
{
public static void Invoke(Delegate method, object[] args)
{
if (method != null)
{
foreach (Delegate handler in method.GetInvocationList())
{
if (handler.Target is Control)
{
Control target = handler.Target as Control;
if (target.IsHandleCreated)
{
target.BeginInvoke(handler, args);
}
}
else if (handler.Target is ISynchronizeInvoke)
{
ISynchronizeInvoke target = handler.Target as ISynchronizeInvoke;
target.BeginInvoke(handler, args);
}
else
{
handler.DynamicInvoke(args);
}
}
}
}
}
public void OnDataReceived(object sender, DataReveivedEventArgs e)
{
if (DataReceived != null) { ThreadSafe.Invoke(this.DataReceived, new object[] { this, e });
}
It works great! No invoke outside my class is needed anymore!
|
|
|
|
|
Hi
We've developed open-source ASP.NET shopping cart. nopCommerce is a open source e-commerce solution that is ASP.NET 3.5 (C#) based with a MS SQL 2005 (or higher) backend database. nopCommerce is available for free. If somebody will be interested in reviewing it please visit http://www.nopCommerce.com
Thank you!
nopCommerce is the open-source eCommerce solution. nopCommerce is available for free.
http://www.nopCommerce.com
|
|
|
|
|
Hi all,
Does someone know if it is possible to access a variable and change the name of the variable based on a condition. (This does not make much sense but let me explain it using the example below.
I have two foreach loops, both doing the exact same thing. But it is accessing different variables. I would prefer it if i were to have one foreach loop and access the different variable based on the string that was passed to the function.
Thus having something like (string.Concat(context,"ReadOnlyProperties"))
private void CustomizeEditor(string context)
{
DetailView detailViewCore = (DetailView)View;
Object obj = detailViewCore.CurrentObject;
if (context == "live")
{
foreach (string liveTargetPropertyName in liveReadOnlyProperties.Keys)
{
CriteriaOperator criteria = CriteriaOperator.Parse(liveReadOnlyProperties[liveTargetPropertyName]);
UpdateProperty(detailViewCore, obj, liveTargetPropertyName, criteria);
}
}
else
{
foreach (string saveTargetPropertyName in saveReadOnlyProperties.Keys)
{
CriteriaOperator criteria = CriteriaOperator.Parse(saveReadOnlyProperties[saveTargetPropertyName]);
UpdateProperty(detailViewCore, obj, saveTargetPropertyName, criteria);
}
}
}
Thanks
|
|
|
|
|
You can make a method which contains the loop, and call the method twice passing the variable to loop through..
|
|
|
|
|
private void CustomizeEditor(string context)
{
DetailView detailViewCore = (DetailView)View;
Object obj = detailViewCore.CurrentObject;
string parse, propertyName;
if (context == "live"){
parse = liveReadOnlyProperties[liveTargetPropertyName];
propertyName = liveTargetPropertyName;
keys = liveReadOnlyProperties.Keys;
}
else{
parse = saveReadOnlyProperties[saveTargetPropertyName];
propertyName = saveTargetPropertyName;
keys = saveReadOnlyProperties.Keys;
}
foreach (string propertyName in keys)
{
CriteriaOperator criteria = CriteriaOperator.Parse(parse);
UpdateProperty(detailViewCore, obj, propertyName , criteria);
}
}
|
|
|
|