2013-04-05 88 views
1

我有一个使用MVVM模式的Windows 8 XAML/C#应用程序。Windows 8 XAML数据绑定更新文本更改

表单上的所有文本框都将其文本属性绑定到我的MVVM类上的属性。

所以,我的文本框的一个看起来是这样的:

<TextBox x:Name="textAddressLine1" Text="{Binding AddressLine1, Mode=TwoWay}"/> 

而且在MVVM类属性看起来是这样的:

private string addressLine1; 

    public string AddressLine1 
    { 
     get { return addressLine1; } 
     set 
     { 
      if (addressLine1 == value) 
      { 
       return; 
      } 

      addressLine1 = value; 
      RaisePropertyChanged("AddressLine1"); 
     } 
    } 

当我键入我的文本框中的MVVM类ISN” t更新。只有当焦点移动到不同的控件时它才会更新。

当我的文本框中的文本发生更改时,如何更新MVVM类属性?

在此先感谢

回答

1

使用明确textAddressLine1

<TextBox x:Name="textAddressLine1" Text="{Binding AddressLine1,UpdateSourceTrigger=Explicit, Mode=TwoWay}" TextChanged="textAddressLine1_Changed"/> 


private void textAddressLine1_Changed(object sender, RoutedEventArgs e) 
{ 
BindingExpression be = textAddressLine1.GetBindingExpression(TextBox.TextProperty); 
be.UpdateTarget(); 
} 

结合的 我没有测试的代码,但应该工作。

编辑:我看到它UpdateSourceTrigger不存在environtment

您可以创建一个视图模型你为实例,并通过您可以轻松地从你的后台代码执行你的视图模型的方式把它作为datacontext的。对于这种类型的情况下,它节省了一天!

public MyClassViewModel ViewModel {get;set} 
ctor() 
{ 
    this.ViewModel=new MyClassViewModel(); 
    this.DataContext=this.ViewModel; 
    InitializeComponets(); 
} 

private void textAddressLine1_Changed(object sender, RoutedEventArgs e) 
{ 
    this.ViewModel.AddressLine1=textAddressLine1.Text; 
} 

我想你不会需要这样的两种方式。单向是好的。因为你明确地改变虚拟机。

注:我在SO编码,没有再测试。希望有帮助!

+0

WinRT/XAML中没有UpdateSourceTrigger或UpdateTarget()。 – 2013-04-05 14:00:55

+0

对不起,我们仍然在办公室使用Win7&VS2010。如果他们之一,我会成为一名富有的工程师,我会买一台PC。然后,我会学到很多东西,并提供更好的答案:) – 2013-04-05 20:20:24

0

使用此解决方法:

public class ExtendedTextBox : TextBox 
    { 
     public static readonly DependencyProperty CustomActionProperty = 
      DependencyProperty.Register(
      "CustomAction", 
      typeof(Action<string>), 
      typeof(ExtendedTextBox), 
      new PropertyMetadata(null, OnPropertyChanged)); 

     public Action<string> CustomAction 
     { 
      get 
      { 
       return (Action<string>)GetValue(CustomActionProperty); 
      } 
      set 
      { 
       SetValue(CustomActionProperty, value); 
      } 
     } 

     private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      if(e.NewValue != null) 
       (d as ExtendedTextBox).TextChanged += ExtendedTextBox_TextChanged; 
      else 
       (d as ExtendedTextBox).TextChanged -= ExtendedTextBox_TextChanged; 
     } 

     async static void ExtendedTextBox_TextChanged(object sender, TextChangedEventArgs e) 
     {    
      await CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() => (sender as ExtendedTextBox).CustomAction((sender as ExtendedTextBox).Text)); 
     }   
    } 

在你的模型:

public Action<string> UpdateBindedViewModelProperty 
     { 
      get { return new Action<string>((value) => NewLabelName = value); } 
     } 

和看法:

<plmrfc:extendedtextbox customaction="{Binding UpdateBindedViewModelProperty, Mode=OneTime}" text="{Binding Path=NewLabelName, Mode=TwoWay}" width="200" x:name="Label_TextBox"></plmrfc:extendedtextbox> 

也有另一种方式,不涉及子类的TextBox。也许你喜欢这一点:

using System.Reflection; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 

namespace Flexman 
{ 
    public class TextBoxUpdateSourceBehaviour 
    { 
     private static PropertyInfo _boundProperty; 

     public static readonly DependencyProperty BindingSourceProperty = 
      DependencyProperty.RegisterAttached(
      "BindingSource", 
      typeof(string), 
      typeof(TextBoxUpdateSourceBehaviour), 
      new PropertyMetadata(default(string), OnBindingChanged)); 

     public static void SetBindingSource(TextBox element, string value) 
     { 
      element.SetValue(BindingSourceProperty, value); 
     } 

     public static string GetBindingSource(TextBox element) 
     { 
      return (string)element.GetValue(BindingSourceProperty); 
     } 

     private static void OnBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var txt = d as TextBox; 
      if (txt == null) 
       return; 

      txt.Loaded += OnLoaded; 
      txt.TextChanged += OnTextChanged; 
     } 

     static void OnLoaded(object sender, RoutedEventArgs e) 
     { 
      var txt = sender as TextBox; 
      if (txt == null) 
       return; 

      // Reflect the datacontext of the textbox to find the field to bind to. 
      var dataContextType = txt.DataContext.GetType(); 
      _boundProperty = dataContextType.GetRuntimeProperty(GetBindingSource(txt)); 

      // If you want the behaviour to handle your binding as well, uncomment the following. 
      //var binding = new Binding(); 
      //binding.Mode = BindingMode.TwoWay; 
      //binding.Path = new PropertyPath(GetBindingSource(txt)); 
      //binding.Source = txt.DataContext; 
      //BindingOperations.SetBinding(txt, TextBox.TextProperty, binding); 
     } 

     static void OnTextChanged(object sender, TextChangedEventArgs e) 
     { 
      var txt = sender as TextBox; 
      if (txt == null) 
       return; 

      if (_boundProperty.GetValue(txt.DataContext).Equals(txt.Text)) return; 
      _boundProperty.SetValue(txt.DataContext, txt.Text); 
     } 
    } 
} 

,并查看

<TextBox Text="{Binding Username}" Flexman:TextBoxUpdateSourceBehaviour.BindingSource="Username" /> 

这是我所知道的最漂亮的解决方案。其他人将是“非通用”黑客。 祝你好运。我不同意,这是从Silverlight的/ WPF重大降级,但嘿,有在WinRT中多了很多可怕的事情是缺少在WPF :)

+0

请注意,通过订阅事件与静态处理程序您创建内存泄漏,因为TextBoxes现在不能垃圾收集。 – 2013-04-08 02:38:12

+0

这似乎是一件大事,应该真的在那里!菲利普,你有什么建议吗? – Sun 2013-04-10 07:13:02

1

我有同样的问题,我在这里找到:https://stackoverflow.com/a/11676076/4551080

<TextBox Text="{Binding Path=EmailAddress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 

所以一定要设置

UpdateSourceTrigger=PropertyChanged
默认值是LostFocus