Skip to content

Commit 90c2d9d

Browse files
weiyuanyueMilly Wei (from Dev Box)Copilot
authored
[Fix]Crashes in model doc page: WinUI element hierarchy and UI thread reentrancy violations (#549)
* scrollview * Add UT * Add UT * fix * fix * fix * remove ut * Fix exception handling in Task.Run and correct Grid.Row index - Move try-catch blocks inside Task.Run to properly capture exceptions from Process.Start() - Fix Grid.Row from 2 to 1 in ModelPage.xaml (parent Grid only has 2 rows) - Ensure telemetry logging happens within Task context for accurate failure tracking * Fix UI thread issue when showing error dialog in Task.Run - Use DispatcherQueue.TryEnqueue to show error dialog on UI thread - Prevents crash when link opening fails in background task * Fix StyleCop SA1513 - Add blank line after closing brace * Update AIDevGallery/Pages/Models/ModelPage.xaml.cs Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Milly Wei (from Dev Box) <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent b40d1b6 commit 90c2d9d

File tree

3 files changed

+85
-70
lines changed

3 files changed

+85
-70
lines changed

AIDevGallery/Controls/Markdown/TextElements/MyHyperlink.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
3-
43
using HtmlAgilityPack;
54
using Markdig.Syntax.Inlines;
65
using Microsoft.UI.Xaml.Documents;
6+
using System;
77
using Windows.Foundation;
88

99
namespace CommunityToolkit.Labs.WinUI.MarkdownTextBlock.TextElements;
@@ -52,15 +52,19 @@ public MyHyperlink(HtmlNode htmlNode, string? baseUrl)
5252

5353
public void AddChild(IAddChild child)
5454
{
55-
if (child.TextElement is Microsoft.UI.Xaml.Documents.Inline inlineChild)
55+
// Hyperlink cannot contain InlineUIContainer - this is a WinUI limitation
56+
if (child.TextElement is not Microsoft.UI.Xaml.Documents.Inline inlineChild || inlineChild is InlineUIContainer)
57+
{
58+
return;
59+
}
60+
61+
try
62+
{
63+
_hyperlink.Inlines.Add(inlineChild);
64+
}
65+
catch (Exception ex)
5666
{
57-
try
58-
{
59-
_hyperlink.Inlines.Add(inlineChild);
60-
}
61-
catch
62-
{
63-
}
67+
System.Diagnostics.Debug.WriteLine($"Exception when adding {inlineChild.GetType().Name}: {ex.GetType().Name} - {ex.Message}");
6468
}
6569
}
6670
}

AIDevGallery/Pages/Models/ModelPage.xaml

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -73,33 +73,28 @@
7373
</StackPanel>
7474

7575

76-
<ScrollViewer
77-
x:Name="RootScroller"
78-
Grid.Row="2"
76+
<Grid
77+
x:Name="ContentGrid"
78+
Grid.Row="1"
7979
Grid.ColumnSpan="2"
80-
Margin="-16,8,-16,-16"
81-
Padding="16,0,16,16"
82-
VerticalAlignment="Stretch"
83-
IsVerticalScrollChainingEnabled="True">
84-
<Grid
85-
x:Name="ContentGrid"
86-
ColumnSpacing="16"
87-
RowSpacing="16">
88-
<Grid.ColumnDefinitions>
89-
<ColumnDefinition Width="*" />
90-
<ColumnDefinition x:Name="SideColumn" Width="380" />
91-
</Grid.ColumnDefinitions>
92-
<Grid.RowDefinitions>
93-
<RowDefinition Height="Auto" />
94-
<RowDefinition Height="Auto" />
95-
<RowDefinition Height="*" />
96-
</Grid.RowDefinitions>
97-
<controls:Card
98-
x:Name="DocumentationCard"
99-
Title="Documentation"
100-
Grid.RowSpan="3"
101-
Icon="{ui:FontIcon Glyph=&#xE7C3;,
102-
FontSize=16}">
80+
Margin="0,8,0,0"
81+
ColumnSpacing="16"
82+
RowSpacing="16">
83+
<Grid.ColumnDefinitions>
84+
<ColumnDefinition Width="*" />
85+
<ColumnDefinition x:Name="SideColumn" Width="380" />
86+
</Grid.ColumnDefinitions>
87+
<Grid.RowDefinitions>
88+
<RowDefinition Height="Auto" />
89+
<RowDefinition Height="Auto" />
90+
<RowDefinition Height="*" />
91+
</Grid.RowDefinitions>
92+
<controls:Card
93+
x:Name="DocumentationCard"
94+
Title="Documentation"
95+
Grid.RowSpan="3"
96+
Icon="{ui:FontIcon Glyph=&#xE7C3;,
97+
FontSize=16}">
10398
<controls:Card.TitleContent>
10499
<HyperlinkButton
105100
Visibility="{x:Bind ModelFamily.DocsUrl, Converter={StaticResource StringVisibilityConverter}}"
@@ -208,7 +203,6 @@
208203
</ItemsView>
209204
</controls:Card>
210205
</Grid>
211-
</ScrollViewer>
212206
<VisualStateManager.VisualStateGroups>
213207
<VisualStateGroup x:Name="LayoutVisualStates">
214208
<VisualState x:Name="WideLayout">
@@ -228,7 +222,6 @@
228222
<Setter Target="ContentGrid.ColumnSpacing" Value="0" />
229223
<Setter Target="DocumentationCard.(Grid.Row)" Value="2" />
230224
<Setter Target="RootGrid.Padding" Value="16,12,16,12" />
231-
<Setter Target="RootScroller.VerticalScrollBarVisibility" Value="Auto" />
232225
</VisualState.Setters>
233226
</VisualState>
234227
</VisualStateGroup>

AIDevGallery/Pages/Models/ModelPage.xaml.cs

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -249,28 +249,40 @@ private void ToolkitActionFlyoutItem_Click(object sender, RoutedEventArgs e)
249249
(AIToolkitAction action, ModelDetails modelDetails) = ((AIToolkitAction, ModelDetails))actionFlyoutItem.Tag;
250250

251251
string toolkitDeeplink = modelDetails.CreateAiToolkitDeeplink(action);
252-
bool wasDeeplinkSuccesful = true;
253-
try
252+
_ = Task.Run(() =>
254253
{
255-
Process.Start(new ProcessStartInfo()
254+
bool wasDeeplinkSuccesful = true;
255+
try
256256
{
257-
FileName = toolkitDeeplink,
258-
UseShellExecute = true
259-
});
260-
}
261-
catch
262-
{
263-
Process.Start(new ProcessStartInfo()
257+
Process.Start(new ProcessStartInfo()
258+
{
259+
FileName = toolkitDeeplink,
260+
UseShellExecute = true
261+
});
262+
}
263+
catch
264264
{
265-
FileName = "https://learn.microsoft.com/en-us/windows/ai/toolkit/",
266-
UseShellExecute = true
267-
});
268-
wasDeeplinkSuccesful = false;
269-
}
270-
finally
271-
{
272-
AIToolkitActionClickedEvent.Log(AIToolkitHelper.AIToolkitActionInfos[action].QueryName, modelDetails.Name, wasDeeplinkSuccesful);
273-
}
265+
try
266+
{
267+
Process.Start(new ProcessStartInfo()
268+
{
269+
FileName = "https://learn.microsoft.com/en-us/windows/ai/toolkit/",
270+
UseShellExecute = true
271+
});
272+
}
273+
catch (Exception ex)
274+
{
275+
// Log the failure to open the fallback URL for diagnostics, but do not surface it to the user.
276+
Debug.WriteLine($"Failed to open AI Toolkit fallback URL: {ex}");
277+
}
278+
279+
wasDeeplinkSuccesful = false;
280+
}
281+
finally
282+
{
283+
AIToolkitActionClickedEvent.Log(AIToolkitHelper.AIToolkitActionInfos[action].QueryName, modelDetails.Name, wasDeeplinkSuccesful);
284+
}
285+
});
274286
}
275287
}
276288

@@ -312,22 +324,28 @@ private void MarkdownTextBlock_OnLinkClicked(object sender, CommunityToolkit.Lab
312324
return;
313325
}
314326

315-
try
327+
_ = Task.Run(() =>
316328
{
317-
var psi = new ProcessStartInfo
329+
try
318330
{
319-
FileName = uri.AbsoluteUri,
320-
UseShellExecute = true
321-
};
322-
Process.Start(psi);
323-
}
324-
catch (Exception ex) when (ex is Win32Exception
325-
|| ex is InvalidOperationException
326-
|| ex is PlatformNotSupportedException)
327-
{
328-
ModelDetailsLinkClickedEvent.Log($"OpenFailed: {uri} | {ex.GetType().Name}: {ex.Message}");
329-
ShowDialog(message: errorMessage);
330-
}
331+
var psi = new ProcessStartInfo
332+
{
333+
FileName = uri.AbsoluteUri,
334+
UseShellExecute = true
335+
};
336+
Process.Start(psi);
337+
}
338+
catch (Exception ex) when (ex is Win32Exception
339+
|| ex is InvalidOperationException
340+
|| ex is PlatformNotSupportedException)
341+
{
342+
ModelDetailsLinkClickedEvent.Log($"OpenFailed: {uri} | {ex.GetType().Name}: {ex.Message}");
343+
DispatcherQueue.TryEnqueue(() =>
344+
{
345+
ShowDialog(message: errorMessage);
346+
});
347+
}
348+
});
331349
}
332350

333351
private async void ShowDialog(string? message)

0 commit comments

Comments
 (0)