2013-04-05 52 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