I have a Canvas control with various elements on, in this particular function I am allowing a user to drag the end point of a line around the canvas. In the MouseMove function I call e.GetPosition().
The function is, according to the VS performance analyzer, close to 30% of total CPU for the app when constantly moving around. Its pretty slow. What can I do to increase this performance?
CurrentPoint = e.GetPosition(PointsCanvas);
I've faced the same problem while using MouseMove on windows phone 8. It seems that while dragging , events (containing the coordinates you need ) are raised at regular time interval ( depending on what you do in the implementation in your listeners, every 20 ms for example). So what I did was to populate a Queue with my coordinates and create a Thread that consume that Queue by enqueue the first element and do the logic I want. Like that the logic is not done serially because it's another thread who does the job.
I don't know if I'm enough clear so please take a look to the code below :
//Class used to store e.getPosition(UIElement).X/Y
public class mouseInformation
{
public int x { get; set; }
public int y { get; set; }
public mouseInformation(int x, int y, String functionName)
{
this.x = x;
this.y = y;
}
}
private readonly Queue<mouseInformation> queueOfEvent = new Queue<mouseInformation>();
//MouseMove listener
private void wpCanvas_MouseDragged(object sender, System.Windows.Input.MouseEventArgs e)
{
//Instead of "wpCanvas" put the name of your UIElement (here your canvas name)
mouseInformation mouseDragged = new mouseInformation((int)e.GetPosition(wpCanvas).X, (int)e.GetPosition(wpCanvas).Y);
EnqueueMouseEvent(mouseDragged);
}
//Allow you to add a MouseInformation object in your Queue
public void EnqueueMouseEvent(mouseInformation mi)
{
lock (queueOfEvent)
{
queueOfEvent.Enqueue(mi);
Monitor.PulseAll(queueOfEvent);
}
}
//Logic that your consumer thread will do
void Consume()
{
while (true)
{
mouseInformation MI;
lock (queueOfEvent)
{
while (queueOfEvent.Count == 0) Monitor.Wait(queueOfEvent);
MI = queueOfEvent.Dequeue();
}
// DO YOUR LOGIC HERE
// i.e DoSomething(MI.x, MI.y)
}
}
And don't forget to create the thread in your Main() or in MainPage_Loaded(object sender, RoutedEventArgs e) method if you are Windows phone user.
System.Threading.ThreadStart WatchQueue = new System.Threading.ThreadStart(Consume);
System.Threading.Thread RunWatchQueue = new System.Threading.Thread(WatchQueue);
RunWatchQueue.Name = "Events thread";
RunWatchQueue.Start();
To be simple less you do in your MouseMove listener, more speed it will be.
You can aswell do the logic asynchronously or even use Bresenham algorithm to simulate more events.
Hope it helps.
Are you using any effects such as dropshaddow etc?
I recently had the situation where e.GetPosition() was also using 30% of the app's cpu resources, which doesn't make any sense right?
I turns out that up the visual tree there was a control applying a dropshaddow effect and that was what was slowing everything down so much...
Related
I'm making a system to balance calls inside of the OnGUI method of a EditorWindow.
I'm doing the following:
public void Update()
{
Repaint();
}
Inside of my OnGUI method I'm calling this Balancer. I have one list with the callbacks (List).
So the idea is simple, some callvaxc
I'm skipping some repaint frames for the callback that has the complete GUI, and calling on each repaint for other callbacks (for example, a marquee label or dispalying gifs).
By some reason, this error happens "Getting control 0's position in a group with only 0 controls when doing repaint"
private int m_repaintCounter;
public void Draw()
{
Event e = Event.current;
try
{
foreach (var action in m_actions)
{
try
{
// Test 1
// MainAction is a class that inherits from Action (class MainAction : Action)
if (action is MainAction)
{
bool isDesignedType = e.rawType == EventType.Repaint || e.rawType == EventType.Layout;
if (isDesignedType)
++m_repaintCounter;
if (!(m_repaintCounter == 20 && isDesignedType))
continue;
else
m_repaintCounter = 0;
}
// Test 2
action.Value();
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
catch
{
// Due to recompile the collection will modified, so we need to avoid the exception
}
}
But if I comment the "Test 1" everythings works fine.
On the ctor of the class we need to specify a callback to a GUI method, for example:
public Balancer(Action drawAction)
{
m_actions = new List<Action>();
m_actions.Add(drawAction);
}
So we could do easily (inside the EditorWindow):
private Balancer m_balancer;
public void OnEnable()
{
m_balancer = new Balancer(Draw);
}
public void Draw()
{
// This block will be called every 20 repaints as specified on the if statment
GUILayout.BeginHorizontal("box");
{
GUILayout.Button("I'm the first button");
GUILayout.Button("I'm to the right");
// This marquee will be called on each repaint
m_balancer.AddAction(() => CustomClass.DisplayMarquee("example"));
}
GUILayout.EndHorizontal();
}
// Inside of the Balancer class we have
// We use System.Linq.Expressions to identify actions that were added already
private HashSet<string> m_alreadyAddedActions = new HashSet<string>();
public void AddAction(Expression<Action> callback)
{
if(!m_alreadyAddedActions.Add(callback.ToString()))
return;
m_actions.Add(callback.Compile());
}
I can't figure this out. I couldn't find any information on the internet. Can anyone help me?
Ok, so, OnGui (IMGui) is awful to work with. If you aren't using it for an editor script, use the new 4.6 UI (UGui) instead.
Now then. The problem.
OnGui is called at least twice every frame. One of those is to calculate layouts and the other is to actually draw stuff ("repaint").
If the number of things, size of things, or anything else changes between these two calls then Unity will error with "Getting control 0's position in a group with only 0 controls when doing repaint."
That is: you cannot change UI state in the IMGui system at any point after Layout and before Repaint.
Only, only, only change state (and thereby which objects are being drawn) during Event.current == EventType.Repaint and only, only, only change state for the next frame (alternatively, do the changes during Event.current == EventType.Layout, provided that this same, new state will result in the same code path during Repaint). Do not, under any circumstances, make changes during Repaint that were not present during the previous Layout.
I am using slimdx to interpret xbox controller button presses. I poll every 200ms to read the xbox button states and all works for me. I use
JoystickState state = Joystick.GetCurrentState();
// get buttons states
bool[] buttonsPressed = state.GetButtons();
Is there anyway to generate events on the button press instead of polling? To explain imagine if my poll time was 5 seconds. And the user presses a button in the 2nd second and releases it. In the next poll time my application will never know that the button was pressed
No - in DirectX you must poll. To do this efficiently you want to create a polling thread, and have a class which raises cross thread events to your consuming thread.
I know this is 4 years old but the answer is incorrect. The most efficient way may be to poll, but you can raise an event when you poll.
This is a work in progress but it should get someone started. Save this as a new class, it derives from a Timer, so once you add this to your project, build it, and drag it onto the Form you want to use it, you can then subscribe to the buttonPressed event.
public class GamePadController : Timer
{
public delegate void ButtonPressedDelegate(object sender, int ButtonNumber);
public event ButtonPressedDelegate ButtonPressed;
List<DeviceInstance> directInputList = new List<DeviceInstance>();
DirectInput directInput = new DirectInput();
List<SlimDX.DirectInput.Joystick> gamepads = new List<Joystick>();
SlimDX.DirectInput.JoystickState state;
public GamePadController()
{
this.Interval = 10;
this.Enabled = true;
this.Tick += GamePadController_Tick;
RefreshGamePads();
}
private void RefreshGamePads()
{
directInputList.Clear();
directInputList.AddRange(directInput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly));
gamepads.Clear();
foreach (var device in directInputList)
{
gamepads.Add(new SlimDX.DirectInput.Joystick(directInput, directInputList[0].InstanceGuid));
}
}
private void GamePadController_Tick(object sender, EventArgs e)
{
foreach (var gamepad in gamepads)
{
if (gamepad.Acquire().IsFailure)
continue;
if (gamepad.Poll().IsFailure)
continue;
if (SlimDX.Result.Last.IsFailure)
continue;
state = gamepad.GetCurrentState();
bool[] buttons = state.GetButtons();
for (int i = 0; i < buttons.Length; i++)
{
if (buttons[i])
{
if (ButtonPressed != null)
{
ButtonPressed(gamepad, i);
}
}
}
gamepad.Unacquire();
}
}
}
}
A table called floorLayout has the original cordinates of the objects stored. These details are showed in a 2D picturebox with basic 2D shapes.
A slave of above table gets updated real time for new cordinates of the objects and these new locations should be also udpated into the 2D shapes (by changing colour, location etc).
I am certainly new to graphics. So following are couple of questions I would like to clarify.
Do I need a backgroundworker with a thread to handle updates to 2D graphics?
Is there any other approach for this scenario?
Edit after helpful comments:
There's a table with a basic seating plan details.
Seat Number, Seat Type (represented by an eclipse or a square), Original Seat Location
When a seat is occupied or reserved, the reference shape in the picture box colour must be changed.
Seats can be in different sections. However at times a certain seat can be coupled with another seat. When a seat is coupled with another, its current location becomes the location of its couple seat (location remain original). Both seats' colour changes.
When decouple, the secondary seat location changes back to its original location and colour changes.
It means for each DML transaction that seating lsyout has an impact. Thats what I want to manage without compromising performance.
The application has three parts. Set up (login is a part of set up), Seating allocation, Graphical layout. Although it is in C#, the model is in 3-tier layered architecture for future web extensibility (if required). Plus having services and data access separately gives lots of freedom n easy to manage.
Given this scenario what're my options?
Edit2:[2014/07/01]
While trying out the Bitmap based drawing for my original question, I have come across an issue related to my threading. I am posting here, as it's infact related to the discussion I had with the capable answerers.
public void bgWorker_DoWork(object sender, DoWorkEventArgs d)
{
//insert seats (sql call via service/access interaces) to table
AddSeats();
}
//this doesn't get fired----<<<-------
public void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs p)
{
txtFlag.Text = p.ProgressPercentage.ToString();
}
//this works fine
public void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs r)
{
if (r.Cancelled)
{
txtFlag.Text = "Failed";
}
else
{
//load datagridview using datatable returned by select query
GetSeats();
//draw the bitmap with a loop over the datagridview
DrawFuntion();
//bgWorker.ReportProgress(prog, txtFlag.Text);
}
}
One major issue:
1. does this really make sense that I use bgworker to do the insertion to database, when it's completed I am calling loadgridview and draw methods?
2. I infact think, it's best to call draw method within bgworker, but I can't figure out how (logically, and functional flow-wise)
3. When I tried to run DrawFunction() within DoWork(), it just threw the biggest cross thread error: that access to UI controls in the form which are created using a different thread is not allowed.
How can I make sense of this?
Here is the layout I would go for, considering the results of our chat:
Given the time constraint of the current project, keep it in Winforms, but keep WPF in mind for a future revision.
Drawing a thousand seats is not a big problem, but in order to keep the GUI responsive it should be done by a background worker like this:
Create two Bitmap properties:
public Bitmap bmp_Display { get; set; }
public Bitmap bmp_Buffer { get; set; }
In the display Panel's Paint event you simply dump the bmp_Display onto the panel like this:
e.Graphics.DrawImage(bmp_Display, Point.Empty);
This is a single command and will happen real fast.
To create the updated floorplan the background thread draws the seats onto the bmp_Buffer, maybe like this:
foreach (Seat s in SeatList)
{
e.Graphics.FillRectangle(seatBrushes[s.State],
new Rectangle(s.Location, s.Size);
e.Graphics.DrawString(s.Name, seatFont, Brushes.Black, s.Location);
}
When it is done, it dumps it onto the bmp_Display like this:
bmp_Display = (Bitmap)bmp_Buffer.Clone();
To do that you should assure thread safety, maybe by a lock.
Finally the display Panel is invalidated.
The details will depend on the data structure and the business logic you will be using. If you will transfer only the changes, use them to update the data structure and still draw them all. You can Initialize the buffer Bitmap with a nice image of the floorplan with the tables and other things.
If needed you can create a helper app to act as a floorplan editor which would create the seats data structure and map it to the floorplan coordinates of the seats.
Here is an example of how the background worker can update the bitmap. Note that the error handling is practically non-existent; also only one of the locks should be necessary. And you need to get at the data somehow. The Seat class is just a dummy, too.
List<SolidBrush> seatBrushes = new List<SolidBrush>()
{ (SolidBrush)Brushes.Red, (SolidBrush)Brushes.Green /*..*/ };
public Bitmap bmp_Display { get; set; }
public Bitmap bmp_Buffer { get; set; }
public class Seat
{
public string Name { get; set; }
public int State { get; set; }
public Point Location { get; set; }
//...
}
private void drawFloorplan(List<Seat> seats)
{
Graphics G = Graphics.FromImage(bmp_Buffer);
Font sFont = new Font("Consolas", 8f);
Size seatSize = new Size(32, 20);
foreach (Seat s in seats)
{
G.FillRectangle(seatBrushes[s.State], new Rectangle(s.Location, seatSize));
G.DrawString(s.Name, sFont, Brushes.Black, s.Location);
}
G.Dispose();
sFont.Dispose();
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if ((worker.CancellationPending == true))
{
e.Cancel = true;
}
else
{
// get the seat data..
List<Seat> seats = new List<Seat>();
if (seats.Count > 0)
{
drawFloorplan(seats);
try { bmp_Display = (Bitmap)bmp_Buffer.Clone(); }
catch { /*!!just for testing!!*/ }
//lock(bmp_Display) { bmp = (Bitmap) bmp_Buffer.Clone(); }
}
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{ this.tbProgress.Text += "Cancelled!"; }
else if (!(e.Error == null))
{ this.tbProgress.Text += ("Error: " + e.Error.Message); }
else
{ panel1.Invalidate(); }
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
try { e.Graphics.DrawImage(bmp, Point.Empty); } catch {/*!!just for testing!!*/ }
//lock (bmp){ e.Graphics.DrawImage(bmp, Point.Empty); }
}
Edit 2 A few words about thread safety: The point of TS is to ensure that no two threads try to access the same object at the same time. Looking at the code one could wonder how it could happen, since it is only upon its completion that the BW thread will trigger the Invalidate. However things are more complicated with threads. They always are! Here for example the problems will come in when the system intself triggers an invalidate at a time the BW thread is dumping its result into the display bitmap. (The system is free to do so, whenever it sees a reason to get the screen updated.)
To avoid this one of the concurring threads should block its access while it is working with the resource. I suggest the do_Work method. Chances are that you never encounter a problem in your tests. My testbed ran up to 30 times per second (!) and after a few minutes it did. The try - catch only prevents crashing. For production code the whole situation should be avoided by using a lock.
Careful with lock though: 'lock blocks' and can create deadlocks, when used too generously..
I want to make hovering button in my game. Because when my cursor touch the button it will go to another screen immediately. I don't like this so much. I use xna 4.0 with visual studio 2010 to make this project. (use kinect without wpf)
How to use timer in this case ? Please help me
if (Hand.contian(Button) && holdtime == targetHoldtime)
{
}
You have to manage time by yourself based in elapsed time per frame:
ft = GameTime.Elapsed.TotalSeconds; // Xna
ft= 1/30f; // 30fps
And can be done in similar way to this:
class Button {
public float Duration = 1; // One second
public Rectangle Bounds; // Button boundaries
public float Progress { get{ return Elapsed/Duration; } }
float Elapsed = 0;
public void Update(float ft) {
if (Bounds.Contains( HandPosition ))
{
if (Elapsed<Duration) {
Elapsed += ft;
if (Elapsed>Duration) {
Elapsed = Duration;
OnClick();
}
}
} else {
Elapsed = 0;
}
}
}
I would first suggest that you look through the SDK documentation and the built in KinectInteraction controls. They may provide you with what you are looking for. Most notably SDK 1.7 removed that "HoverDwell" button in favor of a "press" action, which is a more natural interaction in a gesture system. You may want to look at using that motion instead.
If you truly desire a "click on hover" type action, you can look at the code in SDK 1.6 for an example. Several examples are available online at the Kinect for Windows CodePlex repository. The specific control example you are looking for is in the "BasicInteraction-WPF" project, and is called HoverDwellButton.
The "button" is actually a ContentControl which means you can place any content in there to make it a button. It can be a simple image, or a complex Grid. It has all the hooks to fire events when the timer on your hover goes off.
There is a decent amount of complexity in this control, which is what makes it work for a wide range of applications. At the core of the interaction is a simple DispatcherTimer.
private void OnPreviewHandEnter(object sender, HandInputEventArgs args)
{
if (this.trackedHandHovers.FirstOrDefault(t => t.Hand.Equals(args.Hand)) == null)
{
// additional logic removed for answer sanity
var timer = new HandHoverTimer(DispatcherPriority.Normal, this.Dispatcher);
timer.Hand = args.Hand;
timer.Interval = TimeSpan.FromMilliseconds(Settings.Default.SelectionTime);
timer.Tick += (o, s) => { this.InvokeHoverClick(args.Hand); };
this.trackedHandHovers.Add(timer);
timer.Start();
}
args.Handled = true;
}
Notice that the Tick event is calling InvokeHoverClick, which (in part) reads as follows:
public void InvokeHoverClick(HandPosition hand)
{
// additional logic removed for answer sanity
var t = new DispatcherTimer();
t.Interval = TimeSpan.FromSeconds(0.6);
t.Tick += (o, s) =>
{
t.Stop();
var clickArgs = new HandInputEventArgs(HoverClickEvent, this, hand);
this.RaiseEvent(clickArgs);
this.IsSelected = false;
};
t.Start();
}
This now fires an event after a set amount of time. This event can be capture and acted upon to your liking.
Again, I first recommend looking at the newer interactions in SDK 1.7. If you still want a timed hover click action, check out the links above. I used the HoverDwellButton to great effect in several different areas.
I've got a C# program that talks to an instrument (spectrum analyzer) over a network. I need to be able to change a large number of parameters in the instrument and read them back into my program. I want to use backgroundworker to do the actual talking to the instrument so that UI performance doesn't suffer.
The way this works is - 1) send command to the instrument with new parameter value, 2) read parameter back from the instrument so I can see what actually happened (for example, I try to set the center frequency above the max that the instrument will handle and it tells me what it will actually handle), and 3) update a program variable with the actual value received from the instrument.
Because there are quite a few parameters to be updated I'd like to use a generic routine. The part I can't seem to get my brain around is updating the variable in my code with what comes back from the instrument via backgroundworker. If I used a separate RunWorkerCompleted event for each parameter I could hardwire the update directly to the variable. I'd like to come up with a way of using a single routine that's capable of updating any of the variables. All I can come up with is passing a reference number (different for each parameter) and using a switch statement in the RunWorkerCompleted handler to direct the result. There has to be a better way.
I think what I would do is pass a list of parameters, values, and delegates to the BackgroundWorker. That way you can write the assign-back code "synchronously" but have execution deferred until the values are actually retrieved.
Start with a "request" class that looks something like this:
class ParameterUpdate
{
public ParameterUpdate(string name, string value, Action<string> callback)
{
this.Name = name;
this.Value = value;
this.Callback = callback;
}
public string Name { get; private set; }
public string Value { get; set; }
public Action<string> Callback { get; private set; }
}
Then write your async code to use this:
private void bwUpdateParameters_DoWork(object sender, DoWorkEventArgs e)
{
var updates = (IEnumerable<ParameterUpdate>)e.Argument;
foreach (var update in updates)
{
WriteDeviceParameter(update.Name, update.Value);
update.Value = ReadDeviceParameter(update.Name);
}
e.Result = updates;
}
private void bwUpdateParameters_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
var updates = (IEnumerable<ParameterUpdate>)e.Argument;
foreach (var update in updates)
{
if (update.Callback != null)
{
update.Callback(update.Value);
}
}
}
Here's how you would kick off the update. Let's say you've got a bunch of member fields that you want to update with the actual values of the parameters that were used:
// Members of the Form/Control class
private string bandwidth;
private string inputAttenuation;
private string averaging;
// Later on, in your "update" method
var updates = new List<ParameterUpdate>
{
new ParameterUpdate("Bandwidth", "3000", v => bandwidth = v),
new ParameterUpdate("InputAttenuation", "10", v => inputAttenuation = v),
new ParameterUpdate("Averaging", "Logarithmic", v => averaging = v)
};
bwUpdateParameters.RunWorkerAsync(updates);
That's all you have to do. All of the actual work is done in the background, but you're writing simple variable-assignment statements as if they were in the foreground. The code is short, simple, and completely thread-safe because the actual assignments are executed in the RunWorkerCompleted event.
If you need to do more than this, such as update controls in addition to variables, it's very simple, you can put anything you want for the callback, i.e.:
new ParameterUpdate("Bandwidth", "3000", v =>
{
bandwidth = v;
txtBandwidth.Text = v;
})
Again, this will work because it's not actually getting executed until the work is completed.
[Edit - look back at update history to see previous answer. Talk about not being able to see the wood for the trees]
Is there any reason that, rather than passing a reference number to the Background Worker, you can't pass the ID of the label that should be updated with any value passed back?
So the UI adds an item in the work queue containing:
Variable to change
Attempted change
UI ID
and the BackgroundWorker triggers an event with EventArgs containing
Attempted change
Actual value after attempt
UI ID
Error Message (null if successful)
which is all the information you need to update your UI without a switch or multiple event args and without your Background Worker ever being aware of UI detail.
How about something like this?
[TestFixture]
public class BGWorkerTest
{
string output1;
string output2;
[Test]
public void DoTest()
{
var backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += (sender, args) =>
{
output1 = DoThing1();
output2 = DoThing2();
};
backgroundWorker.RunWorkerAsync();
//Wait for BG to finish
Thread.Sleep(3000);
Assert.AreEqual("Thing1",output1);
Assert.AreEqual("Thing2",output2);
}
public string DoThing1()
{
Thread.Sleep(1000);
return "Thing1";
}
public string DoThing2()
{
Thread.Sleep(1000);
return "Thing2";
}
}