PowerShell / WPF:点击

时间:2018-05-28 15:46:45

标签: wpf powershell

我正在为常见的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代码中编写一个触发器以禁用该按钮,但我不知道这是否有效。如果我做某事异步运行连接尝试,我需要能够以某种方式查询结果。我还在试验。与此同时,我来这里寻求帮助。

我的目标是在连接出现后打开一个新窗口,然后让它关闭此窗口。重要的是我阻止用户多次点击按钮。

任何?

1 个答案:

答案 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
})