OK, so I am trying to apply the accounting number format for all textboxes on my Form.
Now, I did some research here and found this post that will help me to set the format.
And then I found another post to apply the format for all textbox controls on the form without adding the format code individually to all controls.
Well, the thing is that the code on the format uses the control name, which will bind it to a single textbox control. I tried the control name (TextoBox) instead, and it also failed.
There is another issue to consider, that even if I manage to get past the above problem, the code from format is an event, named after the control name, so I do not think it will work if I apply it to a class or method and call for it.
While I already do have the solution to what I want, I would like to know if there is a faster way to apply it, which will not add so much lines to my code. Trying to learn how to keep things easier to read, doing less with more. Any advise?
Thanks for reading.
It sounds like you have all the pieces, just need help putting it together. For the ControlName, you can cast the sender object to the control and access its Name property.
void SetProperty(Control ctr)
{
foreach (Control control in ctr.Controls)
{
if (control is TextBox)
{
control.Leave += control_Leave;
}
else
{
if (control.HasChildren)
{
SetProperty(control);
}
}
}
}
void control_Leave(object sender, EventArgs e)
{
var textBox = sender as TextBox;
Double value;
if (Double.TryParse(textBox.Text, out value))
textBox.Text = String.Format(System.Globalization.CultureInfo.CurrentCulture, "{0:C2}", value);
else
textBox.Text = String.Empty;
}
Usage:
SetProperty(this);
Also, from my comment on the OP: If accounting is truly important, I would suggest using the Decimal type instead of Double. Double will be faster, but Decimal is more precise. Figure out which trade off makes sense and make a decision based on that.
Edit per comments:
myTextBox.Leave -= control_Leave
If you know the name of the control, the above will work. You will need to do this after you use SetProperty(this). If you want to handle this inside the SetProperty() method, do a check on control.Name == "myTextBox".
You can subscribe multiple controls event(that use the same args) to the same event handler :
public YourFormConstructor()
{
foreach(var textbox in form.Controls.OfType<TextBox>())
textbox.Leave += FormatCurrencyText;
}
private void FormatCurrencyText(object sender, EventArgs e)
{
var textbox = sender as TextBox;
Double value;
if (Double.TryParse(textbox.Text, out value))
textbox.Text = String.Format(System.Globalization.CultureInfo.CurrentCulture, "{0:C2}", value);
else
textbox.Text = String.Empty;
}
Related
So, not to beat a dead horse, I understand how to data-bind using MVVM, but I am beating my head against the wall on this particular problem.
My Windows Phone app uses Units, like inches, millimeters, feet... etc.
I am trying to make it possible for the end user to change the units at any point in the equation and convert on the spot. So for instance, I have a TextBox entry for the value then to the right I have a another TextBox which has the units.
I have a collection of units:
public class cUnit
{
public string Name {get;set;}
public string Abb {get;set;}
public double Mulitplier {get;set;}
}
So when a user clicks on the Units TextBox, I expand the ListBox and collapse the Panorama. Once a Unit is selected, I collapse the Listbox and show the Panorma.
Here is where the problem is.
In generation one, I used a Case Statement to look at the Name of the TextBox that was clicked on. I then hard-coded the appropriate PropertyValue so that when I received the cUnit back from the ListBox I could update the property in the ViewModel.
I know this is wrong, but I can't figure out a way around it. Keep in mind that I have a lot of opportunities to change units, so I would like to have just one "Change-Unit" method.
Here is some of the "Bad" code:
Got-Focus Method
private void txt_GotFocus(object sender, RoutedEventArgs e) {
tb = (TextBox)sender;
lbUnits.SelectedIndex = -1;
LengthUnits.Visibility = System.Windows.Visibility.Visible;
Panorama.Visibility =System.Windows.Visibility.Collapsed;
}
This is what happens when a unit is selected from the ListView
private void lbUnits_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (tb == null || lbUnits.SelectedIndex == -1) return;
ViewModels.cUnit unit = (ViewModels.cUnit)lbUnits.SelectedItem;
switch (tb.Name)
{
case "txtUnits1":
App.ViewModel.Unit1 = unit;
break;
case "txtUnits2":
App.ViewModel.Unit2 = unit;
break;
etc... (txtUnit53...) you get the picture
}
LengthUnits.Visibility = System.Windows.Visibility.Collapsed;
Panorama.Visibility = System.Windows.Visibility.Visible;
tb = null;
}
I was hoping there is a better way. I am totally willing to re-write this from scratch, since I need to add another 20 or so items to my app.
I tried getting the BindingExpression but once I get it, I still can't seem to find the property to assign the unit to.
Any help would be appreciated. If you would like to see how the OLD app works you can download it from the store. Just search for Key Knife and pick the Calculator.
Ok, after more research this is what I found. I can use GetBindingExpression(TextBox.TextProperty) to get the Expression.
From there I can get the ParentBinding which will then get me to the PropertyPath of the binding.
I used this information to set the Binding of the ListBox.SelectedItem like this:
private void txt_GotFocus(object sender, RoutedEventArgs e)
{
TextBox tb = (TextBox) sender;
BindingExpression BE = tb.GetBindingExpression(TextBox.TextProperty);
Binding B = BE.ParentBinding;
PropertyPath P = B.Path;
Binding NewBinding = new Binding(P.Path.Replace(".Abb", ""));
NewBinding.Mode = BindingMode.TowWay;
lbUnits.SetBinding(ListBox.SelectedItemProperty, NewBinding);
//Hide Panorama
Panorama.Visibility = System.Windows.Visibility.Collapsed;
// Show ListBoxGrid
LengthUnits.Visibility = System.Windows.Visibility.Visible;
}
Now all I have to do on lbUnits.SelectionChanged is reverse the hiding and showing of the Panorama and ListBoxGrid.
Hope this helps someone
I'm trying to create a simple listbox with ObjectListView (WinForm, C#). The goal is to have a single value (a double) and a check box.
I want to be able to edit the double value by Single Click, so here are the relevant lines of code from my MyWindow.Designer.cs file (i've left out the default values for efficiency):
this.olvDepths = new BrightIdeasSoftware.ObjectListView();
this.olvColumn1 = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn()));
...
this.olvDepths.CellEditActivation = BrightIdeasSoftware.ObjectListView.CellEditActivateMode.SingleClick;
this.olvDepths.CheckBoxes = true;
this.olvDepths.CheckedAspectName = "IsDefault";
this.olvDepths.FullRowSelect = true;
//
// olvColumn1
//
this.olvColumn1.AspectName = "Depth";
this.olvColumn1.Text = "";
this.olvColumn1.IsEditable = true;
I then create a list of my class (ShieldingEntry) and use the olvDepths.SetObjects() with the list. My ShieldingEntry class looks like this:
public class ShieldingEntry
{
public double Depth { get; set; }
public bool IsDefault { get; set; }
}
However, when I click the field, it doesn't go into edit mode. I've also tried the DoubleClick, SingleClickAlways, and F2Only modes and they don't work either.
The Checkbox works fine.
************** I have additional information *********************
I've pulled and build the ObjectListView source, so I could step through it.
I put a breakpoint in the OLV StartCellEdit method and it gets called and appears to setup and select the control appropriately. It just never appears...
As I noted in the comments on the answer below, I've got this control on a tabbed dialog, and if I switch to another tab, then back, the control works fine.
What am I missing?
I've used ObjectListView before, and here is what I had to do:
Handle the CellEditStarting event. This event is raised when the cell goes into edit mode. Since OLV doesn't really have built-in editors, you have to make your own. Then handle the CellEditFinishing event to validate the data before putting it back into your model.
So first, handling the CellEditStarting event:
private void objlv_CellEditStarting(object sender, CellEditEventArgs e)
{
//e.Column.AspectName gives the model column name of the editing column
if (e.Column.AspectName == "DoubleValue")
{
NumericUpDown nud = new NumericUpDown();
nud.MinValue = 0.0;
nud.MaxValue = 1000.0;
nud.Value = (double)e.Value;
e.Control = nud;
}
}
This creates your editing control. If you want to make sure the size is right, you can set the size of the control (in this case a NumericUpDown) to the cell bounds using e.CellBounds from the event object.
This will show the editor when you click in the cell. Then you can handle the editor finished event to validate the data:
private void objlv_CellEditFinishing(object sender, CellEditEventArgs e)
{
if (e.Column.AspectName == "DoubleValue")
{
//Here you can verify data, if the data is wrong, call
if ((double)e.NewValue > 10000.0)
e.Cancel = true;
}
}
I don't think handling it is required, but its good practice to validate data from the user.
The editing control in the CellEditStarting event can be any control, even a user defined one. I've used a lot of user defined controls (like textboxes with browse buttons) in the cell editor.
[Edit]
I uploaded an example here dropbox link that seems to work. Might not be in the exact view as needed, but seems to do the job.
For anyone else with this problem. I had it specifically when trying to edit a 'null' value in a decimal? on the OLV on a tab page. Solution for me was to set UseCustomSelectionColors to 'False'. I didn't look elsewhere to see if it was reported as a bug. Seems like a bug.
Say I have the elements with the ID's of "Input1", "Input2" and "Input3".
Is there a way to loop through them rather then having to write:
Input1.Value = 1;
Input2.Value = 1;
Input3.Value = 1;
in jquery you can just refrence an element like $('#Input'+i) and loop through i, something similar would be very useful in ASP code behind.
Edit: Duh, I searched again for finding all "x" controls on page and came up with the following source code:
foreach(Control c in Page.Controls)
{
if (c is TextBox)
{
// Do whatever you want to do with your textbox.
}
}
Kind of ... based on your example naming scheme you can do something like the following:
private void Button1_Click(object sender, EventArgs MyEventArgs)
{
string controlName = TextBox
for(int i=1;i<4;i++)
{
// Find control on page.
Control myControl1 = FindControl(controlName+i);
if(myControl1!=null)
{
// Get control's parent.
Control myControl2 = myControl1.Parent;
Response.Write("Parent of the text box is : " + myControl2.ID);
}
else
{
Response.Write("Control not found");
}
}
}
This will let you loop through numerically named controls but otherwise it is somewhat clunky.
If you know the parent container you can loop though its .Controls() property. If you start at the Page level and work recursively, you can eventually reach all controls on the page.
See the answer from this question for more details.
I like to keep things strongly typed, so I store them in a list. This makes the code more resilient to refactoring and there's no need to cast. It takes a slight bit more upfront work to put all your controls into the list, but to me it's often worth it.
I'm not sure what type your controls are, so I'm going to pretend they're of type Input.
var InputControls = new List<Input>(){Input1, Input2, Input3};
foreach(var input in InputControls)
{
input.Value = 1;
}
I have custom ComboBox, where DropDownStyle = ComboBoxStyle.DropDown;.DropDown style is set because I want to set the Text property of the ComboBox to something outside the list of values. Everything works good, except that ComboBox is highlighting the text when it's left and when I click on the combobox editing is avaible. How can I cope with this?
To illustrate:
First Picture is where everything looks good, second is the highlight situation, third editing is on.
Try un-selecting the text after the DropDown closes:
void comboBox1_DropDownClosed(object sender, EventArgs e) {
this.BeginInvoke(new Action(() => { comboBox1.Select(0, 0); }));
}
If you are referring to disabling the highlighting and editing, then you might want to consider setting the DropdownStyle property to DropdownList.
yourComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
Tricky problem to solve. It seems to be from the Resize event. There are a lot of solutions that do something similar to this, but none that I've seen worked for me until I tried this. (This is a solution that does not require inheritance from ComboBox; inheriting is probably a much more straight forward solution, but requires you to always use your inherited class and never the actual ComboBox class.)
comboBox.Resize += (s, e) => {
if (!comboBox.IsHandleCreated)
return; // avoid possible exception
comboBox.BeginInvoke(new Action(() => comboBox.SelectionLength = 0));
};
Set the selection length to zero to get rid of the highlight, but when? Other examples do it in other places, but the problem seems to be specifically caused by Resize, so doing it after Resize fixes it consistently, at least for me. (Can still see it flicker when you resize the window though, but it always ends up ok.)
BeginInvoke ensures that it happens sufficiently after Resize to work, and the check for IsHandleCreated prevents it from being called before the handle is created, in which case BeginInvoke would throw an exception.
This slightly more complex version includes some checks to prevent a focused control from losing highlight, since it actually should have it. It also doesn't fire if the parent doesn't exist yet, or if the parent does not have an active control yet, both signs that things are too early.
comboBox.Resize += (s, e) => {
if (!comboBox.IsHandleCreated)
return;
comboBox.BeginInvoke(new Action(() => {
var parent = comboBox.FindForm();
if (parent == null)
return;
if (parent.ActiveControl == null)
return;
if (parent.ActiveControl == comboBox)
return;
comboBox.SelectionLength = 0;
}));
};
I tried to make a version that would 'preserve' the selection length rather than always set it to zero, but I couldn't get it to synchronize properly. Many Resize events can fire before the BeginInvoke delegates start to fire, so the preserved value will always be overwritten by the broken one. I tried saving them all in a Queue or Stack, but in both cases, I was unable to reverse the ordering (not really sure why, since that makes no sense).
To solve the same I have tried almost EVERYTHING:
setting the DropdownStyle property to DropdownList
this.BeginInvoke(new Action(() => { comboBox1.Select(0, 0); }));
combobox1.SelectionLength = 0;
changing comboBox.TabIndex
Not tried SendKeys.Send("{ESC}"); because it is not a reliable solution
Nothing helped.
The only stable and working solution was to move a focus on another Label control:
label.Focus();
You could also hide that label.
I know this post is old but recently I have the same problem with combobox.
Situation : I have an editable combobox which propose complete words when user write some letters.
But when I want to type a letter, combobox auto highlight the text and the next letter auto replace the previous.
Solution : I use a textbox to avoid any highlight like that:
<ComboBox IsTextSearchEnabled="False" IsEditable="True" x:Name="CMB_ClientName"/>
<TextBox Text="{Binding ElementName=CMB_ClientName, Path=Text}" TextChanged="ComboBoxChange" x:Name="TXT_ClientName"/>
And I generate the textbox TextChanged event :
private void ComboBoxChange(object sender, TextChangedEventArgs e)
{
//Clear ComboBox items
CMB_ClientName.Items.Clear();
//Auto Open DropDownList
CMB_ClientName.IsDropDownOpen = true;
//Get data from database (use entity framework 6.x)
dbEntity.Client.Load();
//Attribute Data to variable
var clients = dbEntity.Client.Local;
foreach (Client client in clients)
{
//If data begin with the texbox text, the data is add to the combobox items list.
if (client.Nom.ToLower().StartsWith(TXT_NomClient.Text.ToLower()))
{
CMB_ClientName.Items.Add(client.Nom);
}
}
}
I know this solution isn't realy beautifull, but it is for me the easiest solution to avoid highlight text and all the solutions in this post don't work for me.
I hope this solution will be helpfull, thanks for reading.
Math.
Ps: My apologies, my English is not very good. I hope you will understand me correctly.
Nothing worked for me ( I want the form to load with no highlighting in any combobox) until I set the combobox property TabStop to false. This meant that one of my buttons took the tab highlight which I didn't like so I set them all to false for start up and adjusted them programatically as needed.
I know this is an old thread, but my solution is similar to that of the others, but relies on the Form.ResizeEnd event. In its event handler, I iterate through the ComboBoxes and set ComboBox.SelectionLength to 0.
private void Form_ResizeEnd(object sender, EventArgs e)
{
foreach(ComboBox comboBox in parentControl.Controls.OfType<ComboBox>
{
comboBox.SelectionLength = 0;
}
}
This is what worked for me:
Set DrawMode to OwnerDrawFixed
Set cbxSubsystems.DrawItem event to the function below
private void cbxSubsystems_DrawItem(object sender, DrawItemEventArgs e)
{
Color BgClr;
Color TxClr;
if( (e.State & DrawItemState.ComboBoxEdit) == DrawItemState.ComboBoxEdit )
{
// Do not highlight main display
BgClr = cbxSubsystems.BackColor;
TxClr = cbxSubsystems.ForeColor;
}
else
{
BgClr = e.BackColor;
TxClr = e.ForeColor;
}
e.Graphics.FillRectangle(new SolidBrush(BgClr), e.Bounds);
TextRenderer.DrawText(e.Graphics, cbxSubsystems.Items[e.Index].ToString(), e.Font, e.Bounds,
TxClr, BgClr, TextFormatFlags.Left | TextFormatFlags.VerticalCenter );
}
I would like to the ToolTip always be the same as the ASP TextBox's Text. Of course I can write
AnyTextBox.Text = "any text";
AnyTextBox.ToolTip = "any text";
but I do not want to duplicate hundreds of assignment statements.
I also could write change event handlers for the Text property, but I do not want to write dozens of event handlers just for this (if there is a more elegant solution)
Is there? Something like this:
<asp:TextBox ID="AnyTextBox" runat="server" ToolTip="binding magic goes here, but how?">
Thx in advance
You could write your own custom control which inherits from TextBox? I used the Text property to set the tooltip, but you can do it the other way around if you want.
Control:
public class TooltipTextBox : TextBox {
public new string Text {
get { return base.Text; }
set
{
base.Text = value;
this.ToolTip = value;
}
}
}
Markup:
<my:TooltipTextBox ID="AnyTextBox" runat="server" Text="binding magic goes here">
As far as i know there is no such automatism. For what it's worth, maybe you can use PreRender:
protected void Page_PreRender(Object sender, EventArgs e)
{
var allTextControlsWithTooltips = new List<WebControl>();
var stack = new Stack<Control>(this.Controls.Cast<Control>());
while (stack.Count > 0)
{
Control currentControl = stack.Pop();
if (currentControl is WebControl && currentControl is ITextControl)
allTextControlsWithTooltips.Add((WebControl)currentControl);
foreach (Control control in currentControl.Controls)
stack.Push(control);
}
foreach (var txt in allTextControlsWithTooltips)
txt.ToolTip = ((ITextControl)txt).Text;
}
You could also use a UserControl which handles this event, then you just need to put it on all of the pages that should behave in this way. Or you could let all pages inherit from one base page.
I think using a JavaScript event handler will be your easiest solution. You don't need to write hundreds of event handlers though. Just write one and then use that same event handler for all your text boxes!
<asp:TextBox ID="AnyTextBox" runat="server" onchange="setTooltip(this)" />
And then the script would be
function setTooltip(textbox) {
textbox.title = textbox.value;
}
That's it! Set that onchange event for all your Textboxes who you want to have this tooltip behavior.
You can do this in the TextChanged event of the textbox :
<asp:TextBox ID="AnyTextBox" runat="server" TextChanged="AnyTextBoxTextChanged">
protected void AnyTextBoxTextChanged(object sender, EventArgs e)
{
this.AnyTextBox.Tooltip = this.AnyTextBox.Text;
}
That depends if you are looking for "live update" of tooltip = i.e. do you want to change the tooltip when the user changes the text on website? Then use "onchange" event of the input and JS function that would change its "title" attribute on each event call.
Or you want to ease of your server-side work and do not want to specify tooltip and text for each item, then go with custom control way (and I recommend RGraham code).
Or match both methods and use custom control that would also provide JS "refresh" code :-)
Try using jquery
$(function () {
var maybe = true;
var text = $('.myTextBox').val();
if (maybe) {
$('.myTextBox').attr('title', text);
}
});