gpt4 book ai didi

c# - WPF MVVM 控制台输出到 View 中的文本框

转载 作者:行者123 更新时间:2023-12-03 11:01:37 24 4
gpt4 key购买 nike

我正在编写一个更新文件的应用程序,然后最终将更新的文件导入数据库。我想显示有关正在更新哪个文件以及该过程何时完成的消息。我希望消息来自控制台,因为最终我使用的导入器库会通过控制台显示有用的消息,我也希望显示这些消息。我之前可以在 WPF 应用程序中执行此操作,但我的所有代码都在 View 后面的代码中,我想保留 MVVM 模式并将代码分离到 ViewModel 中。我的问题是我不知道如何获取对 View 中的 TextBox 的引用。一旦我能够在我的 ViewModel 中获得 TextBox,我将能够将控制台写入发送到 TextBox。

这是我的看法

<Window x:Class="DICOM_Importer.Views.StudyImporterView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DICOM_Importer.Views"
mc:Ignorable="d"
Background="Gold"
Title="Importer" Height="450" Width="800">
<Grid Style="{StaticResource gridBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="125" />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="280" />
</Grid.RowDefinitions>

<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal">
<Label Style="{Binding Source={StaticResource studyTitle}}" Content="Study:" />
<Label Style="{Binding Source={StaticResource studyTitle}}" Name="StudyImportViewStudyText" Content="{Binding ImporterTitle}" />
</StackPanel>

<StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Orientation="Horizontal" >
<Label Style="{Binding Source={StaticResource studyTitle}}" Content="Import Directory" />
<Label Style="{Binding Source={StaticResource studyTitle}}" Content="{Binding ImporterPath}" />
</StackPanel>

<Button Grid.Column="2" Grid.Row="1" Command="{Binding ImportCommand}" Style="{Binding Source={StaticResource buttonStyleImport}}" Content="Submit" />

<TextBox Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="2" x:Name="ImportConsole" />

</Grid>
</Window>

这是 View 模型
using DICOM_Importer.Commands;
using DICOM_Importer.Views;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace DICOM_Importer.ViewModels
{
public class StudyImporterViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private string importerTitle;
private string importerPath;
public DirectoryInfo[] directories;
GetIndividualSubjectDirectories subjectDirectories = new GetIndividualSubjectDirectories();
ConsoleOutputStream outputter;

/// <summary>
/// Gets the study information from the HomeView
/// </summary>
public String ImporterTitle
{
get { return importerTitle; }
set
{
importerTitle = value;
OnPropertyChanged("ImporterTitle");
}
}

public String ImporterPath
{
get { return importerPath; }
set
{
importerPath = value;
OnPropertyChanged("ImporterPath");
}
}


public StudyImporterViewModel()
{
ImportCommand = new ActivateImport(this);
outputter = new ConsoleOutputStream(ImportConsole); //Here is where the error is
Console.SetOut(outputter);
}

public ICommand ImportCommand
{
get;
private set;
}

public void Import()
{
MessageBoxResult result = MessageBox.Show("This will import every series in the Import Directory. Are you sure you want to Import?", "Import Confirmation", MessageBoxButton.OKCancel);


switch (result)
{
case MessageBoxResult.OK:
if(importerTitle == "SPIROMICS2")
{
Console.WriteLine("Importing SPIROMICS2 Scans to Mifar");
directories = subjectDirectories.GetSubjectDirectories(importerPath);
subjectDirectories.GetSeriesDirectories(directories);
Console.WriteLine("Import Complete");

}
else if(importerTitle == "BLF")
{
Console.WriteLine("BLF");
}
else if(importerTitle == "PRECISE")
{
Console.WriteLine("PRECISE");
}

break;
case MessageBoxResult.Cancel:
MessageBox.Show("CANCEL", "Nope!");
break;
}
}

#region Error Model
public string Error
{
get;
set;
}
#endregion

#region Error Definition
public string this[string columnName]
{
get
{
if (columnName == "ImporterTitle")
{
if (String.IsNullOrWhiteSpace(ImporterPath))
{
Error = "There is no selected study to import";
}
else
{
Error = null;
}
}
return Error;
}
}
#endregion

#region PropertyChangedEventHandler
public event PropertyChangedEventHandler PropertyChanged;

private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;

if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion


}
}

这是我的 ConsoleOutputStream 命令
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace DICOM_Importer.Commands
{
class ConsoleOutputStream : TextWriter
{
TextBox textBox = null;


public ConsoleOutputStream(TextBox ouput)
{
textBox = ouput;
}

public override void Write(char value)
{
base.Write(value);
textBox.Dispatcher.BeginInvoke(new Action(() => {
textBox.AppendText(value.ToString());
}));
}

public override Encoding Encoding
{
get { return System.Text.Encoding.UTF8; }
}
}
}

这是按钮的命令,它将启动所有文件更改和导入
using DICOM_Importer.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace DICOM_Importer.Commands
{
/// <summary>
/// Starts the import processes on a button click if there is a study available
/// </summary>
class ActivateImport : ICommand
{

private StudyImporterViewModel _studyImporterViewModel;

public ActivateImport(StudyImporterViewModel viewModel)
{
_studyImporterViewModel = viewModel;
}



public event EventHandler CanExecuteChanged
{
//this is forcing the CommandManager to check the ICommand again. If we didn't have this then the buitton wouldl only be
//disabled if the window was loaded with a blank name, not if it was loaded with a name and then was deleted by the user
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

public bool CanExecute(object parameter)
{
return String.IsNullOrWhiteSpace(_studyImporterViewModel.Error);
}

public void Execute(object parameter)
{
_studyImporterViewModel.Import();
}
}
}

任何帮助将非常感激!

最佳答案

您可以将控制台输出重定向到 StringWriter然后在每次生成新的控制台输出时将其内容写入绑定(bind)到文本框的字符串中。

查看型号

private StringWriter _sw;
public string ConsoleOut { /* getter and setter */ }

// inside constructor
_sw = new StringWriter();
Console.SetOut(sw);
Console.SetError(sw);

xml

<TextBlock Text="{Binding Path=ConsoleOut, Mode=OneWay}"/>

这里的问题是,每次你想在 TextBlock 中显示控制台输出时,你都需要用 S = _sw.ToString(); 更新 S 的值。

解决方案

我找到了 this answer实现增强的 StringWriter每次写入时触发事件的类。有了这个,你只需要做一个简单的更新:

查看型号

private StringWriterExt _sw;
public string ConsoleOut { /* getter and setter */ }

// inside constructor
_sw = new StringWriterExt(true);
Console.SetOut(sw);
Console.SetError(sw);
_sw.Flushed += (s, a) => ConsoleOut = _sw.ToString();

关于c# - WPF MVVM 控制台输出到 View 中的文本框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60567294/

24 4 0
文章推荐: c# - WPF 应用程序中 Controller 的位置是什么
文章推荐: c# - 使用MVVM将List 设置为模型