Reduce the complexity of the AttachAndRun code (#19352)
Sometimes the Windows tests fail with no apparent reason, hopefully the slightly reduced complexit and more linear flow makes remote debugging easier. A specific change to first remove the window content before removing the view from the container might help.
This commit is contained in:
Родитель
e3f4ed7685
Коммит
6d4395e7b4
|
@ -24,7 +24,7 @@ namespace Microsoft.Maui.DeviceTests
|
|||
public static partial class AssertionExtensions
|
||||
{
|
||||
public static Task<string> CreateColorAtPointErrorAsync(this CanvasBitmap bitmap, WColor expectedColor, int x, int y) =>
|
||||
CreateColorError(bitmap, $"Expected {expectedColor} at point {x},{y} in renderered view.");
|
||||
CreateColorError(bitmap, $"Expected {expectedColor} at point {x},{y} in rendered view.");
|
||||
|
||||
public static Task WaitForKeyboardToShow(this FrameworkElement view, int timeout = 1000)
|
||||
{
|
||||
|
@ -104,7 +104,7 @@ namespace Microsoft.Maui.DeviceTests
|
|||
}
|
||||
|
||||
public static Task<string> CreateColorAtPointError(this CanvasBitmap bitmap, WColor expectedColor, int x, int y) =>
|
||||
CreateColorError(bitmap, $"Expected {expectedColor} at point {x},{y} in renderered view.");
|
||||
CreateColorError(bitmap, $"Expected {expectedColor} at point {x},{y} in rendered view.");
|
||||
|
||||
public static async Task<string> CreateColorError(this CanvasBitmap bitmap, string message) =>
|
||||
$"{message} This is what it looked like:<img>{await bitmap.ToBase64StringAsync()}</img>";
|
||||
|
@ -165,74 +165,8 @@ namespace Microsoft.Maui.DeviceTests
|
|||
if (view.Parent is Border wrapper)
|
||||
view = wrapper;
|
||||
|
||||
TaskCompletionSource? tcs = null;
|
||||
TaskCompletionSource? unloadedTcs = null;
|
||||
|
||||
if (view.Parent == null)
|
||||
{
|
||||
T result;
|
||||
|
||||
try
|
||||
{
|
||||
await _attachAndRunSemaphore.WaitAsync();
|
||||
|
||||
// prepare to wait for element to be in the UI
|
||||
tcs = new TaskCompletionSource();
|
||||
unloadedTcs = new TaskCompletionSource();
|
||||
|
||||
view.Loaded += OnViewLoaded;
|
||||
|
||||
// attach to the UI
|
||||
Grid grid;
|
||||
var window = (Window)mauiContext!.Services!.GetService(typeof(Window))!;
|
||||
|
||||
if (window.Content is not null)
|
||||
throw new Exception("The window retrieved from the service is already attached to existing content");
|
||||
|
||||
window.Content = new Grid
|
||||
{
|
||||
HorizontalAlignment = WHorizontalAlignment.Center,
|
||||
VerticalAlignment = WVerticalAlignment.Center,
|
||||
Children =
|
||||
{
|
||||
(grid = new Grid
|
||||
{
|
||||
Width = view.Width,
|
||||
Height = view.Height,
|
||||
Children =
|
||||
{
|
||||
view
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
window.Activate();
|
||||
|
||||
// wait for element to be loaded
|
||||
await tcs.Task;
|
||||
view.Unloaded += OnViewUnloaded;
|
||||
|
||||
try
|
||||
{
|
||||
result = await Run(() => action(window));
|
||||
}
|
||||
finally
|
||||
{
|
||||
grid.Children.Clear();
|
||||
await unloadedTcs.Task.WaitAsync(TimeSpan.FromSeconds(5));
|
||||
await Task.Delay(10);
|
||||
window.Close();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_attachAndRunSemaphore.Release();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
// If the view has a parent, it's already attached to the UI
|
||||
if (view.Parent != null)
|
||||
{
|
||||
// Window is not a XAML type so is never on the hierarchy
|
||||
var window = (Window)mauiContext!.Services!.GetService(typeof(Window))!;
|
||||
|
@ -243,22 +177,87 @@ namespace Microsoft.Maui.DeviceTests
|
|||
return await Run(() => action(window));
|
||||
}
|
||||
|
||||
// If the view has no parent, we need to attach it to the UI by creating a new window and using that as the host
|
||||
try
|
||||
{
|
||||
await _attachAndRunSemaphore.WaitAsync();
|
||||
|
||||
// prepare to wait for element to be in the UI
|
||||
var loadedTcs = new TaskCompletionSource();
|
||||
var unloadedTcs = new TaskCompletionSource();
|
||||
|
||||
view.Loaded += OnViewLoaded;
|
||||
|
||||
// attach to the UI
|
||||
Grid viewContainer;
|
||||
var window = (Window)mauiContext!.Services!.GetService(typeof(Window))!;
|
||||
|
||||
if (window.Content is not null)
|
||||
throw new Exception("The window retrieved from the service is already attached to existing content");
|
||||
|
||||
window.Content = new Grid
|
||||
{
|
||||
HorizontalAlignment = WHorizontalAlignment.Center,
|
||||
VerticalAlignment = WVerticalAlignment.Center,
|
||||
Children =
|
||||
{
|
||||
(viewContainer = new Grid
|
||||
{
|
||||
Width = view.Width,
|
||||
Height = view.Height,
|
||||
Children =
|
||||
{
|
||||
view
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
window.Activate();
|
||||
|
||||
// wait for element to be loaded
|
||||
await loadedTcs.Task;
|
||||
view.Unloaded += OnViewUnloaded;
|
||||
|
||||
try
|
||||
{
|
||||
return await Run(() => action(window));
|
||||
}
|
||||
finally
|
||||
{
|
||||
// release all views
|
||||
window.Content = null;
|
||||
viewContainer.Children.Clear();
|
||||
|
||||
// wait for an unload
|
||||
await unloadedTcs.Task.WaitAsync(TimeSpan.FromSeconds(5));
|
||||
await Task.Delay(10);
|
||||
|
||||
// close the window
|
||||
window.Close();
|
||||
}
|
||||
|
||||
void OnViewLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
view.Loaded -= OnViewLoaded;
|
||||
loadedTcs?.SetResult();
|
||||
}
|
||||
|
||||
void OnViewUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
view.Unloaded -= OnViewUnloaded;
|
||||
unloadedTcs?.SetResult();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_attachAndRunSemaphore.Release();
|
||||
}
|
||||
|
||||
static async Task<T> Run(Func<Task<T>> action)
|
||||
{
|
||||
return await action();
|
||||
}
|
||||
|
||||
void OnViewLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
view.Loaded -= OnViewLoaded;
|
||||
tcs?.SetResult();
|
||||
}
|
||||
|
||||
void OnViewUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
view.Unloaded -= OnViewUnloaded;
|
||||
unloadedTcs?.SetResult();
|
||||
}
|
||||
}
|
||||
|
||||
public static Task<CanvasBitmap> ToBitmap(this FrameworkElement view, IMauiContext mauiContext) =>
|
||||
|
|
Загрузка…
Ссылка в новой задаче