You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在WPF的MVVM模式下从另一个窗口获取字段值?

在WPF MVVM模式下实现从子窗口获取数据

我正把C# WinForms开发的软件迁移到基于MVVM模式的WPF平台,目前处于入门阶段,遇到一个问题:如何从另一个窗口获取数据。在WinForms中我是这么实现的:

WinForms主窗体代码

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }

    string userName = string.Empty;
    string userSurName = string.Empty;
    string userAddress = string.Empty;
    private void GetUserInfos()
    {
        using (var form = new UserInfosForm())
        {
            var dialog = form.ShowDialog();
            if (dialog == DialogResult.OK)
            {
                this.userName = form.userName;
                this.userSurName = form.userSurName;
                this.userAddress = form.userAddress;
            }
        }
    }
}

WinForms数据来源窗体代码

public partial class UserInfosForm : Form
{
    public string userName = string.Empty;
    public string userSurName = string.Empty;
    public string userAddress = string.Empty;

    public UserInfosForm()
    {
        InitializeComponent();
        buttonOk.DialogResult = DialogResult.OK;
        buttonOk.Click += ButtonOk_Click;
    }

    private void ButtonOk_Click(object sender, EventArgs e)
    {
        userName = textBoxName.Text;
        userSurName = textBoxSurName.Text;
        userAddress = textBoxAddress.Text;
    }
}

请问如何在WPF的MVVM模式下实现该功能?


实现方案

MVVM模式核心是避免视图直接耦合,通过数据绑定和ViewModel交互传递数据,同时尽量保持ViewModel的纯净性。以下是具体实现步骤:

1. 定义用户数据模型

创建承载用户信息的实体类,实现INotifyPropertyChanged以支持数据绑定:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class UserInfo : INotifyPropertyChanged
{
    private string _userName;
    private string _userSurName;
    private string _userAddress;

    public string UserName
    {
        get => _userName;
        set
        {
            _userName = value;
            OnPropertyChanged();
        }
    }

    public string UserSurName
    {
        get => _userSurName;
        set
        {
            _userSurName = value;
            OnPropertyChanged();
        }
    }

    public string UserAddress
    {
        get => _userAddress;
        set
        {
            _userAddress = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 子窗口ViewModel

子窗口的ViewModel处理输入逻辑,提供确认/取消命令:

using System.Windows.Input;
using Microsoft.Toolkit.Mvvm.Input; // 可通过NuGet安装CommunityToolkit.Mvvm简化命令实现

public class UserInfoDialogViewModel
{
    public UserInfo UserInfo { get; set; } = new UserInfo();

    public ICommand ConfirmCommand { get; }
    public ICommand CancelCommand { get; }

    // 通知主窗口关闭状态的委托
    public Action<bool> OnDialogClose { get; set; }

    public UserInfoDialogViewModel()
    {
        ConfirmCommand = new RelayCommand(ExecuteConfirm);
        CancelCommand = new RelayCommand(ExecuteCancel);
    }

    private void ExecuteConfirm()
    {
        OnDialogClose?.Invoke(true);
    }

    private void ExecuteCancel()
    {
        OnDialogClose?.Invoke(false);
    }
}

3. 子窗口视图(UserInfoDialog.xaml)

通过数据绑定关联ViewModel,无业务逻辑后置代码:

<Window x:Class="YourNamespace.UserInfoDialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:YourNamespace"
        Title="用户信息" Width="300" Height="250" WindowStartupLocation="CenterOwner">
    <Window.DataContext>
        <vm:UserInfoDialogViewModel />
    </Window.DataContext>
    <StackPanel Margin="10">
        <Label Content="用户名:"/>
        <TextBox Text="{Binding UserInfo.UserName, UpdateSourceTrigger=PropertyChanged}" Margin="0 0 0 5"/>
        
        <Label Content="姓氏:"/>
        <TextBox Text="{Binding UserInfo.UserSurName, UpdateSourceTrigger=PropertyChanged}" Margin="0 0 0 5"/>
        
        <Label Content="地址:"/>
        <TextBox Text="{Binding UserInfo.UserAddress, UpdateSourceTrigger=PropertyChanged}" Margin="0 0 0 15"/>
        
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <Button Content="确认" Command="{Binding ConfirmCommand}" Width="80" Margin="0 0 10 0"/>
            <Button Content="取消" Command="{Binding CancelCommand}" Width="80"/>
        </StackPanel>
    </StackPanel>
</Window>

子窗口后置代码仅处理关闭逻辑:

public partial class UserInfoDialog : Window
{
    private UserInfoDialogViewModel _viewModel;

    public UserInfoDialog()
    {
        InitializeComponent();
        _viewModel = (UserInfoDialogViewModel)DataContext;
        _viewModel.OnDialogClose = (isConfirmed) =>
        {
            DialogResult = isConfirmed;
            Close();
        };
    }

    // 对外暴露获取用户信息的方法
    public UserInfo GetUserInfo()
    {
        return _viewModel.UserInfo;
    }
}

4. 主窗口ViewModel

主ViewModel触发子窗口显示,并接收返回数据:

using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;

public class MainViewModel : ObservableObject
{
    private string _userName;
    private string _userSurName;
    private string _userAddress;

    public string UserName
    {
        get => _userName;
        set => SetProperty(ref _userName, value);
    }

    public string UserSurName
    {
        get => _userSurName;
        set => SetProperty(ref _userSurName, value);
    }

    public string UserAddress
    {
        get => _userAddress;
        set => SetProperty(ref _userAddress, value);
    }

    public ICommand GetUserInfoCommand { get; }

    public MainViewModel()
    {
        GetUserInfoCommand = new RelayCommand(ExecuteGetUserInfo);
    }

    private void ExecuteGetUserInfo()
    {
        var dialog = new UserInfoDialog();
        if (dialog.ShowDialog() == true)
        {
            var userInfo = dialog.GetUserInfo();
            UserName = userInfo.UserName;
            UserSurName = userInfo.UserSurName;
            UserAddress = userInfo.UserAddress;
        }
    }
}

5. 主窗口视图(MainWindow.xaml)

绑定ViewModel的属性和命令:

<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:YourNamespace"
        Title="主窗口" Width="400" Height="300">
    <Window.DataContext>
        <vm:MainViewModel />
    </Window.DataContext>
    <StackPanel Margin="10">
        <Button Content="获取用户信息" Command="{Binding GetUserInfoCommand}" Margin="0 0 0 15"/>
        
        <StackPanel>
            <TextBlock Text="用户名:"/>
            <TextBlock Text="{Binding UserName}" Margin="0 0 0 5"/>
            
            <TextBlock Text="姓氏:"/>
            <TextBlock Text="{Binding UserSurName}" Margin="0 0 0 5"/>
            
            <TextBlock Text="地址:"/>
            <TextBlock Text="{Binding UserAddress}"/>
        </StackPanel>
    </StackPanel>
</Window>

补充说明

  • 若不想使用第三方库,可自行实现ICommand接口和INotifyPropertyChanged逻辑。
  • 若要完全解耦窗口显示逻辑,可封装IDialogService接口,让ViewModel依赖该接口,由实现类处理窗口操作,提升ViewModel的可测试性。

内容的提问来源于stack exchange,提问作者Gokhan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 12:35:20