2016-10-29 10 views
0

Ich habe ein scheinbar einfaches Problem: ein Popup, das mich Probleme verursacht sieht in einer abgespeckten Version wie folgt aus (die vollständige Version hat ein Spinner UserControl innerhalb des Border-Elements, aber das seltsame Verhalten ist das gleiche mit oder ohne). Das XAML ist dies:Popup wird nicht geöffnet

<Popup Name="PleaseWaitPopup" Placement="Center" IsOpen="False" StaysOpen="True" Opened="PopupOpened" Closed="PopupClosed"> 
    <Border Width="200" Height="200" Padding="20" Background="#222"> 
     <StackPanel Orientation="Vertical"> 
      <TextBlock Name="WaitHeadTxt" Margin="0 0 0 36" Style="{StaticResource PopupHeadStyle}" VerticalAlignment="Top" FontSize="16"></TextBlock> 
      <Border Width="60" Height="60"> 
      </Border> 
     </StackPanel> 
    </Border> 
</Popup> 

Alle Elemente (PopupOpened(), PopupClosed(), PopupHeadStyle) sind gut getestet und in vielen anderen Pop-ups im gleichen Projekt gut funktionieren.

Als Reaktion auf eine Benutzeraktion möchte ich dieses Popup öffnen, bevor Sie etwas starten, das einige Sekunden dauert (versuchen, ein Gerät über WLAN zu verbinden). Der Code ist wieder einfach:

PleaseWaitPopup.IsOpen = true; 
try 
{ 
    wifiDeviceProvider = new PtpIpProvider(); 
    DeviceManager.AddDevice(wifiDeviceProvider.Connect("192.168.1.1")); 
} 
catch (Exception ex) 
{ 
... 
} 

In meinem Testfall, ich habe nicht ein externes Gerät anschließen, so dass der WiFi-Verbindungsversuch kommt zurück mit einem Timeout nach 10s. Das Popup öffnet sich immer erst NACH dem Timeout, was ich nicht bekomme. Zu diesem Zeitpunkt ist kein weiteres Popup geöffnet.

Ich versuchte dies mit anderen Action-Code (eine FTP-Übertragung anstelle der WiFi-Verbindung) - das Problem blieb, so ist es unwahrscheinlich, dass der WiFi-Verbindungscode damit zu tun hat. Versucht, Dinge asynchron zu machen, indem Sie das Popup oder die WiFi-Verbindung oder beide in einem separaten Thread über "this.Dispatcher.Invoke (() => {...})" öffnen. , aber nichts davon machte einen Unterschied.

Irgendwelche Ideen, was mir hier fehlt? Muss etwas albern sein, aber ich kann es nicht herausfinden. Vielen Dank!

Antwort

0

Ihr WiFi-Code scheint den UI-Thread zu blockieren, bevor er die UI aktualisieren kann. So wird es aktualisiert, sobald es von diesem zurückkehrt (d.h. das Zeitlimit).

Als grundlegende Abhilfe Sie so etwas wie verwenden:

PleaseWaitPopup.IsOpen = true; 

Task.Run(() => 
{ 
    try 
    { 
     wifiDeviceProvider = new PtpIpProvider(); 
     DeviceManager.AddDevice(wifiDeviceProvider.Connect("192.168.1.1")); 
    } 
    catch (Exception ex) 
    { 
     ... 
    } 
}); 

Beachten Sie, dass catch-Block auf dem UI-Thread nicht aber die Benutzeroberfläche dort Aktualisierung ohne Targeting den UI-Thread ist dann so versuchen Sie nicht, . Beachten Sie auch, dass die Aufgabe in diesem Code sofort zurückgegeben wird. Sie müssen einige Änderungen vornehmen, wenn Sie die Aufgabe abwarten möchten.

Im Idealfall möchten Sie vollständig async gehen. Ich würde empfehlen, die Artikel von Stephen Cleary für weitere Informationen zu asynchronen Best Practices zu lesen. z.B. Async/Await - Best Practices in Asynchronous Programming

+0

Rate mal, ich muss wirklich auf Async-Programmierung nachlesen. Aus einem Hintergrund der sequentiellen Programmierung herrührend, ist es alles andere als intuitiv für mich, warum eine nachfolgende Aktion ein vorangehendes UI-Update blockieren würde, insbesondere ein Einzelbefehl, obwohl ich verstehe, dass es eine Aufeinanderfolge von aufeinanderfolgenden Aktionen auslöst. Der Task.Run-Ansatz wird mein Problem immer noch nicht vollständig lösen, da das Popup geöffnet wird, aber der Spinner (aus dem gleichen Grund) nicht dreht, aber wie gesagt, ich verstehe die Async-Programmierung nicht. – Lon

+0

Wie ich es verstehe, arbeiten Windows-Apps mit Nachrichtenwarteschlangen. Obwohl Ihre nachfolgende Aktion kommt, nachdem sie der Warteschlange ** hinzugefügt ** wurde, erfolgt die Nachrichtenverarbeitung nicht sofort. Sie setzen also "IsOpen", sperren dann aber den UIhread mit den WLAN-Anrufen, bevor Windows die Chance bekommt, sie zu verarbeiten. Eine andere Alternative ist die Verwendung einer Fortsetzungsaufgabe - siehe [diese Antwort] (http://stackoverflow.com/questions/4331262/task-continuation-on-ui-thread/12335614#12335614). Sie würden Ihren Spinner vor dem 'Task.Run' starten, dann würden Sie ihn in der Fortsetzungsaufgabe als erledigt markieren (z. B. den Spinner deaktivieren). – Tone

Verwandte Themen