在 UWP App 中实现可拆卸面板
Implementing Detachable Panel in UWP App
我有一个 Image
in a grid where I display some custom content by setting the Image's source to a WritableBitmap
并正在更新位图。我想要做的是实现一个 "detach" 按钮,它将我的图像放在一个单独的 window 上,允许用户将它移动到不同的屏幕,调整它的大小等,独立于我的主应用程序 window。如果新的window关闭了,我想把它带回原来的位置。当图像位于新 window 上时,我想通过更新源位图用新内容不断更新它(就像它在分离之前一样)。
我最初认为我可以在那里创建一个新的 window 和 "move" 我的图像控件,方法是首先将它从其原始父项中删除,然后将其作为子项添加到新 [=27= 中的布局中].我使用了下面的代码:
CoreApplicationView^ newCoreView = CoreApplication::CreateNewView();
int mainViewId = Windows::UI::ViewManagement::ApplicationView::GetApplicationViewIdForWindow(
CoreApplication::MainView->CoreWindow);
uint indexOfObjectToDetach = -1;
bool found = originalGrid->Children->IndexOf(imageToMove, &indexOfObjectToDetach);
if(found)
{
myGrid->Children->RemoveAt(indexOfObjectToDetach);
}
DispatchedHandler^ dispatchHandler = ref new DispatchedHandler([this, mainViewId]()
{
newView_ = Windows::UI::ViewManagement::ApplicationView::GetForCurrentView();
Windows::UI::Xaml::Controls::StackPanel^ newWindowGrid = ref new Windows::UI::Xaml::Controls::StackPanel();
Window::Current->Content = newWindowGrid;
Window::Current->Activate();
newWindowGrid->Children->Append(imageToMove); // Add to new parent
});
create_task(newCoreView->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, dispatchHandler)).then([this, mainViewId]()
{
auto a = newView_->Id;
create_task(ApplicationViewSwitcher::TryShowAsStandaloneAsync(a, ViewSizePreference::Default, mainViewId, ViewSizePreference::Default));
});
但是,在我将图像添加到其新父级的行中,出现 Interface was marshalled for a different thread
错误。经过更多阅读,这是因为每个新的 window 都在自己的线程中,而我正在将一个对象移动到另一个线程。
我是 UWP 的新手,我不确定如何实现这种 UI 行为。我如何 access/transfer 我在一个视图中的状态到另一个视图?
问题确实在于 UWP 中的每个应用程序视图都有自己的线程和自己的 UI 调度程序。当您创建一个控件时,它会绑定到创建它的 UI 线程,因此您不能将它放在另一个应用程序视图上。
解决方案是在新视图的 UI 线程中的 StackPanel
旁边创建新的 Image
。我并没有真正使用 C++,但在 C# 中我会按如下方式实现它:
await newCoreView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
StackPanel panel = new StackPanel();
Image image = new Image();
panel.Children.Add( panel );
image.Source = ...; //your source
Window.Current.Content = frame;
Window.Current.Activate();
newViewId = ApplicationView.GetForCurrentView().Id;
});
进一步说明 - 您可以安全地 "transfer" 普通数据类型到其他视图,问题主要与 UI 相关的类型有关,如控件、页面等
我有一个 Image
in a grid where I display some custom content by setting the Image's source to a WritableBitmap
并正在更新位图。我想要做的是实现一个 "detach" 按钮,它将我的图像放在一个单独的 window 上,允许用户将它移动到不同的屏幕,调整它的大小等,独立于我的主应用程序 window。如果新的window关闭了,我想把它带回原来的位置。当图像位于新 window 上时,我想通过更新源位图用新内容不断更新它(就像它在分离之前一样)。
我最初认为我可以在那里创建一个新的 window 和 "move" 我的图像控件,方法是首先将它从其原始父项中删除,然后将其作为子项添加到新 [=27= 中的布局中].我使用了下面的代码:
CoreApplicationView^ newCoreView = CoreApplication::CreateNewView();
int mainViewId = Windows::UI::ViewManagement::ApplicationView::GetApplicationViewIdForWindow(
CoreApplication::MainView->CoreWindow);
uint indexOfObjectToDetach = -1;
bool found = originalGrid->Children->IndexOf(imageToMove, &indexOfObjectToDetach);
if(found)
{
myGrid->Children->RemoveAt(indexOfObjectToDetach);
}
DispatchedHandler^ dispatchHandler = ref new DispatchedHandler([this, mainViewId]()
{
newView_ = Windows::UI::ViewManagement::ApplicationView::GetForCurrentView();
Windows::UI::Xaml::Controls::StackPanel^ newWindowGrid = ref new Windows::UI::Xaml::Controls::StackPanel();
Window::Current->Content = newWindowGrid;
Window::Current->Activate();
newWindowGrid->Children->Append(imageToMove); // Add to new parent
});
create_task(newCoreView->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, dispatchHandler)).then([this, mainViewId]()
{
auto a = newView_->Id;
create_task(ApplicationViewSwitcher::TryShowAsStandaloneAsync(a, ViewSizePreference::Default, mainViewId, ViewSizePreference::Default));
});
但是,在我将图像添加到其新父级的行中,出现 Interface was marshalled for a different thread
错误。经过更多阅读,这是因为每个新的 window 都在自己的线程中,而我正在将一个对象移动到另一个线程。
我是 UWP 的新手,我不确定如何实现这种 UI 行为。我如何 access/transfer 我在一个视图中的状态到另一个视图?
问题确实在于 UWP 中的每个应用程序视图都有自己的线程和自己的 UI 调度程序。当您创建一个控件时,它会绑定到创建它的 UI 线程,因此您不能将它放在另一个应用程序视图上。
解决方案是在新视图的 UI 线程中的 StackPanel
旁边创建新的 Image
。我并没有真正使用 C++,但在 C# 中我会按如下方式实现它:
await newCoreView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
StackPanel panel = new StackPanel();
Image image = new Image();
panel.Children.Add( panel );
image.Source = ...; //your source
Window.Current.Content = frame;
Window.Current.Activate();
newViewId = ApplicationView.GetForCurrentView().Id;
});
进一步说明 - 您可以安全地 "transfer" 普通数据类型到其他视图,问题主要与 UI 相关的类型有关,如控件、页面等