{"id":1701,"date":"2012-08-05T15:53:15","date_gmt":"2012-08-05T20:53:15","guid":{"rendered":"http:\/\/www.wiredprairie.us\/blog\/?p=1701"},"modified":"2012-08-05T15:53:15","modified_gmt":"2012-08-05T20:53:15","slug":"windows-8-winrtmetro-missing-updatesourcetrigger","status":"publish","type":"post","link":"https:\/\/www.wiredprairie.us\/blog\/index.php\/archives\/1701","title":{"rendered":"Windows 8 WinRT\/Metro Missing UpdateSourceTrigger"},"content":{"rendered":"
If you\u2019ve done WPF or Silverlight programming, you may have found an occasion where using the Binding property UpdateSourceTrigger<\/a> set to PropertyChanged was extremely useful. (I know I have!)<\/p>\n It may have looked something like this:<\/p>\n The key feature was the live updating of the property through the binding. For example, as the user typed in the TextBox above, the property Value<\/strong> in the bound object would have been updated as the user typed. The default behavior in Silverlight 5 and WPF is to use LostFocus: the Value<\/strong> is only updated when the TextBox loses focus. Sometimes, that\u2019s OK. <\/p>\n In WinRT\/Metro however, this option was completely removed, and no decent replacement was provided unfortunately. In searching for a reasonable work-around, I discovered a few other related missing pieces from WinRT\/XAML:<\/p>\n You can start to feel how Xaml really is just a thin wrapper on the Windows 8 run time as you start to look around to see what remains from WPF. Even traditional Silverlight features are gone unfortunately. Maybe Windows 9? <\/p>\n So, I took a round-about approach to solving this problem. <\/p>\n And here it is in use:<\/p>\n (The above namespace is needed to provide context to the Xaml parser for the attached properties. Change it to whatever you need).<\/p>\n A classic pattern in WPF for extending built in controls without subclassing was to create an attached behavior. Thankfully, this pattern still works.<\/p>\n The core concept is to attach to the original instance of the TextBox by using an enabling property. In this case, an attached property<\/a> called IsEnabled is added to the TextBox.<\/p>\n<<\/span>TextBox <\/span>Text<\/span>=<\/span>"<\/span>{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}<\/span>" <\/span>\/><\/span><\/pre>\n
\n
<\/span>public class <\/span>UpdateSourceHelper <\/span>: <\/span>FrameworkElement\n <\/span>{\n <\/span>public static string <\/span>GetUpdateSourceText(<\/span>DependencyObject <\/span>obj)\n {\n <\/span>return <\/span>(<\/span>string<\/span>)obj.GetValue(UpdateSourceTextProperty);\n }\n\n <\/span>public static void <\/span>SetUpdateSourceText(<\/span>DependencyObject <\/span>obj, <\/span>string <\/span>value)\n {\n obj.SetValue(UpdateSourceTextProperty, value);\n }\n\n <\/span>\/\/ Using a DependencyProperty as the backing store for UpdateSourceText. This enables animation, styling, binding, etc...\n <\/span>public static readonly <\/span>DependencyProperty <\/span>UpdateSourceTextProperty =\n <\/span>DependencyProperty<\/span>.RegisterAttached(<\/span>"UpdateSourceText"<\/span>, <\/span>typeof<\/span>(<\/span>string<\/span>), <\/span>typeof<\/span>(<\/span>UpdateSourceHelper<\/span>), <\/span>new <\/span>PropertyMetadata<\/span>(<\/span>""<\/span>));\n \n <\/span>public static bool <\/span>GetIsEnabled(<\/span>DependencyObject <\/span>obj)\n {\n <\/span>return <\/span>(<\/span>bool<\/span>)obj.GetValue(IsEnabledProperty);\n }\n\n <\/span>public static void <\/span>SetIsEnabled(<\/span>DependencyObject <\/span>obj, <\/span>bool <\/span>value)\n {\n obj.SetValue(IsEnabledProperty, value);\n }\n\n <\/span>\/\/ Using a DependencyProperty as the backing store for IsEnabled. This enables animation, styling, binding, etc...\n <\/span>public static readonly <\/span>DependencyProperty <\/span>IsEnabledProperty =\n <\/span>DependencyProperty<\/span>.RegisterAttached(<\/span>"IsEnabled"<\/span>, <\/span>typeof<\/span>(<\/span>bool<\/span>), <\/span>typeof<\/span>(<\/span>UpdateSourceHelper<\/span>), \n <\/span>new <\/span>PropertyMetadata<\/span>(<\/span>false<\/span>, \n <\/span>\/\/ property changed\n <\/span>(obj, args)=> \n { \n <\/span>if <\/span>(obj <\/span>is <\/span>TextBox<\/span>)\n {\n <\/span>TextBox <\/span>tb = (<\/span>TextBox<\/span>)obj;\n <\/span>if <\/span>((<\/span>bool<\/span>)args.NewValue)\n { \n tb.TextChanged += AttachedTextBoxTextChanged;\n }\n <\/span>else\n <\/span>{\n tb.TextChanged -= AttachedTextBoxTextChanged;\n }\n }\n }\n ));\n\n <\/span>static void <\/span>AttachedTextBoxTextChanged(<\/span>object <\/span>sender, <\/span>TextChangedEventArgs <\/span>e)\n {\n <\/span>if <\/span>(sender <\/span>is <\/span>TextBox<\/span>)\n {\n <\/span>var <\/span>tb = (<\/span>TextBox<\/span>)sender;\n tb.SetValue(<\/span>UpdateSourceHelper<\/span>.UpdateSourceTextProperty, tb.Text); \n }\n } \n }<\/span><\/pre>\n
xmlns<\/span>:<\/span>local<\/span>="using:WiredPrairie.Converter"<\/span><\/pre>\n
<<\/span>TextBox <\/span>Height<\/span>="Auto" <\/span>Margin<\/span>="0,6" <\/span>Grid.Row<\/span>="1" <\/span>TextWrapping<\/span>="Wrap" <\/span>TabIndex<\/span>="0" \n <\/span>Text<\/span>="{<\/span>Binding <\/span>Value<\/span>}" \n <\/span>local<\/span>:<\/span>UpdateSourceHelper.IsEnabled<\/span>="True" \n <\/span>local<\/span>:<\/span>UpdateSourceHelper.UpdateSourceText<\/span>="{<\/span>Binding <\/span>Value<\/span>, <\/span>Mode<\/span>=TwoWay}"\/><\/span><\/pre>\n