【问题标题】:Windows 8 XAML Databinding on updating on text changedWindows 8 XAML 数据绑定更新文本已更改
【发布时间】:2013-04-05 13:39:25
【问题描述】:

我有一个使用 MVVM 模式的 Windows 8 XAML/C# 应用程序。

表单上的所有文本框的文本属性都绑定到我的 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 类没有更新。仅当焦点移动到其他控件时才会更新。

当我的文本框上的文本发生变化时,如何更新 MVVM 类属性?

提前致谢

【问题讨论】:

    标签: c# binding windows-8 winrt-xaml


    【解决方案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 在环境中不存在

    您可以创建一个您的视图模型作为实例并将其作为数据上下文提供,您可以轻松地从您的代码隐藏执行您的视图模型。对于这种类型的案例,它可以节省一天的时间!

     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;
     }
    

    我认为您不需要两种方式。 OneWay 没问题。因为您明确更改了 VM。

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

    【讨论】:

    • WinRT/XAML 中没有 UpdateSourceTrigger 或 UpdateTarget()。
    • 很抱歉,我们在办公室仍然使用 Win7 和 VS2010。如果有的话,我会成为一名富有的工程师,我会买一台 PC。然后我会学到很多东西并提供更好的答案:)
    【解决方案2】:

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

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

    所以一定要设置

    UpdateSourceTrigger=PropertyChanged
    默认值为 LostFocus

    【讨论】:

      【解决方案3】:

      使用此解决方法:

      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 中缺失:)

      【讨论】:

      • 请注意,通过使用静态处理程序订阅事件会造成内存泄漏,因为现在无法对 TextBox 进行垃圾收集。
      • 这对于真正应该存在的东西来说似乎是一项很大的工作! Filip,你有什么建议吗?
      猜你喜欢
      • 1970-01-01
      • 2018-08-10
      • 2012-11-07
      • 2016-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-06
      • 1970-01-01
      相关资源
      最近更新 更多