Reputation: 630
I have an application that's meant to do data capturing of mostly numerical values. Typically I'm using text boxes. To organise this text, I decided to group the digits entered and put spaces between the groups.
So something like '555555555' will appear like '555 555 555', to give something similar to a whatsapp or viber signup text box effect. I'm using a TextChanged event to accomplish this.
Here's an example of how I've done it so far. This is a Text Box ment to take in a phone number.
private void cell_TextChanged(object sender, TextChangedEventArgs e)
{
string phrase = cell.Text;
if (phrase != null)
{
// This is to reset all spaces in the text back to none before the code below puts new ones.
// This avoids puting a space directly next to another one previously set.
// For some reason the textbox becomes difficult to work with if I don't do this.
phrase = Regex.Replace(phrase, @"\s+", "");
}
// If the text is smaller than 4 characters;
if (phrase.Length <= 4)
{
// Do nothing to it
cell.Text = phrase;
}
// if the text is equal to five characters
if (phrase.Length == 5)
{
// group the first 3 characters
string first = phrase.Substring(0, 3);
// and the last 2 to characters
string second = phrase.Substring(3, 2);
// then put a space between them
string paste = (first + " " + second);
//This string goes into the TextBox 'cell'
cell.Text = paste;
}
// if the text is equal to six characters
if (phrase.Length == 6)
{
// group the first 3 characters
string first = phrase.Substring(0, 3);
//And the last 3 characters
string second = phrase.Substring(3, 3);
// then put a space between them
string paste = (first + " " + second);
//This string goes into the TextBox 'cell'
cell.Text = paste;
}
if (phrase.Length == 7)
{
// group the first 4 characters
string first = phrase.Substring(0, 4);
// then the next 3
string second = phrase.Substring(4, 3);
// then put a space between them
string paste = (first + " " + second);
//This string goes into the TextBox 'cell'
cell.Text = paste;
}
if (phrase.Length == 8)
{
// group the first 4 characters
string first = phrase.Substring(0, 4);
// then the next 3
string second = phrase.Substring(4, 3);
// then the next character
string third = phrase.Substring(7, 1);
// then put a space between the first, second and third string
string paste = (first + " " + second + " " + third);
//This string goes into the TextBox 'cell'
cell.Text = paste;
}
if (phrase.Length == 9)
{
// group the first 4 characters
string first = phrase.Substring(0, 4);
// then the next 3
string second = phrase.Substring(4, 3);
// then the next 2 characters
string third = phrase.Substring(7, 2);
// then put a space between the first, second and third string
string paste = (first + " " + second + " " + third);
//This string goes into the TextBox 'cell'
cell.Text = paste;
}
if (phrase.Length == 10)
{
// group the first 4 characters
string first = phrase.Substring(0, 4);
// then the next 3
string second = phrase.Substring(4, 3);
// then the next 3 characters after that
string third = phrase.Substring(7, 3);
// then put a space between the first, second and third string
string paste = (first + " " + second + " " + third);
//This string goes into the TextBox 'cell'
cell.Text = paste;
}
//This is to keep the cursor at the end of the TextBox's text when I enter a new character other wise it goes back to the start.
cell.CaretIndex = cell.Text.Length;
}
the problem is this code for starters is too long so I can't afford to place it in every text box that needs to separate numbers (My lecturer already mentioned repetition of something like this was bad practice and I might get penalised for it). However I have a lot of cells that need to be able to do this but I kind of lack the skill to turn it into a behaviour or place it in a class and make it still function.
So basically what I'd like to know is how you'd implement this in a get,set class or behaviour class (or anyother I'm overlooking for that matter) to be used across multiple pages. Suggestions anyone?
Upvotes: 1
Views: 974
Reputation: 69959
The simplest way of encapsulating some code into any UI control is to declare an Attached Property... that's pretty much what they're there for - extending the functionality of pre-existing UI elements. If you're not familiar with Attached Properties, then you can find out more about them from the Attached Properties Overview page on MSDN.
Here is an example that you could use... all you need to do is to add your event handler:
public static readonly DependencyProperty IsFormattedProperty = DependencyProperty.RegisterAttached("IsFormatted", typeof(bool), typeof(TextBoxProperties), new UIPropertyMetadata(default(bool), OnIsFormattedChanged));
public static bool GetIsFormatted(DependencyObject dependencyObject)
{
return (bool)dependencyObject.GetValue(IsFormattedProperty);
}
public static void SetIsFormatted(DependencyObject dependencyObject, bool value)
{
dependencyObject.SetValue(IsFormattedProperty, value);
}
public static void OnIsFormattedChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
TextBox textBox = dependencyObject as TextBox;
if (textBox != null)
{
bool newIsFormattedValue = (bool)dependencyPropertyChangedEventArgs.NewValue;
if (newIsFormattedValue) textBox.TextChanged += YourTextChangedHandler;
else textBox.TextChanged -= YourTextChangedHandler;
}
}
It should be added into a class named TextBoxProperties
and would be used as simply as this:
<TextBox TextBoxProperties:IsFormatted="True" ... />
Upvotes: 1
Reputation: 303
If you want to do it in MVVM way you can use any of those options :
1. Bind to different properties and in ViewModel call the same method. Do not forget to specify UpdateSourceTrigger
<TextBox Text="{Binding MyText, ElementName=myControl, UpdateSourceTrigger=PropertyChanged}"/>
2. Or write your own an attached behavior for TextBoxes to support TextChanged commands.
3. Or use InvokeCommandAction from System.Windows.Interactivity to bind to the same method
<TextBox x:Name="SomeText">
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="TextChanged">
<interactivity:InvokeCommandAction Command="{Binding SomeCommand, Mode=OneWay}"/>
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
</TextBox>
Upvotes: 0
Reputation: 1230
If you are not following MVVM then you can use something like this.
class FindingLogicalChildren
{
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject dependencyObject) where T : DependencyObject
{
if (dependencyObject != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(dependencyObject, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
and in your mainwindow Loaded
mainwindow.xaml
private void window_Loaded(object sender, RoutedEventArgs e)
{
foreach (TextBox it in FindingLogicalChildren.FindVisualChildren<TextBox>(Application.Current.MainWindow))
{
t = it;
t.TextChanged += t_TextChanged;
}
}
void t_TextChanged(object sender, TextChangedEventArgs e)
{
// do your work here.. you get all textchanged events here
}
Upvotes: 0
Reputation: 7737
You should extract the code from cell_TextChanged
and move it into a new method. You would then call this new method in your event handlers.
e.g.
private void cell_TextChanged(object sender, TextChangedEventArgs e)
{
YourTextChangedHandlerMethod(sender as TextBox, e);
}
This approach means you don't have to write the same code for each event - you just reuse the same code. The first parameter to YourTextChangedHandlerMethod
will be the text box that raised the event.
You may find you can tighten the parameters your new method takes, but that should be simple for you to figure out.
Upvotes: 1