TextChanged is called twice but not update latest value ?

Topics: Bugs
Jun 12, 2012 at 1:47 PM

I have a WPF source as follow:

<TextBox x:Name="Barcode" Text="{Binding Path=Barcode, Mode=TwoWay}" cal:Message.Attach="[Event TextChanged]=[Action ProcessBarcode(Barcode.Text)]" />

and the ViewModel code:
public string Barcode {get;set;} // with NotifyPropertyChanged ...
if (barcode.Length == 12)) { ArrayList details = new ArrayList(StockInventoryList); // add to stockOut list InsertBarcodeToList(details, barcode, 1);
Barcode = "";
}
When I did input a barcode to textbox, it inserted a product with quantity is 2.
Debugging and it showed that function
ProcessBarcode(Barcode.Text)
is called twice and it used the old value, not the new value "" ?
This thing was not happen with Caliburn before.
Does it has any way to update value in the recalled of TextChanged event ?

if (ObjectUtility.LengthEqual(barcode, 12))
			{
				ArrayList details = new ArrayList(StockInventoryList);
				// add to stockOut list
				InsertBarcodeToList(details, barcode, 1);
				#region useless
				/*ArrayList details = new ArrayList(StockInventoryList);
				DepartmentStockTempValid result = (from sod in details.OfType<DepartmentStockTempValid>()
												   where sod.Product.ProductId.Equals(barCode)
												   select sod).FirstOrDefault();
				if (result != null) // if exist in list
				{
					result.Quantity += 1;
				}
				else
				{
 
					// get information from database
					DepartmentStockTempValid tempValid = DepartmentStockTempValidLogic.CreateFromProductId(barCode, SelectedDepartment.DepartmentId);
					if (tempValid == null) throw new InvalidDataException("Can not found product in database !");
					tempValid.GoodQuantity = 1;
					details.Add(tempValid);
				}*/
 
				#endregion
				StockInventoryList = details;
			}
Jun 12, 2012 at 3:52 PM

I guess I fail to understand why it is that you are using Convention and cal:Message.Attach at the same time since you are forcing the TextChanged event to due exactly the behavior you are seeing.  I am surprised it's not 3 times since you are actually Tripling the ammount of calls, 1 Convention, 2 Binding, 3 Message.Attach

Unless I am missing the point you only need one as long as you have a property backer for the field you are trying to get data from then you would just call your Method in the Settter of your property.

If you wanted to trap the event then don't send it any data imo... You already have it....

Ex 1.

<TextBox x:Name="Barcode" <!-- CONVENTION -->  cal:Message.Attach = "[Event TextChanged] = [Action ProcessBarCode()] <!-- Trap Event --> />

private string _barcode = null;

public string Barcode{
  get{ return _barcode;}
  set{
     if(_barcode == value)
          return;
     _barcode = value;
     NotifyOfPropertyChange(()=>Barcode);  // <<< ABSOLUTELY NEED FOR TEXT UPDATE NOTIFICATION
     }
}

public void ProcessBarCode(){

}

Or

Ex 2

<TextBox x:Name="Barcode"  />

public string Barcode{
get{ return _barcode;}
set{
   if(_barcode == value)
      return;
   _barcode = value;
   NotifyOfPropertyChange(()=>Barcode); // <<< ABSOLUTELY NEED FOR TEXT UPDATE NOTIFICATION
   ProcessBarCode();
   }
}

private void ProcessBarcode(){
  // DO IT!

}

Jun 13, 2012 at 3:29 AM

Hi mvermef,

As I stated in the post, the old code worked with Caliburn (not Caliburn.Micro) and it had Convention only. Btw, the setter has NotifyOfPropertyChange, I just din't write it for short.

<TextBox x:Name="Barcode" cal:Message.Attach="[Event TextChanged]=[Action ProcessBarcode()]" />

Then in ProcessBarcode I processed value of Barcode and blah blah blah ...
But the problem is when project upgrades to Caliburn.Micro, it ceases working. So I added the Binding, after that I pass the View value to function call.
The last method worked but it did not meet the expectation.The flow is as follow IMO:
1/ When "text changed" appear on View it calls ProcessBarcode()
2/ ProcessBarcode() processes Barcode's value and set Barcode = "".
3/ NotifyOfChange(()=>Barcode) notifies the change up to View.
4/ Value of text box changed in the View. "Text changed" appear again and it continue to call ProcessBarcode() with changed value.
The problem is step 4 happened with old value. It did not used the new value, seems that Message.Attach is run before the TextChanged event run so it can not get the new value from control.

Jun 13, 2012 at 7:45 AM

The convention should work without the explicit binding. I would first debug that issue, to see why it is not working (acitvate CM logging).