[Windows 8] Update TextBox’s binding on TextChanged
- by Benjamin Roux
Since UpdateSourceTrigger is not available in WinRT we cannot update the text’s binding of a TextBox at will (or at least not easily) especially when using MVVM (I surely don’t want to write behind-code to do that in each of my apps !). Since this kind of demand is frequent (for example to disable of button if the TextBox is empty) I decided to create some attached properties to to simulate this missing behavior. namespace Indeed.Controls
{
public static class TextBoxEx
{
public static string GetRealTimeText(TextBox obj)
{
return (string)obj.GetValue(RealTimeTextProperty);
}
public static void SetRealTimeText(TextBox obj, string value)
{
obj.SetValue(RealTimeTextProperty, value);
}
public static readonly DependencyProperty RealTimeTextProperty =
DependencyProperty.RegisterAttached("RealTimeText", typeof(string), typeof(TextBoxEx), null);
public static bool GetIsAutoUpdate(TextBox obj)
{
return (bool)obj.GetValue(IsAutoUpdateProperty);
}
public static void SetIsAutoUpdate(TextBox obj, bool value)
{
obj.SetValue(IsAutoUpdateProperty, value);
}
public static readonly DependencyProperty IsAutoUpdateProperty =
DependencyProperty.RegisterAttached("IsAutoUpdate", typeof(bool), typeof(TextBoxEx), new PropertyMetadata(false, OnIsAutoUpdateChanged));
private static void OnIsAutoUpdateChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var value = (bool)e.NewValue;
var textbox = (TextBox)sender;
if (value)
{
Observable.FromEventPattern<TextChangedEventHandler, TextChangedEventArgs>(
o => textbox.TextChanged += o,
o => textbox.TextChanged -= o)
.Do(_ => textbox.SetValue(TextBoxEx.RealTimeTextProperty, textbox.Text))
.Subscribe();
}
}
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
The code is composed of two attached properties. The first one “RealTimeText” reflects the text in real time (updated after each TextChanged event). The second one is only used to enable the functionality.
To subscribe to the TextChanged event I used Reactive Extensions (Rx-Metro package in Nuget). If you’re not familiar with this framework just replace the code with a simple:
textbox.TextChanged += textbox.SetValue(TextBoxEx.RealTimeTextProperty, textbox.Text);
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
To use these attached properties, it’s fairly simple
<TextBox Text="{Binding Path=MyProperty, Mode=TwoWay}" ic:TextBoxEx.IsAutoUpdate="True" ic:TextBoxEx.RealTimeText="{Binding Path=MyProperty, Mode=TwoWay}" />
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Just make sure to create a binding (in TwoWay) for both Text and RealTimeText.
Hope this helps !