【问题标题】:Attempting to bind textbox with viewmodel but no update occuring尝试将文本框与视图模型绑定但未发生更新
【发布时间】:2017-02-14 06:09:41
【问题描述】:

我设置了一个小型测试项目并创建了一个登录页面,该页面需要用户名和密码。我正在使用 MVVM 方法和 Prism 框架。我一直在关注这个视频 (https://www.youtube.com/watch?v=ZfBy2nfykqY)。

这里是 xaml:

<Page x:Class="Control_Center.Views.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:Control_Center.Views"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <StackPanel VerticalAlignment="Center"
                    HorizontalAlignment="Center"
                    Grid.Row="0">
            <StackPanel Orientation="Horizontal"
                        HorizontalAlignment="Center">
                <TextBlock Name="LoginResponse"
                           Text="{Binding LoginStatus}" />
            </StackPanel>
        </StackPanel>
        <StackPanel VerticalAlignment="Center"
                    HorizontalAlignment="Center"
                    Grid.Row="1">
            <StackPanel Orientation="Horizontal"
                        HorizontalAlignment="Center">
                <TextBox Name="UsernameBox"
                         Text="{Binding Username, UpdateSourceTrigger=PropertyChanged}"
                         AcceptsReturn="False"
                         PlaceholderText="Username..."
                         HorizontalAlignment="Center"
                         VerticalAlignment="Center"
                         FontSize="14"
                         Width="200"
                         Height="25" />
            </StackPanel>
            <StackPanel Orientation="Horizontal"
                        HorizontalAlignment="Center">
                <PasswordBox Name="PasswordBox"
                             PasswordRevealMode="Peek"
                             PlaceholderText="Password..."
                             Width="200"
                             Height="25"
                             VerticalAlignment="Center"
                             HorizontalAlignment="Center"
                             FontSize="14"
                             PasswordChanged="PasswordBox_PasswordChanged" />
            </StackPanel>
            <StackPanel Orientation="Horizontal"
                        HorizontalAlignment="Right">
                <Button Name="LoginButton"
                        HorizontalAlignment="Right"
                        VerticalAlignment="Bottom"
                        Margin="0,10,0,0"
                        FontSize="12"
                        Content="Login"
                        Command="{Binding LoginCommand}" />
                <Button Name="CancelButton"
                        HorizontalAlignment="Right"
                        VerticalAlignment="Bottom"
                        Margin="10,10,0,0"
                        FontSize="12"
                        Content="Cancel" />

            </StackPanel>
        </StackPanel>
    </Grid>
</Page>

还有 viewModel(注意:BindableBase 是 Prism 的一部分:https://github.com/PrismLibrary/Prism/blob/master/Source/Prism/Mvvm/BindableBase.cs):

using System;
using System.Diagnostics;
using System.Windows.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Prism.Commands;
using Prism.Mvvm;

namespace EJD_Control_Center.ViewModels
{
    class ViewLoginViewModel : BindableBase
    {
        private string _username;

        public string Username
        {
            get { return _username; }
            set { SetProperty(ref _username, value); }
        }

        private string _password;

        public string Password
        {
            get { return _password; }
            set { SetProperty(ref _password, value); }
        }

        private string _loginStatus;

        public string LoginStatus
        {
            get { return _loginStatus; }
            set { SetProperty(ref _loginStatus, value); }
        }

        public DelegateCommand LoginCommand { get; set; }

        public ViewLoginViewModel()
        {
            LoginCommand = new DelegateCommand(Execute, CanExecute).ObservesProperty(() => Username).ObservesProperty(() => Password);
        }

        private bool CanExecute()
        {
            Debug.WriteLine($"Username: {Username}, password: {Password}");
            Debug.WriteLine("Username is not null or whitespace? " + !string.IsNullOrWhiteSpace(Username) + ", and password: " + !string.IsNullOrWhiteSpace(Password));
            return !string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password);
        }

        private void Execute()
        {
            LoginStatus = $"Login Successful! Username: {Username} Password: {Password}"; 
            //actually return the status of the login request, but we don't have this yet. then switch screens.
        }
    }
}

为了完成,代码隐藏:

using Windows.Foundation;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Control_Center.ViewModels;

namespace Control_Center.Views
{
    /// <summary>
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            InitializeComponent();

            ApplicationView.PreferredLaunchViewSize = new Size(500, 320);
            ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;

            DataContext = new ViewLoginViewModel();
        }

        private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
        {
            var vm = (ViewLoginViewModel) DataContext;
            vm.Password = PasswordBox.Password;
        }
    }
}

现在在任何人开始之前,我知道这不是处理传递密码的安全方法。这不是这个问题的重点。

问题是当我将用户名文本框绑定到 ViewModel 中的用户名变量时,它似乎没有更新该字符串。如果我将 ViewModel 中的用户名设置为某个值,比如“test”,它会在文本框中显示它,但没有对该文本框的更新会更改 ViewModel 中的用户名变量。

修改这两个框时我得到的输出是:

Username: , password: d
Username is not null or whitespace? False, and password: True

即使用户名文本框中有内容。出现这些调试行的唯一原因是我处理密码的方式是调用 canExecute,但我处理用户名的方式不是,尽管据我所知它应该这样做。

为什么"{Binding Username, UpdateSourceTrigger=PropertyChanged}" 没有将用户名文本框文本发送到 ViewModel 中的用户名变量?

【问题讨论】:

  • BindableBase 怎么样 - 任何人都可以在没有它的情况下运行您的代码,并且知道 SetProperty() 背后隐藏着什么样的魔法?
  • 因为 BindableBase 是 Prism 的一部分,我特别提到我正在使用并放入标签。
  • 好的,没有棱镜,所以仅根据我所见,我建议将 Mode=TwoWay 设置为绑定
  • 我已经用关于 BindableBase 的通知更新了这个问题,并提供了一个指向它的 github 页面的链接。对此感到抱歉。
  • @RTDev 哇,做到了。你先生太棒了。如果您想将其作为答案,我可以将其标记为已回答。

标签: c# mvvm uwp prism


【解决方案1】:

这是因为 Binding 的默认模式设置是 OneWay - 所以从代码更新到布局可以正常工作,但从布局到代码则不行。 设置 Mode=TwoWay 使其双向工作。

"{Binding Username, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

【讨论】:

  • x:Bind 的默认模式设置也是 OneTime,与 Binding 不同。
  • 是的,但在这种情况下您不会使用 x:Bind - 因为它不支持 UpdateSourceTrigger。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多