我正在尝试编写一个函数,在给定的秒数和回调的情况下,在给定的秒数后运行回调.回调不必在同一个线程上.目标语言是C++/CX.
我尝试使用Windows :: System :: Threading :: ThreadPoolTimer,但结果是内存访问异常.问题似乎是无法从计时器正在运行其回调的托管线程访问回调实现(在本机C++中).
ref class TimerDoneCallback {
private:
function<void(void)> m_callback;
public:
void EventCallback(ThreadPoolTimer^ timer) {
m_callback(); // <-- memory exception here
}
TimerDoneCallback(function<void(void)> callback) : m_callback(callback) {}
};
void RealTimeDelayCall(const TimeSpan& duration, function<void(void)> callback) {
auto t = ref new TimerDoneCallback(callback);
auto e = ref new TimerElapsedHandler(t, &TimerDoneCallback::EventCallback);
ThreadPoolTimer::CreateTimer(e, duration);
}
void Test() {
RealTimeDelayCall(duration, [](){}); //after a delay, run 'do nothing'
}
Run Code Online (Sandbox Code Playgroud)
我不想创建一个线程并在其上休眠,因为可能存在许多并发延迟.
我正在编写一个由Window的商店应用程序使用的C++/CX组件.我正在寻找一种方法来完成Task.Delay(1000)在C#中所做的工作.
我有这个在代码中XAML
显示一个.在将被用作一个选择菜单.ListView
C++/CX
ListView
<ListView x:Name="itemsListView"
ItemsSource="{Binding Source={StaticResource MenuDataSourceCVS}}"
HorizontalAlignment="Stretch"
Width="230"
Margin="0,45,0,0"
VerticalAlignment="Top"
Grid.Row="1"
SelectionChanged="itemsListView_SelectionChanged" SelectionMode="Single"
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
FontFamily="Global User Interface">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="40" Width="230">
<TextBlock Text="{Binding Name}"
Margin="10,5" Width="150" Height="30"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
<Border Height="30" Width="30" Margin="5">
<Image Source="{Binding ImageSrc}" Stretch="Fill"/>
</Border>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Run Code Online (Sandbox Code Playgroud)
如下图所示,选择不会占据所有列,并在选中时显示复选标记.
有没有办法消除这种填充和复选标记?
我有一个将由C#WP应用程序使用的WP C++运行时组件.
在C++ Runtime Component中,我有
public interface class ICallback
{
public:
virtual void DoSomething();
};
public ref class WindowsPhoneRuntimeComponent sealed
{
public:
WindowsPhoneRuntimeComponent();
void SetCallback(ICallback ^callback);
IMap<Platform::String^, Platform::Object^>^ CreateDictionary();
};
Run Code Online (Sandbox Code Playgroud)
在C#Application中,我
CallbackImp
实现了ICallback
.然后我做
CallbackImp cb = new CallbackImp ();
WindowsPhoneRuntimeComponent com = new WindowsPhoneRuntimeComponent();
// Set callback
com.SetCallback(cb);
// Get dictionary
IDictionary<string, object> dict = com.CreateDictionary();
Run Code Online (Sandbox Code Playgroud)
我有以下问题
这是关于C++
(不同平台的共享代码)与C#
(Windows Universal App)之间的通信.我们知道,下面是我们如何从一个函数调用C++
来C#
.
C#
class FooCS
{
FooCS()
{
FooC c = new ref FooC();
c.m_GetSomeValueEvent = GetSomeValueEvent;
// Some other stuff ...
}
string GetSomeValueEvent()
{
// Some other stuff ...
return "Hello World";
}
}
Run Code Online (Sandbox Code Playgroud)
C++
public delegate Platform::String GetSomeValueEventHandler();
class FooC
{
public:
event GetSomeValueEventHandler^ m_GetSomeValueEvent;
void someFunction(){
Platform::String^ str = m_GetSomeValueEvent();
// Some other stuff ...
}
}
Run Code Online (Sandbox Code Playgroud)
以上是非常直截了当的.但问题是这个字符串GetSomeValueEvent()
在C#
做一些繁重的任务,比如从数据库中读取数据,我必须做到async
.
async Task<string> GetSomeValueEvent() …
Run Code Online (Sandbox Code Playgroud) (这也可以表述为"如何迭代从C++/CX中的C#Windows运行时组件返回的集合?")
我尝试使用std::for_each
,IIterable<T>
但得到以下编译时错误
错误C2664:'std :: begin':无法将参数1从'my_collection_type ^'转换为'Platform :: String ^'没有可用的用户定义转换运算符,或者指向的类型不相关; 转换需要reinterpret_cast,C风格的转换或函数式转换
我如何迭代收藏?
C#有很多样本,但MSDN上的C++只有一些代码片段.我把它放在一起,我认为它会工作,但我不确定我是否发布了我必须的所有COM引用.
如果我写一个简单的函数,我可以立即得到一个结果.如果我使用async/await
并返回一个Task
- 该方法将在完成任务后返回,但是如果我需要编写一个需要立即返回的方法,然后继续更新结果并可能最终完成任务呢?另外,如果我想在WinRT组件库之外公开它以供其他语言的组件使用,该怎么办?我如何在C#中完成它,我将如何在C++/CX中完成?或JS或许?
例1:
我想公开一个返回一个的属性,ImageSource
所以我可以立即将它从我的MVVM视图模型绑定到XAML视图.加载方法ImageSource
将在一个单独的类中,该类在WinRT组件外部公开(它是一个公共方法).现在我希望该方法是可以等待的,或者至少以某种方式返回我可以等待的任务但也立即返回ImageSource
所以我调用它的属性可以立即返回,因为属性不能是异步的.调用者不知道ImageSource
将是什么类型,因此它无法实例化它,因为ImageSource
它实际上是一个抽象类型,通常表示为BitmapImage
或WriteableBitmap
在我的情况下,两者都可以从方法返回.显然,该方法本身立即知道它是否将返回任何类型的对象,但是它需要一些时间来读取/创建和/或解码图像.
我在想C#中的签名可能是这样的
public async Task<ImageSource> GetImage(
object key,
out ImageSource bitmap,
CancellationToken cancellationToken)
Run Code Online (Sandbox Code Playgroud)
我只是不等待属性访问器中的方法的结果,但我想我能够立即返回位图参数,而当我在其他地方调用或在我的视图模型的代码中的其他地方事件时我会能够等待或取消任务.
例2:
我希望能够列出磁盘中的文件,并在列出所有文件后获得完成的任务,但会立即返回一个IObservableVector视图模型,表示在我的XAML UI中使用的文件,这些文件更新为文件页面异步加载.
在这里,我可能会做类似的事情:
public async Task<int> GetImages(
object queryParemeters,
out ObservableCollection<CustomFileInfoType> files,
CancellationToken cancellationToken)
Run Code Online (Sandbox Code Playgroud)
问题
现在上面看起来几乎不错,但是我认为我不能在WinRT组件之外暴露一个TPL任务,因为Task
它不是WinRT类型,所以我可能给出了一个类似上面的内部方法和一个包含结果的公共方法作为IAsyncOperation
通过调用AsyncInfo.Run()
,传递任务和取消标记.ObservableCollection
也只是.NET,所以我可能需要在它周围创建一个包装器来实现,IObservableVector
因为我不认为它在.NET中可用.这些可能存在其他潜在问题,我不确定这种设计是否正确.
那么 - 我将如何在C++/CX中完成所有这些工作?还是JS?
自从 Visual Studio 2019 正式发布以来,我一直尝试切换到它,但是我在构建基于 C++/CX 的项目时遇到了问题。
我没有重新定位项目,但它仍然配置为使用 v141 平台工具集,即 Visual Studio 2017 Build Tools。
据我所知,我已经在 Visual Studio 2019 中专门安装了所需的构建工具,这里应该很明显:
尽管如此,根据项目属性,未安装 Visual Studio 2017 Build Tools:
当我构建项目时,我收到以下错误:
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Microsoft\VC\v160\Microsoft.CppBuild.targets(378,5): error MSB8020: The build tools for Visual Studio 2017 (Platform)找不到工具集 = 'v141')。要使用 v141 构建工具进行构建,请安装 Visual Studio 2017 构建工具。或者,您可以通过选择“项目”菜单或右键单击解决方案,然后选择“重定向解决方案”来升级到当前的 Visual Studio 工具。
我的安装中是否仍然缺少某些组件,或者这是 Visual Studio 2019 中的错误?
编辑我应该指出我仍然在同一台计算机上安装了 Visual Studio 2017。
当我使用microsoft docs 中的帮助程序函数从 cx 迁移到 winrt时,会发生此错误。我在这里看到类似的问题,但提到的解决方案似乎不适合我。此处提到的解决方案在存在此错误的文件中的任何其他 winrt 标头之前添加 #include <Unknwn.h>。
template <typename T>
T from_cx(Platform::Object ^ from) {
T to{nullptr};
winrt::check_hresult(reinterpret_cast<::IUnknown*>(from)->QueryInterface(
winrt::guid_of<T>(), reinterpret_cast<void**>(winrt::put_abi(to))));
return to;
}
Run Code Online (Sandbox Code Playgroud)
这是整个文件:
#pragma once
#include <Unknwn.h>
#include <winrt/Windows.Foundation.h>
namespace x {
namespace y {
template <typename T>
T from_cx(Platform::Object ^ from) {
T to{nullptr};
winrt::check_hresult(reinterpret_cast<::IUnknown*>(from)->QueryInterface(
winrt::guid_of<T>(), reinterpret_cast<void**>(winrt::put_abi(to))));
return to;
}
template <typename T>
T ^
to_cx(winrt::Windows::Foundation::IUnknown const& from) {
return safe_cast<T ^>(reinterpret_cast<Platform::Object ^>(winrt::get_abi(from)));
}
}
}
Run Code Online (Sandbox Code Playgroud)