Created
April 19, 2011 23:25
-
-
Save edchapel/929974 to your computer and use it in GitHub Desktop.
Supporting code for http://edchapel.tumblr.com/post/4759954989/editing-numbers-in-silverlight-with-binding-and
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public partial class ConvictionHistory | |
{ | |
[RegularExpression(@"^\d*$", ErrorMessage = "Felonies must be a number.")] | |
public string FeloniesText | |
{ | |
get { return this.GetNumberAsString(_ => _.Felonies); } | |
set { this.SetIntProperty(_ => _.Felonies, value, number => Felonies = number); } | |
} | |
[RegularExpression(@"^\d*$", ErrorMessage = "Misdemeanors must be a number.")] | |
public string MisdemeanorsText | |
{ | |
get { return this.GetNumberAsString(_ => _.Misdemeanors); } | |
set { this.SetIntProperty(_ => _.Misdemeanors, value, number => Misdemeanors = number); } | |
} | |
[RegularExpression(@"^\d*\.?\d*$", ErrorMessage = "Bail must be a number.")] | |
public string BailText | |
{ | |
get { return this.GetNumberAsString(_ => _.Bail ); } | |
set { this.SetDoubleProperty(_ => _.Bail , value, number => Bail = number); } | |
} | |
#region Text-Number Support Code | |
private IDictionary<string, string> _textProperties; | |
public IDictionary<string, string> TextProperties | |
{ | |
get { return _textProperties ?? (_textProperties = new Dictionary<string, string>()); } | |
} | |
void IExposeNumbersAsText.ValidateProperty(string propertyName, object value) | |
{ | |
ValidateProperty(propertyName, value); | |
} | |
void IRaisesPropertyChangedEvent.RaisePropertyChanged(PropertyChangedEventArgs args) | |
{ | |
RaisePropertyChanged(args.PropertyName); | |
} | |
protected override void OnPropertyChanged(PropertyChangedEventArgs e) | |
{ | |
base.OnPropertyChanged(e); | |
if (TextProperties.ContainsKey(e.PropertyName)) | |
{ | |
RaisePropertyChanged(e.PropertyName + "Text"); | |
} | |
} | |
#endregion | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Supports presenting and validating numbers within TextBoxes. | |
/// </summary> | |
public static class ExtensionsForNumbersWithTextboxes | |
{ | |
/// <summary> | |
/// Returns the last value set on the <paramref name="numericProperty"/> from the TextBox. | |
/// </summary> | |
/// <param name="entity">The Entity with a numeric property to be bound to a TextBox.</param> | |
/// <param name="numericProperty">A lambda representing the path to the numeric property.</param> | |
/// <typeparam name="TEntity">The type hosting the numeric property you are battling to present in a TextBox.</typeparam> | |
/// <typeparam name="TNumber">Usually an int or double.</typeparam> | |
/// <returns>A string version of the numeric property or the last invalid text set by the user.</returns> | |
public static string GetNumberAsString<TEntity, TNumber>(this TEntity entity, Expression<Func<TEntity, TNumber?>> numericProperty) | |
where TEntity : class, IExposeNumbersAsText | |
where TNumber : struct | |
{ | |
var number = numericProperty.GetValueFrom(entity); | |
var propName = numericProperty.GetNameFor(); | |
string text; | |
entity.TextProperties.TryGetValue(propName, out text); | |
return text == null && number.HasValue ? number.Value.ToString() : text; | |
} | |
/// <summary> | |
/// Stores the <param name="value"/> set in the TextBox in the <param name="entity"/>. | |
/// An invalid <param name="value"/> is stored in the <see cref="IExposeNumbersAsText.TextProperties"/> for later. | |
/// A valid <param name="value"/> is sent to the <param name="setIntProperty"/> to be stored in the original numeric property. | |
/// </summary> | |
/// <param name="entity">The host object with an numeric property.</param> | |
/// <param name="intProperty">A lambda representing the path to the numeric property.</param> | |
/// <param name="value">The string value set against the text version of the property.</param> | |
/// <param name="setIntProperty">A lambda to set the numeric property with an int (or null) when the value from the TextBox is valid.</param> | |
/// <typeparam name="TEntity">The type hosting the numeric property you are battling to present in a TextBox.</typeparam> | |
public static void SetIntProperty<TEntity>(this TEntity entity, Expression<Func<TEntity, int?>> intProperty, string value, Action<int?> setIntProperty) | |
where TEntity : class, IExposeNumbersAsText | |
{ | |
SetStringToNumeric(entity, intProperty, value, setIntProperty, | |
str => | |
{ | |
int number; | |
return int.TryParse(str, out number) ? (int?) number : null; | |
}); | |
} | |
/// <summary> | |
/// Stores the <param name="value"/> set in the TextBox in the <param name="entity"/>. | |
/// An invalid <param name="value"/> is stored in the <see cref="IExposeNumbersAsText.TextProperties"/> for later. | |
/// A valid <param name="value"/> is sent to the <param name="setDoubleProperty"/> to be stored in the original numeric property. | |
/// </summary> | |
/// <param name="entity">The host object with an numeric property.</param> | |
/// <param name="doubleProperty">A lambda representing the path to the numeric property.</param> | |
/// <param name="value">The string value set against the text version of the property.</param> | |
/// <param name="setDoubleProperty">A lambda to set the numeric property with an double (or null) when the value from the TextBox is valid.</param> | |
/// <typeparam name="TEntity">The type hosting the numeric property you are battling to present in a TextBox.</typeparam> | |
public static void SetDoubleProperty<TEntity>(this TEntity entity, Expression<Func<TEntity, double?>> doubleProperty, string value, Action<double?> setDoubleProperty) | |
where TEntity : class, IExposeNumbersAsText | |
{ | |
SetStringToNumeric(entity, doubleProperty, value, setDoubleProperty, | |
str => | |
{ | |
double number; | |
return double.TryParse(str, out number) ? (double?) number : null; | |
}); | |
} | |
private static void SetStringToNumeric<TEntity, TNumber>(TEntity entity, | |
Expression<Func<TEntity, TNumber?>> numericProperty, | |
string value, Action<TNumber?> setNumericProperty, | |
Func<string, TNumber?> parseNumber) | |
where TEntity : class, IExposeNumbersAsText | |
where TNumber : struct | |
{ | |
// Need the name of the property | |
var propName = numericProperty.GetNameFor(); | |
// Tell the WCF RIA Entity to run validation. This will update a TextBox with a validation error to no longer be red. | |
entity.ValidateProperty(propName + "Text", value); | |
// Store empty strings as nullable numerics | |
if (string.IsNullOrWhiteSpace(value)) | |
{ | |
entity.TextProperties[propName] = null; | |
setNumericProperty(null); | |
return; | |
} | |
// Call the int/double specific parser | |
var number = parseNumber(value); | |
if (number.HasValue) | |
{ | |
// The user typed a valid number | |
entity.TextProperties[propName] = null; | |
setNumericProperty(number.Value); | |
} | |
else | |
{ | |
// The value was not valid. Store it in the entity's storage area. It will be retrieved by validation | |
// when the entity is submitted to the server. | |
entity.TextProperties[propName] = value; | |
// Raise a property changed for the text version of the property for any listeners to react | |
entity.RaisePropertyChanged(new PropertyChangedEventArgs(propName + "Text")); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// <para>Assists the <see cref="ExtensionsForNumbersWithTextboxes"/> extension to provide a solution for | |
/// presenting and validating numbers in TextBoxes.</para> | |
/// <para></para> | |
/// </summary> | |
public interface IExposeNumbersAsText : IRaisesPropertyChangedEvent | |
{ | |
/// <summary> | |
/// Storage for the string-based state of a numeric property. | |
/// </summary> | |
IDictionary<string, string> TextProperties { get; } | |
/// <summary> | |
/// Exposes the <see cref="Entity"/>'s <see cref="Entity.ValidateProperty"/> method. | |
/// </summary> | |
/// <param name="propertyName">Name of the property</param> | |
/// <param name="value">Value of the property</param> | |
void ValidateProperty(string propertyName, object value); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///<summary> | |
/// Extends <see cref="INotifyPropertyChanged"/> to support the | |
/// <see cref="NotifyPropertyChangedExtensions.NotifyIfPropertyChanged{THost,TProperty}"/> extension method. | |
///</summary> | |
public interface IRaisesPropertyChangedEvent : INotifyPropertyChanged | |
{ | |
///<summary> | |
/// Raise the <see cref="INotifyPropertyChanged.PropertyChanged"/> event. | |
///</summary> | |
///<param name="args">The args with the property name defined</param> | |
void RaisePropertyChanged(PropertyChangedEventArgs args); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment