C#: TextChanged event of a Control not firing on "assign" - c#

Ok, here's the deal.
I have a graph, that "listens" to some labels' textfields, and graphs their values. It does this by adding the values on the TextChanged event.
The problem:
TextChanged only fires when the text has actually changed (obviously), and not when it has been assigned a new value.
What I need:
A way to detect if the Text field of label has been updated (assigned to), and all I have to work with is a reference to the Control (ie the Label).
I realize TextChanged wasn't designed for this, which is why I'm wondering if any of you guys have encountered a similar problem, and found a solution to it.

The reason that your TextChanged event handler is not invoked in initial assignment of the text is that it is attached after the first text has been assigned (the designer seems to do things in this order by default). I would do like this:
TextChanged calls another method (UpdateGraph)
UpdateGraph collects necessary data and updates the graph
Call UpdateGraph as the last thing done when loading the form
That will make sure that the graph is updated with the initial values. It is important that this call happens after the call to InitializeComponent.

It is fairly common practice in "setters" to ignore trivial changes, for example:
public int Foo {
get {return foo;}
set {
if(foo != value) {
foo = value;
OnFooChanged();
}
}
}
If Text is behaving like this, and you are relying on all updates causing an event, then it may not work as you want. I would probably try to find another way to do what you want; perhaps using an intermediate object that passes the values through.

You could create your own control that inherits from that control and create your own Text property that will fire an event when assigned a new value.

Related

Public static variables

I'm using a public static variable in C# Windows forms application. I have two files as Audits.cs and Findings.cs. I have created a public static variable as F_Status in Audits.cs file and made it to assign to the value '1' when an item is selected in a listView. I'm going to use this variable in Findings.cs file in an if statement. My coding in the Findings.cs file is as follows.
if (Audits.F_Status==1)
{
// Do something
}
I have made some break points and tested the coding. In Audits.cs file the variable get assigned to the value '1' and however when it come to the if statement in Findings.cs file the value of the F_Status become '0'. I cannot understand why? If anyone can help me it will be great.
looks like the value is set somewhere else. To find out where this happens, implement the variable as property and set a break-point on it. Of course, don't use an auto property as this wont hit the break point
My guess is that you set F_Status = 1 inside a handler for event ListView.ItemSelectionChanged. ListView raises the event multiple times when the selected item changes: probably the last of these indicates unselected for the previously selected item.
MSDN's reference ListView.ItemSelectionChanged includes example code to debug the event behaviour. But the example calls MessageBox.Show which to me defeats the purpose of analyzing an event's behaviour - when it's a window event. I'd add at the top of the file:
using System.Diagnostics;
And inside the event handler add appropriate calls to Trace.WriteLine, to see how the value of IsSelected changes.
As a commenter noted, there are better designs for telling form B that an item on form A's ListView is selected. The public static variable in form A is undesirable because form B can change the value, which is probably not what you want, and often leads to disaster. There are lots of examples on the web for designing interaction between forms - using a structured programming approach.

TextBox TextChanged Event Problems

I'm using a basic TextBox that is bound to an object. Basically, what I want to do is call a method every time the text in the box is edited and the user de-selects the box or when the underlying bound data is edited. What I am using right now is the TextChanged event, but this has a few problems:
It is called when the TextBox is first created, and I don't want this.
It is called every time a new character is added, and I only want it called when the underlying bound data is changed (which seems to be whenever focus shifts from the box).
How can I accomplish this?
EDIT: I've tried several other TextBox properties like Get/LostFocus but they never seem to fire.
Also, I don't want to put this method call in the Setter of the Property, because the underlying data is something that is logically separate from the UI of this project and I don't want any method calls that relate to doing computations for the UI.
The event LostFocus fires when the focus is shifted from the current element. I tried it and its working fine.
As jods says, the best way to bind your TextBox's Text to ViewModel's property. The Code are:
View:
<TextBox x:Name="TextBox1" Text="{Binding Path=Text1,Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
ViewModel:
public string Text1
{
get { return _text1; }
set
{
_text1 = value;
RaisePropertyChanged("Text1");
}
}
View code behind:
private void ViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Text1")
{
//Call UI related method...
}
}
In this way, it satisfy your two conditions:
1. Every time when you edit TextBox and lose the focus, Setter of Text1 will be called and ViewModel will raise PropertyChanged event.
2. When underlying Text1 is changed. Text1 will also raise the event so View can know it.
Also it can avoid your two concerns:
1. In the first time binding, only getter of Text1 is called. No event is raised.
2. Setter of Text1 is only called after TextBox is lost focus.
every time the text in the box is edited and the user de-selects the box
Hmmm AFAIK it's a standard behaviour of TextBox if you bind text like that: Text={Binding Property}
when the underlying bound data is edited
You can provide this functionality inside setter of your property.
Best design is to listen for changes in the underlying bound property. You can do that without changing the setter if you use a DependencyProperty or if your object implements INotifyPropertyChanged.
When the underlying property changes (LostFocus by default, or each char at a time) is a binding option.
If you don't want to follow my advice of listenning for changes in your (view-)model, you could subscribe to GotFocus and LostFocus events. Save the current value when you get focus, compare with current value when you lose it. If it's different -> do what it is you want to do.
I am not sure what you are finally trying to achieve but I am going to take a guess at this. If you are following an MVVM pattern then, then it seems like you can achieve what you want by using the updateSourceTrigger property of the binding. If you are not using MVVM then you might what to take a look at using MVVM

TwoWay binding is not really Two Way?

I have a two way binding on a string dependency property to the Text of a TextBox.
The binding looks like this:
Text="{Binding MyValue, Mode=TwoWay}"
I have some code that fires in OnKeyUp (in an attached property) that sets MyValue. But rather than taking my value and applying it to the Text property, it is going the other way around.
Here are the sequence of events:
The user enters a string of text that looks like this: 0299900650
The user presses enter.
In my on key up I set MyValue to 2999 and move to the focus to the next field.
The setter for MyValue fires and does a NotifiyPropertyChanged with 2999
The LostFocus fires.
The setter for MyValue fires and does a NotifiyPropertyChanged with 0299900650.
It seems to me that my value is not making it back to "TextBox.Text" somehow. When I loose focus the TextBox is updating the value of the string with what it has in the Text property (the unchanged value because my change did not get back.)
Is there some WPF magic I am not aware of here?
NOTE: I have double checked my bindings. (Besides they work from the UI so I imagine they are correct going to the UI.)
NOTE II: When I say the "user enters a string", it is really a scanned barcode. But since I am using a keyboard wedge, it is as if it was typed in. (However, the whole point of setting the value is because I am doing something different if the user scans as apposed to typing.)
UPDATE: I found this was due to another property having a side effect. I was able to fix the problem.
You simply jump into the concurency conflict on WPF binding messaging.
To prove that, do the following:
remove your OnKeyUp even handler
and do the same you did. On Enter click binding mechanism fires and sets your code behind property.
In case when you make on KeyUp, you new value 2999 is surpressed by the binding after.
To manage this correctly make use of Converter and get rid of OnKeyDown even subscription.
I found this was due to another property having a side effect. I was able to fix the problem by fixing that side effect.

Controlling event-driven navigation in a WPF application

I think the title for this question is probably wrong, but I'm not sure quite how to phrase it. I have a C# 4.0 (VS2010) WPF application.
This application consists of a single window with a header including the basics (logos, captions, etc) and a set of navigation buttons (back, retry, next, etc). The rest of the window is comprised of a listbox that is populated with one or more usercontrols based on what mode the app is currently in.
The way the code is currently written when the mode changes the listbox is cleared, all new user controls are added, and the buttons are set to their required state. This is fine for the initial state of each window mode but I'm having trouble deciding a good approach to update the navigation buttons as the contents of the controls change.
For example one screen is a configuration screen and there are three user controls contained within the listbox. These controls are custom classes that inherit from UserControl. Additionally they implement an interface that defines a method 'bool Validate' which determines if the control has been completely filled out.
This same scenario could apply to lots of other situations but this is a generic use case that is pretty straightforward to understand. When the screen initially loads the 'Next' button, whose visibility is controled by the parent window, is visible but disabled as the child controls can't possibly yet be valid. At some point as the user fills out arbitrary data within one or more controls each one would return true if its Validate method was called.
At the point where all controls are valid, the next button would then become enabled. Fairly straightforward design.
The problem is each control doesn't know what screen it is on, and this is by design. I don't want the controls having to be aware of each other and updating a button status in the parent window. I also don't want the parent window to run a polling thread to call Validate every second because in some cases the validation could be complex.
I'm thinking that the change event of each control within the UserControl (text boxes, radio buttons, etc) would all call a trigger a private validate event and this would set some public property on the interface or class.
f I can do that is there a way for the parent window to respond in an event-driven manner to the change of that property? I'm not looking to do this in WPF, doing this in C# code is preferable as I don't want to get into the complexity of WPF quite yet. I'm just not sure, other than constant polling, how to tell when every control's 'IsValid' property will have synchronized all to 'true', if that is even a good approach.
EDIT:
Okay, here is another way to ask the question. I have a List of something (in this case a list of an interface) and want to be able to respond to a public property change on each item in the list so I can take an action when all items are (bool in this case) true. The above explains the use case, but this is a more generic version of the question.
EDIT:
#Vincent "you might do it in an even simpler way with a custom "ValidatedChanged()" event that you can hook in the same way."
It turns out that this is really what I was looking for. The property notification approach seems to be more for ease of use with data-bound controls. I read a lot of posts on this site about how to implement that but it really wasn't what I wanted. I just wanted my objects to notify that an event occured, which happened to be a property change, but that is beside the point. I found documentation on implementing an event in an interface and I have it working now. Thanks for pointing me in the right direction and helping me realize what is really is that I needed.
So you have a ListBox which contains all your controls, and when all controls are validated, the Next button should be enabled ?
If so, when one of your control validates, you might search all sons of the ListBox to check them for validation, using VisualTreeHelper.GetChildren to get them all.
If you don't want / can't have a handle on the ListView, you might find it by searching up the visual tree starting from the control that just validated.
Each 'Validated' event of each control would be handled by a 'CheckIfAllValidated' event handler, and when all are validated, you could raise a 'AllValidated' events that would be handled by the button (and maybe some other controls as well) to enable it.
Edit : I understood that you did not want each component to know about their children, but notice that even the quite common PropertyChanged event has a 'sender' fields that tells who did raise the event. So any listener of a PropertyChanged on, say, the 'validated' property, can go up the visual tree, stop when it encounters a ListView, then search downstairs if all control that have a validated property do have this property set to true...
Edit 2 :
To be more clear about how to do it, either in your window new or on the window loaded event
or maybe on the ContentRendered Event, depending on how your controls are loaded, you
might use once that code to hook a handler to all your controls :
For Each ThisControl In MainListView.
Dim ThisControlType = ThisControl.GetType
Dim ThisControlPropertyChangedEvent = ThisControlType.GetEvent("PropertyChanged")
' you might wanna check here if event is not null / nothing
ThisControlPropertyChangedEvent.AddEventHandler(ThisControl, New PropertyChangedEventHandler(AddressOf APropChanged))
Next
and you write the APropChanged somehow like that :
Public Sub APropChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
If e.PropertyName = "Validated" Then
Dim ValidatedForAll = True
For Each ThisControl In MainListView.Items
Dim ThisControlType = ThisControl.GetType
Dim ThisControlValidatedProperty = ThisControlType.GetProperty("Validated")
'you might wanna check for non null here
If Not ThisControlValidatedProperty.GetValue(ThisControl, Nothing) Then
ValidatedForAll = False
Exit For
End If
Next
If ValidatedForAll Then
MessageBox.Show("Yeeppee") ' you might send an event instead.
End If
End If
End Sub
Edit 3 : you might do it in an even simpler way with a custom "ValidatedChanged()" event that you can hook in the same way.

Event Tracking in C#

I want to understand event cycles. I have a form with a grid and textboxes. It has a grid, bound to DataTable, and textboxes bound to same table too. I'm trying to debug something and need to know how to identify ALL events fired in the form to see what may solve an issue for me.
Anyhow, unless I explicitly subclass every class on my form, and override / attach to every event to my own event handlers, how can I get / listen to all events being fired during a certain action... Such as changing a "Selected" road in a DataGridView. It obviously updates its own "CurrentRow"... I need to know what / how to maybe FORCE a re-loading of SAME CurrentRow.
Reason: during a form level "Edit Mode", and I change the content in another "Textbox" control, and reject changes, I need it to simulate the current "Record" is reloaded to go back to its original values.
You could fire up a profiler and look at the method call tree.

Categories