I have a method in a silverlight application. I want to start calling this method when an event occurs (mouse move), and continue to call this method every 1 second until a simple boolean condition changes. Is this possible ? I can't work out how to get the rx to generate multiple 'events' from the single event
Here's a method that I used to do this:
var isChecked = from f in Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
h => new RoutedEventHandler(h),
h => checkBox1.Checked += h,
h => checkBox1.Checked -= h)
where checkBox1.IsChecked == true
select new Unit();
var xs = from click in Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
h => new RoutedEventHandler(h),
h => button1.Click += h,
h => button1.Click -= h)
from ping in Observable.Interval(TimeSpan.FromSeconds(1.0)).TakeUntil(isChecked)
select ping;
_subscription = xs.ObserveOnDispatcher().Subscribe(v => label1.Content = v.ToString());
I created a button to begin the events on click. I created a check box that will stop the events when it is checked. This may not be exactly what you want but the events fire as you asked and you should be able to make modifications to suit from here.
Related
Afternoon,
I have a search button which searches the list of the users is either by IDnumber,Username or department.
I have 2 list view which the users clicks and it load the selected user to the second list view. now the problem is after u clicked users from listview1 and u went to type ID,Username or select department and click search...It clears all the users you selected and bring new users u where searching.
I want to be able to select the users and be able to search without losing my current selected users from the listview
my code ;
//search button
private void Searchbutton_Click(object sender, EventArgs e)
{
try
{
listView1.Items.Clear();
string sID = string.IsNullOrEmpty(txtUserID.Text) ? null : txtUserID.Text;
string sDepartment;
if (cboDepartment.SelectedItem != null)
{
sDepartment = cboDepartment.SelectedItem.ToString();
}
else
{
sDepartment = "";
}
oConnection = new SqlConnection(_connectionString);
oCommand = new SqlCommand(#"Select us.sFieldValue5, u.sUserName, d.sName, TB_USER_CUSTOMINFO.sFieldValue2
From TB_USER u(nolock)
left join [TB_USER_CUSTOMINFO] us(nolock) on us.nUserIdn = u.nUserIdn
left join TB_USER_CUSTOMINFO on u.nUserIdn = TB_USER_CUSTOMINFO.nUserIdn
left join TB_USER_DEPT d(nolock) on d.nDepartmentIdn = u.nDepartmentIdn
where u.sUserName like '%'+ISNULL(#UserName,u.sUserName)+'%'
and us.sFieldValue5 = isnull(#IDNumber,us.sFieldValue5)
and d.sDepartment like '%'+isnull(#Department,d.sDepartment)+'%'", oConnection);
oCommand.Parameters.AddWithValue("UserName", string.IsNullOrEmpty(txtUsername.Text) ? DBNull.Value : (object)txtUsername.Text);
oCommand.Parameters.AddWithValue("IDNumber", string.IsNullOrEmpty(txtUserID.Text) ? DBNull.Value : (object)txtUserID.Text);
oCommand.Parameters.AddWithValue("Department", string.IsNullOrEmpty(sDepartment) ? DBNull.Value : (object)sDepartment);
oConnection.Open();
oDataset = new System.Data.DataSet();
SqlDataReader oReader = oCommand.ExecuteReader();
while (oReader.Read())
{
ListViewItem item1 = new ListViewItem(oReader[1].ToString());
item1.SubItems.Add(oReader[2].ToString());
item1.SubItems.Add(oReader[3].ToString());
item1.SubItems.Add(oReader[0].ToString());
listView1.Items.AddRange(new ListViewItem[] {item1});
}
oReader.Close();
oConnection.Close();
}
//selected users
private void listView1_ItemChecked(object sender, ItemCheckedEventArgs e)
{
if (e.Item.Checked == true)
{
ListViewItem l = listView1.Items[e.Item.Index];
int i = l.SubItems.Count;
string sValue1 = l.SubItems[1].Text;
string sValue2 = l.SubItems[2].Text;
string sValue3 = l.SubItems[3].Text;
ListViewItem item1 = new ListViewItem(l.SubItems[0].Text.ToString());
item1.SubItems.Add(sValue3);
item1.SubItems.Add(sValue2);
item1.SubItems.Add(sValue1);
listView2.Items.AddRange(new ListViewItem[] { (ListViewItem)l.Clone() });
}
else if (e.Item.Checked == false)
{
ListViewItem l = listView1.Items[e.Item.Index];
foreach (ListViewItem i in listView2.Items)
{
if (i.SubItems[0].Text == l.SubItems[0].Text.ToString())
{
listView2.Items.Remove(i);
}
}
}
}
ListView remember which ListViewItems were checked. As soon as you say Items.Clear(), all that knowledge is lost.
To solve your problem, you will need to remember which users were checked, do your refresh, then go through and mark each user as checked again.
To do those steps, you really need to separate your model from your view. Create a User model object to hold the actual data, then populate your ListView with data from your model. When the user does another search, update or refresh your model objects, then rebuild your view.
Doing this model/view separation is a little more work up front, but future generations of maintenance programmers will bless your name.
BTW, ObjectListView -- an open source wrapper around a .NET ListView -- makes creating a fully functional ListView from a list of model objects trivially easy.
There is need to add to the .net windows application measurement of the responsiveness and load time for the windows forms.
What is correct way to measure winform response and load time?
I'm not sure how you would measure responsiveness but for load time you can log the StopWatch elapssed milliseconds of the successive events that are raised when a Form loads. Based on Order of Events in Windows Forms on MSDN we learn the events raised (in order) are:
Control.HandleCreated
Control.BindingContextChanged
Form.Load
Control.VisibleChanged
Form.Activated
Form.Shown
You can hookup these events in the constructor of a form and have a simple Log method to handle the data collection. Be aware that collecting the data also takes time.
public partial class Form1 : Form
{
Stopwatch timing = new Stopwatch();
// naive data collection
void Log(string stage)
{
Trace.WriteLine(String.Format("{0} = {1}", timing.ElapsedMilliseconds, stage));
}
public Form1()
{
timing.Start();
Log("Constructor Start");
InitializeComponent(); // adding all designer generated stuff
Log("Constructor - Initialized");
// hookup events
this.HandleCreated += (s, e) => Log("HandleCreated");
this.BindingContextChanged += (s,e)=> Log("BindingContextChanged");
this.Load += (s, e) => Log("Load");
this.Activated += (s, e) => Log("Activated");
this.Shown += (s, e) => Log("Shown"); ;
Log("Constructor End");
}
}
On my laptop with .Net 4.0 in Debug the timings are as follows:
0 = Constructor Start
19 = Constructor - Initialized
20 = Constructor End
22 = HandleCreated
24 = BindingContextChanged
25 = Load
30 = Activated
31 = Shown
I would like to override the text displayed when an item is added to a checked list box. Right now it is using obj.ToString(), but I want to append some text, without changing the objects ToString method. I have seen examples of handling the DrawItem event for ListBoxs, but when I try to implement them, my event handler is not called. I have noted that the Winforms designer does not seem to allow me to assign a handler for the DrawItem event. Being stubborn, I just added the code myself
listbox1.DrawMode = DrawMode.OwnerDrawVariable;
listbox1.DrawItem += listbox1_DrawItem;
Am I trying to do the impossible?
Not impossible, but incredibly difficult. What you suggest will not work, note the meta-data in class CheckedListBox for method DrawItem:
// Summary:
// Occurs when a visual aspect of an owner-drawn System.Windows.Forms.CheckedListBox
// changes. This event is not relevant to this class.
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public event DrawItemEventHandler DrawItem;
Therefore, your only option is to derive your own class from CheckedListBox, and in my limited testing, this will be a long road. You can handle the drawing simply enough, as such:
public class CustomCheckedListBox : CheckedListBox
{
protected override void OnDrawItem(DrawItemEventArgs e)
{
String s = Items[e.Index].ToString();
s += "APPEND"; //do what you like to the text
CheckBoxState state = GetCheckBoxState(e.State); // <---problem
Size glyphSize = CheckBoxRenderer.GetGlyphSize(e.Graphics, state);
CheckBoxRenderer.DrawCheckBox(
e.Graphics,
e.Bounds.Location,
new Rectangle(
new Point(e.Bounds.X + glyphSize.Width, e.Bounds.Y),
new Size(e.Bounds.Width - glyphSize.Width, e.Bounds.Height)),
s,
this.Font,
false,
state);
}
}
Note the method GetCheckBoxState(). What you get in the DrawItemEventArgs is a DrawItemState, not the CheckBoxState you need, so you have to translate, and that's where things started to go downhill for me.
Soldier on, if you like, this should get you started. But I think it'll be a messy, long road.
I continued the work in DonBoitnotts answer.
The "GetCheckBoxState" is implemented using a very limited set with only two states.
var state = GetItemChecked(e.Index) ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal;
Vertically aligned the checkbox and left aligned the text.
var b = e.Bounds;
int checkPad = (b.Height - glyphSize.Height) / 2;
CheckBoxRenderer.DrawCheckBox(g, new Point(b.X + checkPad, b.Y + checkPad),
new Rectangle(
new Point(b.X + b.Height, b.Y),
new Size(b.Width - b.Height, b.Height)),
text, this.Font, TextFormatFlags.Left, false, state);
I am trying to implement a Search as you type functionality ( like the one in the search in the default email app ) - I have a listbox with say 50 items - each item bound to a class object which has string fields ... I wish to search and display items which have the text in the search box in one of their string fields - this as the user keys in to the textbox ... tried a couple of approaches -->
1 >> Using a CollectionViewSource
- Bound a CollectionViewSource to All the items from the DB
- Bound the List Box to a CollectionViewSource
- Setting the filter property of the CollectionViewSource - to whose function which searchs for the text in the Search box in the items and set the e.Accepted - on every keyup event
- Filtering works fine but its slow with 50 items :( - guess cos of filter taking each item and checking if to set e.Accepted property to true
.... One DB call on load but seems to be a lot of processing to decide which element to disply in the filer by the CollectionViewSource
2 >> Filter # DB level
- on keyup - sending the text in the search box to the ViewModel where a function returns an ObservableCollection of objects which has the search string
- ObservableCollection is bound to the listbox
.... Not much processing # the top layer but multiple DB calls on each Keypress - still slow but just a tad faster than Approach One
Is there any other approch you would recommend ? or any suggestions to further optimize the above mentioned approaches? - any tweak to give smooth functioning for the search?
First time into mobile dev :) ... Thanx in advance :)
You can optimize the search process further by delaying the search action by x milliseconds to allow the user to continue the writing of the search criteria. This way, each new typed char will delay the search action by xxx milliseconds till the last char where the action is triggered, you'll get a better performance using just one call instead of say 10 calls. Technically speaking, you can achieve this by using a Timer class.
Here you'll find a sample source code example that shows u how to implement this.
private void txtSearchCriteria_TextChanged(object sender, TextChangedEventArgs e)
{
if (txtSearchCriteria.Text == "Search ...")
return;
if (this.deferredAction == null)
{
this.deferredAction = DeferredAction.Create(() => ApplySearchCriteria());
}
// Defer applying search criteria until time has elapsed.
this.deferredAction.Defer(TimeSpan.FromMilliseconds(250));
}
private DeferredAction deferredAction;
private class DeferredAction
{
public static DeferredAction Create(Action action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
return new DeferredAction(action);
}
private Timer timer;
private DeferredAction(Action action)
{
this.timer = new Timer(new TimerCallback(delegate
{
Deployment.Current.Dispatcher.BeginInvoke(action);
}));
}
public void Defer(TimeSpan delay)
{
// Fire action when time elapses (with no subsequent calls).
this.timer.Change(delay, TimeSpan.FromMilliseconds(-1));
}
}
public void ApplySearchCriteria()
{
ICollectionView dataView = this.ViewSource.View;
string criteria = this.txtSearchCriteria.Text;
string lowerCriteria = criteria.ToLower();
using (dataView.DeferRefresh())
{
Func<object, bool> filter = word =>
{
bool result = word.ToString().ToLower().StartsWith(lowerCriteria);
return result;
};
dataView.Filter = l => { return filter.Invoke(l); };
}
this.lstWords.ItemsSource = dataView;
if (this.lstWords.Items.Count != 0)
{
this.lblError.Visibility = Visibility.Collapsed;
}
else
{
this.lblError.Visibility = Visibility.Visible;
}
}
I have several radio buttons that are dynamically populated on a form and I have set a click event on the dynamically created radio buttons. On click i get a returned value as follows through debugging (eg) "sender { Text = "this is answer one" + Checked = "True"} using code as follows:
//Radio button click:
void Form1_Click(object sender, EventArgs e)
{
RadioButton rb = sender as RadioButton;
string radioButtonValue = rb.Text;
if (radioButtonValue != String.Empty)
{
}
}
The debug values are returned via "RadioButton rb = sender as RadioButton;" - the diffrent radio buttons text is set via a dataset that I call in a local dataset that loops through the dataset and and sets the radio button text accordingly (eg):
for (int i = 0; i < _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows.Count; i++)
{
radioButtons[i] = new RadioButton();
radioButtons[i].AutoCheck = true;
radioButtons[i].Text = _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows[i]["tbl_QuestionnaireAnswer_Description"].ToString();
radioButtons[i].Location = new System.Drawing.Point(60, 20 + i * 20);
radioButtons[i].Click += new EventHandler(Form1_Click);
panel.Controls.Add(radioButtons[i]);
}
So: wat id like to know is on the radio button click (Form1_Click) event is it possible to return the primary key of the of the selected radio button that I choose and not just the sender { Text = "this is answer one" + Checked = "True"} as I would like to use the primarykey in that dataset to write back to my Database.
Thanks in advance.
Kind regards
geo
Most winforms controls contain the Tag property that is used to contain custom user data in the control. You can read more at: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.tag.aspx
So, your solution should be simpler and more concise like this:
for (int i = 0; i < _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows.Count; i++)
{
radioButtons[i] = new RadioButton();
radioButtons[i].AutoCheck = true;
radioButtons[i].Location = new System.Drawing.Point(60, 20 + i * 20);
radioButtons[i].Tag = _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows[i];
radioButtons[i].Click += new EventHandler(Form1_Click);
panel.Controls.Add(radioButtons[i]);
}
This includes a relevant datarow in the radiobutton. The next thing is to get any data from it you need:
//Radio button click:
void Form1_Click(object sender, EventArgs e)
{
RadioButton radioButton = sender as RadioButton;
if (radioButton == null)
return;
DataRow row = radioButton.Tag as DataRow;
if (row == null)
return;
/* Post any processing here. e.g.
MessageBox.Show(row["ID"].ToString());
*/
}
This way you have all the data and it's strongly typed, which is a good thing.