UI responsiveness on listbox ItemSelectionChanged() event - c#

I'd like to enable a button if some Data is available:
private void myListBox_ItemSelectionChanged(object sender, EventArgs e)
{
downloadButton.Enabled = myList.SelectedItems.Cast<myClass.myObject>().Any(x => x.Data != null);
}
The problem is that the UI is not quite responsive, and behaves weirdly (sometimes when I click the selection does not get changed when I click and select a different element). I figured that this is because of that bit of code.
Any suggestion to speed things up?

Related

How to keep update user interface on Windows Phone apps responsively

I am trying to create an Calculator app on WP 8.1. I would like to create an Automation Button which perform automation click on other buttons of my app. For example, in this code, when I click the automation button, it will call the event of clicking other buttons such as:
private void Auto_Click(object sender, RoutedEventArgs e)
{
button3_Click(this, null);
button_addition_Click(this, null);
button7_Click(this, null);
button_result_Click(this, null);
}
I this example, I perform the operations is "3 + 7" and after that I press the "Equal" button.
The result created is right. But I have 1 issue, that is the showing of textbox's data don't change responsively in this method. But when I click the button3 independently, the showing of textbox's data changed instantly. The code button3_Click event is:
private void button3_Click(object sender, RoutedEventArgs e)
{
if (is_subtend(this.textbox.Text) == false)
this.textbox.Text += "3";
else
this.textbox.Text = "3";
}
So what can I do to change the showing of textbox's data in the automation_click event.
Thank you for your help.
The results are as expected. There are really no delays in between those Button Clicks, so it changes the text really fast, no time for the UI to update. If you want to see a "3" then... a "3+"... then a "3+7"... etc.. then implement a delay in-between the button clicks.
To see what I mean try this
using System.Threading.Tasks;
// don't forget the async
private async void Auto_Click(object sender, RoutedEventArgs e)
{
button3_Click(this, null);
await Task.Delay(TimeSpan.FromMilliseconds(250));
button_addition_Click(this, null);
await Task.Delay(TimeSpan.FromMilliseconds(250));
button7_Click(this, null);
await Task.Delay(TimeSpan.FromMilliseconds(250));
button_result_Click(this, null);
await Task.Delay(TimeSpan.FromMilliseconds(250));
}
Lower the 250 to a value you want for the speed you're looking for.

C# Drag and Drop From listBox

I'm trying to build a simple interface that allows users to drop files into a listBox to add them to a process, and to drag them out to remove them. Everything is working fine, but I'd like to add one feature to make it just a tad more sophisticated.
Right now, I have the removal of the item tied to the DragLeave event, which means that as soon as the mouse leaves the box, the item is removed. But I'd like for users to be able to change their minds. In other words, if they realize they're dragging the wrong file out, I'd like them to be able to move the mouse back into the listBox and release the mouse to cancel the action. I'm thinking that means I need to be able to capture the MouseUp event instead of the DragLeave event. But that hasn't been successful so far.
Below is the code I'm currently using for removing files dragged out. How can I modify to keep the files from being removed form the list until the user lets the mouse button go?
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
if (listBox1.Items.Count == 0)
{
return;
}
int index = listBox1.IndexFromPoint(e.X, e.Y);
string s = listBox1.Items[index].ToString();
DragDropEffects dde1 = DoDragDrop(s, DragDropEffects.All);
}
private void listBox1_DragLeave(object sender, EventArgs e)
{
ListBox lb = sender as ListBox;
lb.Items.Remove(lb.SelectedItem);
}
Edit 2013/05/16
The comments and answers so far have been useful, but I realize my question isn't clear enough. In this case, I'm displaying a dialog separate from the parent form that is basically as big as the listBox. When someone drags a file out of the list, they're dragging it off the form completely. Have I backed myself into a corner by doing this? I recognize I'm making it harder than it has to be, but I'd still like to see how it would work if it's possible.
Here's a fairly quick hack approach to gaining the functionality you want:
public object lb_item = null;
private void listBox1_DragLeave(object sender, EventArgs e)
{
ListBox lb = sender as ListBox;
lb_item = lb.SelectedItem;
lb.Items.Remove(lb.SelectedItem);
}
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
if (lb_item != null)
{
listBox1.Items.Add(lb_item);
lb_item = null;
}
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
lb_item = null;
if (listBox1.Items.Count == 0)
{
return;
}
int index = listBox1.IndexFromPoint(e.X, e.Y);
string s = listBox1.Items[index].ToString();
DragDropEffects dde1 = DoDragDrop(s, DragDropEffects.All);
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
lb_item = null;
}
Every time the user drags an item out of the box, it's saved temporarily until the user drops it somewhere else or mouses down on a new item in the list.
Note the important part of this is detecting when and where the user let's go of that mouse, which is the rationale behind handling the DragDrop event of Form1, the parent of listBox1.
Depending on the sophistication and density of the rest of your layout, where you handle DragDrop could be much different for you. This is why it's kind of "hacky", but it's also quite simple. It shouldn't matter, though, where or how many times you null lb_item since it pertains only to that specific ListBox.
I suppose another way to do it would be to track the user's mouse states and act accordingly, which may be more appropriate for you if it's inconceivable to handle a lot of DragDrop stuff.
EDIT: If you wanted to be REAL thorough, you could enumerate through every control of the base form using foreach and programmatically append a handler for the DragDrop event to that control, then remove it when done... but that may be getting a little nutty. I'm sure someone has a better approach.

Monotouch TouchUpInside does not work, TouchDown works

I have seen some topics about this subject in Objective-C. I read a lot of them, spent 2 days on it on trying to find a solution and none of them worked for me. I am mainly coding in C#. Since my problem behaviour (fire only when leaving/re-enter button) and context (C#) is a bit different. So, I will try my chance by asking my question here.
I will try to keep it simple.
Here is a sample of code:
private UIButton _buttonTest;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
_buttonTest = new UIButton(new RectangleF(10, 70, 50, 50));
_buttonTest.SetTitle("0", UIControlState.Normal);
_buttonTest.TouchUpInside += HandleButtonTestTouchUpInside;
_buttonTest.BackgroundColor = UIColor.Red;
this.View.AddSubview(_buttonTest);
}
void HandleButtonTestTouchUpInside (object sender, EventArgs e)
{
string textNumber = _buttonTest.Title(UIControlState.Normal);
// Increment Number
_buttonTest.SetTitle((int.Parse(textNumber)+1).ToString(), UIControlState.Normal);
}
There is a button and the title text is set to "0".
When the user click on it, it increments the number (title) by 1.
This code usually works very well!
However, it does not work in some of my classes for some unknown reasons...
Here is the problem:
TouchUpInside does not fire. ... However, if I hold the button with a finger and keep holding the finger while leaving the button and then re-entering the button then release the button, then.... it will fire the TouchUpInside, .... so the finger need to leave and re-renter the button while holding the button to make the TouchUpInside fires. Usually, this code works very well.
Things Checked:
if I replace TouchUpInside by TouchDown, then TouchDown works.
'User Interaction Enabled' is set to True for all superviews.
All views frames (among the superviews) seem to be inside their superview frames.
I moved the _buttonTest around and I noticed that the _buttonTest TouchUpInside does not fire correctly in the View, the SuperView, the SuperSuperView.... but it fires correctly in the SuperSuperSuperView.
Any suggestion?
In the SuperSuperView, I had this tap gesture that was entering in conflict with the Button event.
// Tap Gesture
UITapGestureRecognizer tapPageGestureRecognizer = new UITapGestureRecognizer();
tapPageGestureRecognizer.AddTarget(this, new Selector ("HandleTapPageGestureRecognizer:"));
this.View.AddGestureRecognizer(tapPageGestureRecognizer);
The idea is to disable the gesture SuperSuperView gesture when the button event, TouchDown was fired, ... and to re-enable it when the TouchUpInside is fired.
So here is one solution for the problem:
private void SetGrandParentViewGestureEnabled(bool enabled)
{
foreach(UIGestureRecognizer g in this.View.Superview.Superview.GestureRecognizers)
{
g.Enabled = enabled;
}
}
void HandleButtonSubmitTouchDown (object sender, EventArgs e)
{
SetGrandParentViewGestureEnabled(false);
}
void HandleButtonSubmitTouchUpInside (object sender, EventArgs e)
{
// => Do treatments here!
SetGrandParentViewGestureEnabled(true);
}
However, I could have used EventHandler or Action to enable/disable the tap gesture.
EDIT: Here is another function that need to be added as well to re-enable the gesture.
void HandleButtonSubmitTouchUpOutside (object sender, EventArgs e)
{
SetGrandParentViewGestureEnabled(true);
}
I had a similar problem, I ended up using a tap recognizer together with the long press recognizer like this for the button TopRightButton.
var longPressGesture = new UILongPressGestureRecognizer(Action);
TopRightButton.AddGestureRecognizer(longPressGesture);
var tapRecognizer = new UITapGestureRecognizer();
tapRecognizer.AddTarget(() =>
{
//method
});
tapRecognizer.NumberOfTapsRequired = 1;
this.TopRightButton.AddGestureRecognizer(tapRecognizer);
private void Action(){ };

How can I keep multiple controls in focus?

I have a tree view on the left side. Selecting a node displays relevant information in a form on the right side.
Would I be able to keep the tree and any one control (textbox, combobox, checkbox) on the right in focus at the same time? This will enable a user to select a field, make a change, select another node, and without having to go back and select the same field again, just type and change the value of the same field.
Thanx.
EDIT
I suppose one could implement such behaviour manually:
private Control __cFocus;
private void {anyControl}_Focus(object sender, EventArgs e)
{
__cFocus = (Control)sender;
}
private void treeView1_AfterSelect(object sender, EventArgs e)
{
__cFocus.Focus();
}
I was just wondering if there exists an automatic / more elegant solution
EDIT 2
Ok, so it seems I'll have to implement it manually. Manual implementation it is then. However, now there seem to be another problem; not sure if I should ask this as a separate question.
When selecting a node the textbox gains focus as intended, but only when using the keyboard. It doesn't work when selecting a node with the mouse. First I thought that it might be a mouse event that's interfering, but stepping revealed that the MouseUp event fired first and then the AfterSelect event which sets the focus, so I don't think it's interfering. The textbox's Enter event is also fired, but for some reason it loses focus again to the tree.
Thanx
no, you cannot keep two controls in focus at the same time. But what you can do is set the focus to the target control in the treeview AfterSelect event
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
textBox1.Focus();
textBox1.SelectAll();
}
then in your textbox leave, save the changes, like so:
private void textBox1_Leave(object sender, EventArgs e)
{
//save changes here
}
this way, everytime you select an item in the treeview, check your textbox for change and save as needed, then you will refocus on the textbox for your next edit
There only can be one element having the focus!
But I have an idea for you that might solve your problem. Assuming you have a window with a TreeView and a TextBox. Set the HideSelection property of the TreeView to false and subscribe the AfterSelect event (like edeperson already answered) like this:
private void OnTreeViewAfterSelect(object sender, TreeViewEventArgs e)
{
textBox1.Text = e.Node.Text;
textBox1.Focus();
}
Then subscribe the KeyDown event of the TextBox and do following in the event method:
private void OnTextBoxKeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.Up) || (e.KeyCode == Keys.Down))
{
treeView1.Focus();
SendKeys.Send(e.KeyCode == Keys.Up ? "{UP}" : "{DOWN}");
}
}
At last subscribe the Leave event of the TextBox and do following in the event method:
private void OnTextBoxLeave(object sender, EventArgs e)
{
if (treeView1.SelectedNode != null)
{
treeView1.SelectedNode.Text = textBox1.Text;
}
}
And, voilá it should work like you expected it...
If you want to focus on it , you can use usercontrol. you can put your textbox on usercontrol and set focus of this textbox on usercontrol using set properties on treeview select.
No you may not, only one control may be in focus at any given time.
See Moonlight's comment for one way to achieve the behavior that you seek.

Can I place the mouse event handler on a separate thread?

Can I put a thread on a mouse event handler?
Calls_Calls.MouseUp += new MouseEventHandler(Calls_Calls_MouseUp);
How to add a thread over this?
I would set up the event handler in the same way, but in the Calls_Calls_MouseUp method you can launch a thread to do the work:
private void Calls_Calls_MouseUp(object sender, MouseEventArgs e)
{
ThreadPool.QueueUserWorkItem(state => {
// do the work here
});
}
However, I typically try to have my event handlers as unaware as possible, just calling some other method, often based on some condition:
private void Calls_Calls_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DoSomething();
}
}
private void DoSomething()
{
ThreadPool.QueueUserWorkItem(state => {
// do the work here
});
}
This gives you the ability to trigger the exact same behavior from something else than the MouseUp event on a certain control (so that you can have the same behavior on a menu item, a toolbar button and perhaps a regular command button). It may also open up the possibility to have unit tests on the functionality (even though that is somewhat trickier with asynchronous code).
you can also use BackgroundWorker for this in case you require any updation on the UI for progress and completion.
Calls_Calls.MouseUp+= new MouseEventHandler(delegate(System.Object o, System.EventArgs e) { new Thread(Calls_Call_MouseUp).Start(); });
should work for you. If you get brackets errors, fix them since I handwrote the code :) :)

Categories

Resources