首页 文章

使用C / WinRT使用设备填充ListBox,显示其名称?

提问于
浏览
0

我有一个DeviceSelector类,它显示了一个要选择的设备列表 . 我想以编程方式执行此操作,而不使用XAML文件 . 由于我发现很难从C中正确使用ListBox控件,因此我有以下问题:

  • 如何正确使用 DisplayMemberPath 属性在ListBox中显示 Name 属性?应传入属性的路径,但由于某种原因,这似乎在我的程序中不起作用 .

  • 是否可以使用 ItemsSource 属性使用Collection填充ListBox?从文档中不清楚作为参数传递什么,并且没有那么多非XAML C示例 .

下面我有我简化的DeviceSelector类,我提供了一个简单的应用程序用于故障排除 .

编辑1:

DisplayMemberPath不像我期望的那样工作,并不是特定于C / WinRT . 我尝试使用XAML和代码实现它,使用:

<ListBox x:Name="DeviceSelector" DisplayMemberPath="Name">
...
</ListBox>

使用设备填充ListBox后,它也不显示名称 .


DeviceSelector.h

#pragma once

#include <winrt\Windows.Foundation.h>
#include <winrt\Windows.UI.Xaml.Controls.h>


struct DeviceSelector : winrt::Windows::UI::Xaml::Controls::ListBox
{
    DeviceSelector();
    winrt::Windows::Foundation::IAsyncAction ShowAllAsync();
};

DeviceSelector.cpp

#include "pch.h"
#include "DeviceSelector.h"

#include <winrt\Windows.Devices.Enumeration.h>
#include <winrt\Windows.Foundation.h>
#include <winrt\Windows.UI.Xaml.Controls.h>


using namespace winrt::Windows::Devices::Enumeration;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml::Controls;


DeviceSelector::DeviceSelector()
{
    //DOES NOT WORK:
    //DisplayMemberPath(L"Name");
}


IAsyncAction DeviceSelector::ShowAllAsync()
{
    DeviceInformationCollection devices = co_await DeviceInformation::FindAllAsync();

    //DOES NOT WORK:
    //ItemsSource(devices);

    //DOES WORK:
    //But does not display device names, without the right DisplayMemberPath.
    for (DeviceInformation device : devices)
    {
        Items().Append(device);
    }
}

Main.cpp

#include "pch.h"

#include <winrt\Windows.ApplicationModel.Activation.h>
#include <winrt\Windows.UI.Xaml.h>

#include "DeviceSelector.h"


using namespace winrt;
using namespace winrt::Windows::ApplicationModel::Activation;
using namespace winrt::Windows::UI::Xaml;


struct App : ApplicationT<App>
{
    DeviceSelector selector;

    void OnLaunched(LaunchActivatedEventArgs const &)
    {
        //Create window with a DeviceSelector instance.
        Window window = Window::Current();
        window.Content(selector);
        window.Activate();

        //Populate selector with devices.
        selector.ShowAllAsync();
    }

    static void Initialize(ApplicationInitializationCallbackParams const &)
    {
        make<App>();
    }

    static void Start()
    {
        Application::Start(App::Initialize);
    }
};

int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    App::Start();
}

pch.h

#pragma once

#pragma comment(lib, "windowsapp")

#include <winrt\Windows.ApplicationModel.Activation.h>
#include <winrt\Windows.Devices.Enumeration.h>
#include <winrt\Windows.Foundation.h>
#include <winrt\Windows.Media.Devices.h>
#include <winrt\Windows.UI.Xaml.h>
#include <winrt\Windows.UI.Xaml.Controls.h>

1 回答

  • 1

    以您描述的方式连接Bindings需要:

    • Xaml编译器支持(即将推出,但仍在预览中)

    要么

    • 您需要指向实现ICustomPropertyProviderICustomProperty 的对象(如果您希望在数据值更改时更新 ListBox 项目,则需要 INotifyPropertyChanged ) .

    这是因为 DataMemberPath 依赖于运行时反射(它在运行时查询具有给定名称的属性 - 更多详细信息here) . 一个普通的WinRT类不能将它包装成可以的东西 .

    如果你决定采用ICustomPropertyProvider路线,这里是一个黑客攻击的示例实现,只挂钩 Name 属性 . 这只是概念的快速证明;有更好,更可扩展的方法:

    #include <winrt/Windows.ApplicationModel.Activation.h>
    #include <winrt/Windows.Devices.Enumeration.h>
    #include <winrt/Windows.Foundation.h>
    #include <winrt/Windows.UI.Xaml.Controls.h>
    #include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
    #include <winrt/Windows.UI.Xaml.Data.h>
    #include <winrt/Windows.UI.Xaml.Interop.h>
    
    using namespace winrt;
    
    using namespace Windows::ApplicationModel::Activation;
    using namespace Windows::Devices::Enumeration;
    using namespace Windows::Foundation;
    using namespace Windows::UI::Xaml;
    using namespace Windows::UI::Xaml::Controls;
    using namespace Windows::UI::Xaml::Data;
    using namespace Windows::UI::Xaml::Interop;
    
    struct DeviceInfoCustomProperty : implements<DeviceInfoCustomProperty, ICustomProperty>
    {
        DeviceInfoCustomProperty(bool canRead, bool canWrite, hstring name, TypeName type)
            : m_CanRead(canRead)
            , m_CanWrite(canWrite)
            , m_Name(std::move(name))
            , m_Type(std::move(type))
        {
        }
    
        bool CanRead() const noexcept
        {
            return m_CanRead;
        }
    
        bool CanWrite() const noexcept
        {
            return m_CanWrite;
        }
    
        hstring Name() const noexcept
        {
            return m_Name;
        }
    
        TypeName Type() const noexcept
        {
            return m_Type;
        }
    
        IInspectable GetIndexedValue(const IInspectable&, const IInspectable&) const noexcept { return nullptr; }
        IInspectable GetValue(const IInspectable& target) const;
        void SetIndexedValue(const IInspectable&, const IInspectable&, const IInspectable&) const noexcept {}
        void SetValue(const IInspectable&, const IInspectable&) const noexcept {}
    
        IInspectable m_Object;
        bool m_CanRead;
        bool m_CanWrite;
        hstring m_Name;
        TypeName m_Type;
    };
    
    struct DeviceInfoWrapper : implements<DeviceInfoWrapper, ICustomPropertyProvider>
    {
        explicit DeviceInfoWrapper(DeviceInformation info)
            : m_info(std::move(info))
        {
        }
    
        TypeName Type() const noexcept
        {
            return xaml_typename<DeviceInformation>();
        }
    
        ICustomProperty GetCustomProperty(const hstring& name)
        {
            if (name == L"Name")
            {
                return make<DeviceInfoCustomProperty>(true, false, name, xaml_typename<hstring>());
            }
            return nullptr;
        }
    
        ICustomProperty GetIndexedProperty(const hstring&, const TypeName&)
        {
            return nullptr;
        }
    
        hstring GetStringRepresentation()
        {
            return L"DeviceWrapper";
        }
    
        DeviceInformation m_info;
    };
    
    IInspectable DeviceInfoCustomProperty::GetValue(const IInspectable& target) const
    {
        // Temporary workaround if preview SDK <= 17095
        auto wrapper = from_abi<DeviceInfoWrapper>(target.as<ICustomPropertyProvider>());
        // else
        auto wrapper = target.as<DeviceInfoWrapper>();
    
        if (m_Name == L"Name")
        {
            return box_value(wrapper->m_info.Name());
        }
        return nullptr;
    }
    
    struct DeviceSelector : winrt::Windows::UI::Xaml::Controls::ListBoxT<DeviceSelector>
    {
        DeviceSelector()
        {
            DisplayMemberPath(L"Name");
            SelectionChanged([](const IInspectable&, const SelectionChangedEventArgs& args)
            {
                for (const auto& item : args.AddedItems())
                {
                    // DEBUG - verifying that this is, in fact, the object
                    auto wrapper = item.as<DeviceInfoWrapper>();
                    wrapper->m_info.Name().c_str();
                }
            });
        }
    
        fire_and_forget ShowAllAsync()
        {
            DeviceInformationCollection devices = co_await DeviceInformation::FindAllAsync();
            for (const auto& device : devices)
            {
                Items().Append(make<DeviceInfoWrapper>(device));
            }
        }
    };
    
    struct App : ApplicationT<App>
    {
        DeviceSelector selector;
    
        void OnLaunched(LaunchActivatedEventArgs const &)
        {
    
            Window window = Window::Current();
            window.Content(selector.try_as<UIElement>());
            window.Activate();
    
            selector.ShowAllAsync();
        }
    };
    
    int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
    {
        Application::Start([](auto &&) { make<App>(); });
    }
    

相关问题