我正在为常见的vSphere任务编写一个小工具箱。这一次,我想进入WPF。 我已经创建了一个初始的连接到服务器GUI,一切都按设计工作。但是现在我陷入了以下困境:
单击Connect
按钮(btnConnect
)时,我希望它变为灰色/禁用,然后是连接尝试。尝试完成后,它可以再次激活。这是为了防止人们连续多次点击它。
这是我的第一次尝试(我无法展示完整的东西,鉴于它有4个文件,其中有一些东西,我不是允许自由分享,所以我会发布相关内容:
$Window.btnConnect.Add_Click({
$Window.btnConnect.IsEnabled = $False
$Window.btnConnect.Content = 'Connecting...'
Connect-CompanyVIServer -VIServer 'ServerName' -VICredential 'PSCredentialObject'
$Window.btnConnect.Content = 'Connect'
$Window.btnConnect.IsEnabled = $True
})
基本上,我禁用按钮,将其文本更改为Connecting...
,然后连接到VMware vCenter Server。然后我重新更改按钮标签并重新启用它。
当我点击按钮时,表单在加载并进行连接尝试时挂起。这是可以预料的,因为他们在同一个线程中。这没关系,因为表单应该做任何事情,直到尝试完成(同时学习WPF和运行空间会使它太复杂)。
问题在于即使$Window.btnConnect.IsEnabled = $False
位于顶部,表单也不会实际更新,直到整个块完成处理。在此之前,我可以继续点击按钮,它只是缓冲尝试并逐个执行。
所以我认为我将它们分成不同的事件:
$Window.btnConnect.Add_Click({ $Window.btnConnect.IsEnabled = $False })
$Window.btnConnect.Add_IsEnabledChanged({
If ($Window.btnConnect.IsEnabled -eq $False) {
$Window.btnConnect.Content = 'Connecting...'
Connect-CompanyVIServer -VIServer 'ServerName' -VICredential 'PSCredentialObject'
$Window.btnConnect.Content = 'Connect'
$Window.btnConnect.IsEnabled = $True
}
})
勇敢的尝试,虽然没有奏效。我得到完全相同的东西。
所以现在我没有想法。我正在考虑在WPF代码中编写一个触发器以禁用该按钮,但我不知道这是否有效。如果我做某事异步运行连接尝试,我需要能够以某种方式查询结果。我还在试验。与此同时,我来这里寻求帮助。
我的目标是在连接出现后打开一个新窗口,然后让它关闭此窗口。重要的是我阻止用户多次点击按钮。
任何?
答案 0 :(得分:0)
正如上面的评论所暗示的,在特定线程上关闭按钮,进行工作,然后再次将其打开,而不是在更新GUI的线程上。从GUI线程的角度来看,似乎是瞬间发生的,即关闭然后再打开,什么也没有发生。
如果您使用调度程序将消息发送到GUI线程,即
$Window.Dispatcher.invoke([action]{$Window.btnConnect.IsEnabled -eq $False})
您会看到,现在单击一次即可成功禁用按钮(显示为灰色)。不幸的是,这在GUI上是永久的情况。
要使用运行空间在其他线程中执行“关闭,工作,打开”操作,将会发生以下情况(如果不完善,请原谅我):
function my_func {
param($Window,$btnConnect)
$Runspace = [runspacefactory]::CreateRunspace()
$Runspace.ApartmentState = "STA"
$Runspace.ThreadOptions = "ReuseThread"
$Runspace.Open()
$Runspace.SessionStateProxy.SetVariable("Window",$Window)
$Runspace.SessionStateProxy.SetVariable("btnConnect",$btnConnect)
#add server name/credentials with SetVariable so they can be seen in code block
$code = {
$Window.Dispatcher.invoke(
[action] {$Window.Dispatcher.btnConnect.IsEnabled = $False})
$Window.btnConnect.Content = 'Connecting...'
Connect-CompanyVIServer -VIServer 'ServerName' -VICredential 'PSCredentialObject'
$Window.btnConnect.Content = 'Connect'
#below line throws away any clicks since we've disabled button
[System.Windows.Forms.Application]::DoEvents()
$Window.Dispatcher.invoke(
[action] {$Window.Dispatcher.btnConnect.IsEnabled = $True})
}
$PSinstance = [powershell]::Create().AddScript($code)
$PSinstance.Runspace = $Runspace
$job = $PSinstance.BeginInvoke()
}
$Window.btnConnect.Add_Click({
my_func $Window $Window.btnConnect
})