更新文本的Windows 8 XAML数据绑定已更改

时间:2013-04-05 13:39:26

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

我有一个使用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类属性?

提前致谢

3 个答案:

答案 0 :(得分: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

您可以创建一个viewmodel作为实例,并通过您从代码隐藏中轻松执行viewmodel的方式将其作为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;
 }

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

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

答案 1 :(得分:1)

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

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

因此请务必设置

UpdateSourceTrigger=PropertyChanged
默认值为LostFocus

答案 2 :(得分: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的主要降级但是嘿,在WinFT中有很多更可怕的东西在WPF中缺失:)