我想通过代码隐藏调用WPF窗口,并在应用程序中显示它,无论我在应用程序中的哪个位置。我失败的地方是,调用窗口的静态方法不允许在代码中继续,直到我单击了一个按钮。确定或取消。我现在办不到。然后,OK按钮应该从文本框中读取一个值,然后在方法中处理它。打开WPF窗口时,应在文本框中输入值(如果可用)。
我尝试了以下方法:
WPF窗口
<Window x:Class="MyNamespace.Views.UC.TextboxAndButtons"
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:MyNamespace.UC"
xmlns:viewModels="clr-namespace:MyNamespace.ViewModels"
mc:Ignorable="d"
Height="105" Width="200"
FontFamily="Arial"
WindowStyle="None"
Closing="WindowClosing"
WindowStartupLocation="CenterOwner"
>
<Window.DataContext>
<viewModels:TextboxAndButtonsViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="24"/>
<RowDefinition Height="*"/>
<RowDefinition Height="32"/>
</Grid.RowDefinitions>
<TextBlock Text="Please, input some text if you wish"
FontWeight="Bold"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBox Grid.Row="1"
Height="16"
Margin="5"
Text="{Binding UserText, Mode=TwoWay}"/>
<StackPanel Grid.Row="2"
Orientation="Horizontal"
HorizontalAlignment="Center">
<Button Content="OK"
Width="80"
Height="24"
Margin="10,0"
Command="{Binding OkCommand}" />
<Button Content="Cancel"
Width="80"
Height="24"
Margin="10,0"
Command="{Binding CancelCommand}" />
</StackPanel>
</Grid>
我的TextboxAndroid.Xaml.cs:
public partial class TextboxAndButtons : Window
{
private readonly TextboxAndButtonsViewModel textboxAndButtonsViewModel;
public TextboxAndButtons()
{
InitializeComponent();
this.textboxAndButtonsViewModel = new TextboxAndButtonsViewModel();
this.DataContext = this.textboxAndButtonsViewModel;
if (this.textboxAndButtonsViewModel.CloseAction == null)
{
this.textboxAndButtonsViewModel.CloseAction = this.Close;
this.textboxAndButtonsViewModel.DialogResultValue = this.DialogResult;
}
}
public string UserText
{
get
{
return this.textboxAndButtonsViewModel.UserText;
}
set
{
if (!string.IsNullOrWhiteSpace(value))
{
this.textboxAndButtonsViewModel.UserText = value;
}
}
}
private void WindowClosing(object sender, CancelEventArgs e)
{
try
{
this.DialogResult = this.textboxAndButtonsViewModel.DialogResultValue;
}
catch
{
}
}
}
我的ViewModel类:
public class TextboxAndButtonsViewModel : ViewModelBase
{
public TextboxAndButtonsViewModel()
{
this.OkCommand = new RelayCommand(this.OkCommandExecuted);
this.OkCommand = new RelayCommand(this.CancelCommandExecuted);
}
public bool? DialogResultValue { get; set; }
private void CancelCommandExecuted(object obj)
{
this.DialogResultValue = false;
this.CloseAction();
}
private void OkCommandExecuted(object obj)
{
this.DialogResultValue = true;
this.CloseAction();
}
private string userText;
public string UserText
{
get => userText;
set
{
//userText = value;
// Prism
SetProperty(ref this.userText, value);
}
}
public Action CloseAction { get; set; }
public ICommand OkCommand { get; private set; }
public ICommand CancelCommand { get; private set; }
}
任何类的静态方法:
public class TextWrapper
{
private static TextboxAndButtons textboxAndButtons;
public static string TextBoxValue { get; set; }
public static string CallTextboxWindow(string userText)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new Action(() =>
{
TextBoxValue = TextBoxWindow(userText);
}));
return TextBoxValue;
}
private static string TextBoxWindow(string userText)
{
string text = "";
try
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.DataBind, new Action(() =>
{
textboxAndButtons = new TextboxAndButtons();
textboxAndButtons.UserText = userText;
textboxAndButtons.Owner = Application.Current.Windows.Cast<Window>().LastOrDefault(x => x.IsActive) ?? Application.Current.MainWindow;
textboxAndButtons.ShowDialog();
if (textboxAndButtons.UserText != userText)
{
text = textboxAndButtons.UserText;
}
}));
// Check text
/// {......}
}
catch (Exception ex)
{
string error = ex.Message;
string inner = ex.InnerException.ToString();
}
return text;
}
}
有了调度器,我已经更接近目标了,但它还没有完全工作。
使用上面的代码,我有以下行为:(它从外部调用方法“CallTextBoxWindow(string userText)”)。
当我启动应用程序并在类TextWrapper -->方法CallTextBoxWindow(string userText)--> at“return TextBoxValue;“它跳到那里,这是不正确的。只有当单击WPF窗口中的“确定”按钮时,它才应该出现在那里。如果我让代码在断点处继续,那么窗口会显示,我可以输入文本,单击OK按钮,但随后它不再在方法中。如果我现在点击OK按钮,窗口关闭,就这样。
如果我只在调度程序中使用fixke,那么我会有一个奇怪的行为,我不能在文本框中输入任何东西。
我的目标是将它构建为MVVM,但我也很高兴它能在其中工作。
谢谢你的帮忙。
2条答案
按热度按时间icomxhvb1#
我假设,您需要某种
MessageBox
,但用于用户输入而不是通知。有很多关于“如何创建自定义
MessageBox
'es”的例子。对于目前的问题,我将使用我自己的想法。因此,首先,您需要创建一个单独的窗口(视图),其中包含
TextBox
用于用户输入和OK/Cancel按钮。UserTextInputWindow.xaml:
这一个看起来像下面。Ofc,你可以按照你的意愿定制它。
在XAML中可以看到,我使用
UserTextInputViewModel
类作为此窗口的ViewModel,其代码隐藏是:UserTextInputViewModel.cs:
ParameterizedCommand
实现是对一些Action
的简单 Package ,并以object
作为参数,因此Action可以通过Command
属性绑定到XAML中的Button
。parameterizedCommand.cs:
因此,事实上,ViewModel只是存储用户输入,并通过关闭窗口(并在取消时重置用户输入)来处理OK/Cancel按钮单击。
最后,
UserTextInputWindow
本身的代码隐藏,我隐藏了默认构造函数,并将其调用替换为静态方法Show
:UserTextInputWindow.xaml.cs:
我的这个例子的项目结构看起来像这样(与这个例子无关的项目被绘制):
使用方法与
MessageBox
非常相似。它也可以安全地从任何线程。不确定这是纯粹和正确的MVVM方法,但它的工作。你可以纠正我。
rkkpypqq2#
您可以使用
SemaphoreSlim
异步等待,直到窗口关闭,以不阻塞UI线程: