fix: 修复消息弹出动画错误 (#1142)

This commit is contained in:
Xu 2025-05-04 11:20:04 +08:00 committed by GitHub
commit db310ef355
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 60 additions and 14 deletions

View file

@ -220,5 +220,6 @@
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natstepfilter" />
</ItemGroup>
</Project>

View file

@ -1,4 +1,4 @@
#include "pch.h"
#include "pch.h"
#include "ToastPage.h"
#if __has_include("ToastPage.g.cpp")
#include "ToastPage.g.cpp"
@ -15,6 +15,7 @@ using namespace winrt::Magpie::implementation;
using namespace winrt;
using namespace Windows::UI::ViewManagement;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Media::Imaging;
namespace winrt::Magpie::implementation {
@ -85,6 +86,8 @@ static void UpdateToastPosition(HWND hwndToast, const RECT& frameRect, bool upda
}
fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring message, HWND hwndTarget, bool showLogo) {
CoreDispatcher dispatcher = Dispatcher();
// !!! HACK !!!
// 重用 TeachingTip 有一个 bug: 前一个 Toast 正在消失时新的 Toast 不会显示。为了
// 规避它,我们每次都创建新的 TeachingTip但要保留旧对象的引用因为播放动画时销毁
@ -96,16 +99,6 @@ fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring
oldTeachingTip = std::move(_oldTeachingTip);
}
CoreDispatcher dispatcher = Dispatcher();
auto weakThis = get_weak();
// oldTeachingTip 卸载后弹窗不会立刻隐藏,稍微等待防止弹窗闪烁
co_await resume_foreground(dispatcher, CoreDispatcherPriority::Low);
if (!weakThis.get()) {
co_return;
}
RECT frameRect;
if (!Win32Helper::GetWindowFrameRect(hwndTarget, frameRect)) {
co_return;
@ -145,9 +138,9 @@ fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring
MessageTextBlock().Text(message);
// !!! HACK !!!
// 移除关闭按钮。必须在模板加载完成后做TeachingTip 没有 Opening 事件,但可以监听 MessageTextBlock 的
// LayoutUpdated 事件,它在 TeachingTip 显示前必然会被引发。
MessageTextBlock().LayoutUpdated([weak(weak_ref(curTeachingTip))](IInspectable const&, IInspectable const&) {
// 移除关闭按钮和修复弹出动画。必须在模板加载完成后做TeachingTip 没有 Opening 事件,但可以监听
// MessageTextBlock 的 LayoutUpdated 事件,它在 TeachingTip 显示前必然会被引发。
MessageTextBlock().LayoutUpdated([this, weak(weak_ref(curTeachingTip))](IInspectable const&, IInspectable const&) {
auto teachingTip = weak.get();
if (!teachingTip) {
return;
@ -159,6 +152,28 @@ fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring
if (DependencyObject closeButton = protectedAccessor.GetTemplateChild(L"AlternateCloseButton")) {
closeButton.as<FrameworkElement>().Visibility(Visibility::Collapsed);
}
// 检查 Tag 记录,修复弹出动画只需执行一次
if (teachingTip.Tag()) {
return;
}
// XAML Islands 中 TeachingTip 弹出动画存在 bug在弹出前有一瞬间会完全显示。为了修复它这里
// 手动将弹窗隐藏,动画开始后再恢复。
for (const Popup& popup : VisualTreeHelper::GetOpenPopupsForXamlRoot(XamlRoot())) {
// 查找 TeachingTip 的弹窗
if (XamlHelper::ContainsControl(popup.Child(), MessageTextBlock())) {
popup.Visibility(Visibility::Collapsed);
Dispatcher().RunAsync(CoreDispatcherPriority::Low, [popup]() {
popup.Visibility(Visibility::Visible);
});
// 修复后使用 Tag 记录
teachingTip.Tag(box_value(0));
break;
}
}
});
// 应用内消息无需显示 logo
@ -181,6 +196,8 @@ fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring
}
}(dispatcher, curTeachingTip, oldTeachingTip);
auto weakThis = get_weak();
// 定期更新弹窗位置
RECT prevframeRect{};
do {

View file

@ -129,4 +129,28 @@ void XamlHelper::UpdateThemeOfTooltips(const DependencyObject& root, ElementThem
} while (!elems.empty());
}
bool XamlHelper::ContainsControl(const DependencyObject& parent, const DependencyObject& target) {
std::vector<DependencyObject> elems{ parent };
do {
std::vector<DependencyObject> temp;
for (const DependencyObject& elem : elems) {
const int count = VisualTreeHelper::GetChildrenCount(elem);
for (int i = 0; i < count; ++i) {
DependencyObject current = VisualTreeHelper::GetChild(elem, i);
if (current == target) {
return true;
}
temp.emplace_back(std::move(current));
}
}
elems = std::move(temp);
} while (!elems.empty());
return false;
}
}

View file

@ -12,6 +12,8 @@ struct XamlHelper {
static void RepositionXamlPopups(const winrt::XamlRoot& root, bool closeFlyoutPresenter);
static void UpdateThemeOfTooltips(const winrt::DependencyObject& root, winrt::ElementTheme theme);
static bool ContainsControl(const winrt::DependencyObject& parent, const winrt::DependencyObject& target);
};
}

View file

@ -22,6 +22,7 @@
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natstepfilter" />
</ItemGroup>
<ItemGroup>
<Manifest Include="app.manifest" />

View file

@ -35,6 +35,7 @@
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natstepfilter" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />