MVVM WPF:为啥在运行应用程序时更新文本框中的文本后模型中的属性始终为空?

Posted

技术标签:

【中文标题】MVVM WPF:为啥在运行应用程序时更新文本框中的文本后模型中的属性始终为空?【英文标题】:MVVM WPF: Why is the property in the Model always null even after updating the text in textbox while running the application?MVVM WPF:为什么在运行应用程序时更新文本框中的文本后模型中的属性始终为空? 【发布时间】:2021-10-30 06:34:39 【问题描述】:

我放弃了 MVP 模式,尝试了 MVVM 和 WPF。到目前为止,我设法通过单击不同的按钮来导航显示不同用户控件的菜单。 DataBinding 和 Commands 在导航中运行良好,但是在 DataBinding 文本框时遇到了问题。

该属性总是得到 null 值,我不知道为什么。我添加了一个命令,以便在单击按钮时从文本框中获取用户 ID,并显示一个包含用户 ID 的消息框,以便在我尝试其他任何操作之前使其变得简单。

MessageBox 显示,但它是空的。我在 UsersModel.cs 中添加了一个 Task.Run,​​因此我可以查看字符串是否在 propertychange 上更新但值为 null。

我正在使用 ObservableObject 的类来通知 OnPropertyChanged。还有一个继承自 ICommand 的 RelayCommand 类。两者似乎都按预期工作,但仅在单击按钮以显示不同的用户控件并关闭应用程序时。下面是来自 View、Model 和 ViewModel 的示例代码。我错过了什么?

RegisterMenu.xaml

      <TextBox x:Name="RegTextUserID" Margin="163,66,148,112"
               Style="StaticResource ResourceKey=UserBox"
               Text="Binding UserID, UpdateSourceTrigger=PropertyChanged">
                     
           <TextBox.DataContext>
               <models:UsersModel/>
           </TextBox.DataContext>
       </TextBox>

       <Button x:Name="Button_Register" Content="Register" HorizontalAlignment="Left" 
               Margin="183,129,0,0" VerticalAlignment="Top"
               Command="Binding Path=GetUserCommand">
                    
            <Button.DataContext>
               <viewmodels:RegisterViewModel/>
            </Button.DataContext>
        </Button>

UsersModel.cs

 public class UsersModel : ObservableObject


    // backing fields
    private string _userID;

    // Properties
    public string UserID      // UserID is null
    
        get  return _userID; 
        set
        
            SetProperty(ref _userID, value);
        
    
    

    // testing loop for propertychange trigger
    public UsersModel()
    
        Task.Run(() =>
        
            while (true)
            
                Debug.WriteLine($"UserID:   UserID");
                Thread.Sleep(1000);
            

        );
    

RegisterViewModel.cs

public class RegisterViewModel : ObservableObject

    public RelayCommand GetUserCommand  get; set; 

    public RegisterViewModel()
    
        
        GetUserCommand = new RelayCommand(o =>
        

         // Command is responding to button click.

        );
    

编辑 1 如果我将 ObservableObject.cs 更改为使用 [CallerMemberName]SetProperty,则更新了 UsersModel.cs 中的代码。我还从 RegisterViewModel.cs 中删除了 GetUserCommand 代码,所以我只能测试 UsersModel.cs 中的属性。

据我了解,文本框绑定不起作用。即使使用了 SetProperty 方法,我也没有得到任何价值。

编辑 2

为了澄清,我在一开始就在 XAML(一个 DataContext)中使用了以下内容。但我仍然有同样的问题。 UsersModel 属性没有获取我在文本框中输入的文本。

<UserControl.DataContext>
    <models: UserModel/>
</UserControl.DataContext>

我创建了一个带有一个文本框的示例项目,以尝试为文本框设置特定的 DataContext,如下面的代码。它在示例中工作。输出打印我在文本框中写的文本。为什么它在上面的 UsersModel.cs 中不起作用?

MainWindow.xaml

<TextBox HorizontalAlignment="Left" Margin="249,60,0,0" 
         Text=" Binding SomeText, UpdateSourceTrigger=PropertyChanged, 
                 Mode=TwoWay" 
         TextWrapping="Wrap" VerticalAlignment="Top" Width="120">
        <TextBox.DataContext>
            <local:TestModel/>
        </TextBox.DataContext>
 </TextBox>

TestModel.cs(这很有效,每次我更改文本框中的文本时,我都能看到循环输出)。

class TestModel
 
    private string _someText;

    public string SomeText
    
        get  return _someText; 
        set  _someText = value; 
    

    public TestModel()
    
        Task.Run(() =>
        
            while (true)
            
                Debug.WriteLine(SomeText);
                Thread.Sleep(1000);
            
        );
    



       

【问题讨论】:

ObservableObject 的文档显示您需要对其调用 SetProperty() 方法来引发通知事件。 ObservableObject。 "提供的 SetProperty(ref T, T, string) 方法检查属性的当前值,如果不同则更新,然后还会自动引发相关事件。属性名称通过使用 [CallerMemberName] 属性,因此无需手动指定要更新的属性。” UsersModel User = new() 创建一个新的 UsersModel,与用作 TextBox 的 DataContext 的 UsersModel 完全无关 @quaabaam 即使使用 SetProperty 和使用 [CallerMemberName],我也遇到了同样的问题。但我会调整我的代码,然后再试一次。 @KlausGütter 在 UsersModel.cs 中怎么样,因为我将 UpdateSourceTrigger 设置为 propertychange,所以每次我更新文本框时循环不应该不断更改 UserID 吗? 我不明白这里使用的 2 个上下文。我通常为表单/对话框设置一个上下文并使用那里的属性。第二件事是绑定模式可以设置为TwoWay,这样可以确保视图可以写回,不确定。 【参考方案1】:

我在错误的地方寻找错误。我设法找到了样式的错误。我已经测试过删除样式并且绑定工作正常。我必须调整我正在使用的主题的代码。感谢所有的cmets。

【讨论】:

以上是关于MVVM WPF:为啥在运行应用程序时更新文本框中的文本后模型中的属性始终为空?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 WPF 转换器“错过”文本框中的最后一个字符?

动态地,在运行时,如何在 WPF 中更改文本框中某些单词的颜色?

文本框中的 WPF 命令参数

在 WPF + MVVM +Binding + UserInput 中的 TextBox “预期格式为 DD/MM/YYYY”

当我尝试使用 MVVM WPF 中的命令修改对象时,为啥在视图模型中出现空错误?

MVVM:将带有 Observable 集合的命令绑定到 Listbox 并从文本框中获取值