1

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

提前致谢

4

3 回答 3

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 上编码,没有再次测试。希望有所帮助!

于 2013-04-05T13:43:00.087 回答
1

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

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

所以一定要设置

UpdateSourceTrigger=PropertyChanged
默认值为 LostFocus

于 2016-01-12T12:51:42.890 回答
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 中丢失了 :)

于 2013-04-05T18:09:58.693 回答