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

如何在C#静态方法中打开WPF窗口并读取TextBox值

基于MVVM的WPF模态输入窗口实现方案

核心思路

通过**模态窗口(ShowDialog)**实现调用等待,结合MVVM分离视图与逻辑,解决命令覆盖、异步提前返回、输入失效等问题。以下是可直接运行的完整实现:

1. 通用RelayCommand实现

public class RelayCommand : ICommand
{
    private readonly Action _execute;
    private readonly Func<bool> _canExecute;

    public event EventHandler CanExecuteChanged;

    public RelayCommand(Action execute, Func<bool> canExecute = null)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute();
    }

    public void Execute(object parameter)
    {
        _execute();
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

2. 输入窗口ViewModel

public class TextInputViewModel : INotifyPropertyChanged
{
    private string _inputText;
    private bool _isOk;

    public string InputText
    {
        get => _inputText;
        set
        {
            _inputText = value;
            OnPropertyChanged();
            OkCommand.RaiseCanExecuteChanged();
        }
    }

    public bool IsOk => _isOk;

    public ICommand OkCommand { get; }
    public ICommand CancelCommand { get; }

    public TextInputViewModel(string presetText = null)
    {
        InputText = presetText;
        OkCommand = new RelayCommand(ExecuteOk, () => !string.IsNullOrWhiteSpace(InputText));
        CancelCommand = new RelayCommand(ExecuteCancel);
    }

    private void ExecuteOk() => _isOk = true;

    private void ExecuteCancel() => _isOk = false;

    public event PropertyChangedEventHandler PropertyChanged;

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

3. 输入窗口视图(XAML)

<Window x:Class="YourNamespace.TextInputWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="输入文本" Width="300" Height="150"
        WindowStartupLocation="CenterOwner">
    <Grid Margin="10">
        <StackPanel>
            <TextBox Margin="0 0 0 10" Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}"/>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                <Button Content="OK" Margin="0 0 10 0" Command="{Binding OkCommand}" IsDefault="True"/>
                <Button Content="Cancel" Command="{Binding CancelCommand}" IsCancel="True"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

4. 窗口后台代码(含静态调用方法)

public partial class TextInputWindow : Window
{
    private readonly TextInputViewModel _viewModel;

    private TextInputWindow(TextInputViewModel viewModel)
    {
        InitializeComponent();
        _viewModel = viewModel;
        DataContext = viewModel;
    }

    // 静态调用入口,支持UI/后台线程调用,返回输入内容(Cancel返回null)
    public static string Show(string presetText = null)
    {
        return Application.Current.Dispatcher.Invoke(() => 
        {
            var viewModel = new TextInputViewModel(presetText);
            var window = new TextInputWindow(viewModel);
            window.Owner = Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w.IsActive);
            
            var dialogResult = window.ShowDialog();
            return dialogResult == true ? viewModel.InputText : null;
        });
    }
}

5. 使用示例

// UI线程直接调用
var userInput = TextInputWindow.Show("请输入内容");
if (userInput != null)
{
    // 处理OK后的输入
    MessageBox.Show($"输入内容:{userInput}");
}

// 后台线程调用
Task.Run(() =>
{
    var input = TextInputWindow.Show("后台线程预设文本");
    // 回到UI线程处理结果
    Application.Current.Dispatcher.Invoke(() =>
    {
        if (input != null) MessageBox.Show($"后台获取输入:{input}");
    });
});

问题修复说明

  • 命令覆盖:ViewModel中OkCommand和CancelCommand分别实例化独立的RelayCommand,避免复用同一实例导致覆盖。
  • BeginInvoke提前返回:改用Dispatcher.Invoke同步调用模态窗口(ShowDialog),阻塞直到用户关闭窗口后再返回结果。
  • TextBox无法输入:确保窗口始终在UI线程创建显示,后台线程调用时通过Dispatcher切换到UI线程,保证输入交互正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:38:13