Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AppNotificationContent Builder Core Features - part II #2760

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
7119200
First iteration
pmpurifoy Jun 20, 2022
4765ea2
Fix formatting issues
pmpurifoy Jun 20, 2022
30a4376
Remove all references to toast
pmpurifoy Jun 20, 2022
40bd764
Add ProgressBar
pmpurifoy Jun 21, 2022
8668d3a
Remove getters and other nits
pmpurifoy Jun 21, 2022
1545006
Add XML outputs for all examples
pmpurifoy Jun 21, 2022
e470027
Update examples and fix missing png
pmpurifoy Jun 21, 2022
422eae8
Add limitations
pmpurifoy Jun 22, 2022
f55aad3
Add ArgumentSerializer and rename APIs
pmpurifoy Jun 24, 2022
aa7ed04
Fix some nits
pmpurifoy Jun 28, 2022
e0b2847
Fix audio ctors
pmpurifoy Jun 28, 2022
15b477c
Add Deserializer functions and example
pmpurifoy Jun 28, 2022
903956a
Apply review changes
pmpurifoy Jun 29, 2022
bbe8a26
Update AppNotificationBuilder-spec.md
pmpurifoy Jun 29, 2022
f5a745f
Initial commit
pmpurifoy Jun 29, 2022
435a152
Working on it
pmpurifoy Jun 30, 2022
238684d
Add AppNotificationContent
pmpurifoy Jun 30, 2022
5423935
Current impl
pmpurifoy Jul 7, 2022
d427450
Working on unit tests
pmpurifoy Jul 13, 2022
5dc491a
Added unit tests
pmpurifoy Jul 14, 2022
2b24c69
Add Audio tests
pmpurifoy Jul 15, 2022
33a4b1b
Update APITests.cpp
pmpurifoy Jul 15, 2022
5bd1f9e
Remove spec from PR
pmpurifoy Jul 15, 2022
41a699e
Rename AppNotification Builder API to match specs (#2766)
loneursid Jul 25, 2022
5ea7ddd
Update the spec with BuildNotification
pmpurifoy Jul 26, 2022
019077a
Remove unused files
pmpurifoy Jul 26, 2022
48fcdc7
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/erlangl/Bui…
Jul 27, 2022
f45fb7a
Add copyright to all files
pmpurifoy Jul 27, 2022
f81258e
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/purifoypaul…
loneursid Jul 28, 2022
8851cae
Update AppNotificationBuilder.idl
loneursid Jul 28, 2022
224877f
Update pch.cpp
loneursid Jul 28, 2022
861014d
Update WindowsAppRuntime_DLL.vcxproj
loneursid Jul 28, 2022
a934566
Update packages.config
loneursid Jul 28, 2022
19d0cd4
Update AppNotificationBuilder.cpp
loneursid Jul 28, 2022
195492a
Merge branch 'user/purifoypaul/BuilderCoreFeaturesUpdate' into user/e…
Jul 28, 2022
9c6bb22
Addressing comments
pmpurifoy Jul 29, 2022
8f51b89
Update error codes with messages
pmpurifoy Jul 29, 2022
4b59d7f
Merge branch 'user/purifoypaul/BuilderCoreFeaturesUpdate' into user/e…
Jul 29, 2022
f8ed6ca
Add helper file
pmpurifoy Jul 29, 2022
49c02bb
Add SetTimestamp impl
pmpurifoy Jul 29, 2022
3b3b08c
Add AppNotificationAudioLooping
pmpurifoy Jul 29, 2022
c86c655
Merge branch 'user/purifoypaul/BuilderCoreFeaturesUpdate' into user/e…
Jul 29, 2022
604a24f
Add IsSupported to attributes
pmpurifoy Jul 29, 2022
203b318
Merge branch 'user/purifoypaul/BuilderCoreFeaturesUpdate' into user/e…
Jul 29, 2022
f8e8b30
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/erlangl/Bui…
Jul 29, 2022
83f3e0e
AddTextBox
Jul 30, 2022
c53c4dd
AddTextBox with PlaceHolderText and Title
Jul 30, 2022
69e458f
consexpr all the things
Jul 30, 2022
162cd55
code cleanup
Jul 30, 2022
493f0a6
AddComboBox
Jul 30, 2022
eeccf81
Improving validation for selection items
Aug 1, 2022
6624283
Input element limit is for textbox and comboBox combined
Aug 1, 2022
0b994b3
formating
Aug 1, 2022
b3de669
struct isn't required unless we decide to do extra validation in the …
Aug 1, 2022
5dd8f22
Merge branch 'feature/WNP_ContentBuilder_Prev1' into user/erlangl/Bui…
Aug 2, 2022
d52a87c
PR feedback
Aug 2, 2022
01ea539
Check for non-empty IDs
Aug 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ using namespace winrt::Windows::Globalization::DateTimeFormatting;

namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
{
void AppNotificationBuilder::ThrowIfMaxInputItemsExceeded()
{
THROW_HR_IF_MSG(E_INVALIDARG, m_textBoxList.size() + m_comboBoxList.size() >= c_maxTextInputElements, "Maximum number of input elements added");
}

bool AppNotificationBuilder::IsUrgentScenarioSupported()
{
return WindowsVersion::IsWindows10_20H1OrGreater();
Expand Down Expand Up @@ -195,6 +200,25 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::AddTextBox(hstring id)
{
ThrowIfMaxInputItemsExceeded();
loneursid marked this conversation as resolved.
Show resolved Hide resolved
THROW_HR_IF_MSG(E_INVALIDARG, id.empty(), "You must provide an id for the TextBox");


m_textBoxList.push_back(wil::str_printf<std::wstring>(L"<input id='%ls' type='text'/>", id.c_str()));
Copy link
Member

@DrusTheAxe DrusTheAxe Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is ID restricted to never allow standard entities that need to be escaped?

standard entities are the gang of 5 -- greater-than, less-than, apostraphe, quote, ampersand

same comment applies in general - any data the Builder accepts that could contain these escape their content appropriately, e.g.

Bogus but representative example builder.AddButton("Ben & Jerry's") yields what?

<Button Name="Ben & Jerry's"> ==> not well-formed XML
<Button Name="Ben &amp; Jerry&apos;s"> ==> well-formed XML

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it doesn't like " & <, but also it doesn't mind empty string. I am introducing an escape character map in my PR :#2805 @loneursid. We can add these to this map when my PR merges.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using percent encoding for our special characters: https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding

Go ahead and merge this PR when ready, I'll raise another PR regarding this issue since it would require more of a sweeping change in AppNotificationBuilder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'll do that. I'll merge this as is, since it's approved and the build is passing and raise a new PR to address nits from this and other PRs in the series

Copy link
Contributor

@pmpurifoy pmpurifoy Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressing in: #2813

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @DrusTheAxe for catching this. It totally slipped past me.

Since we put anything that comes to us through the builder API into single quotes, technically, that the only character we need to escape, right? Or am I missing something?

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::AddTextBox(hstring id, hstring placeHolderText, hstring title)
{
ThrowIfMaxInputItemsExceeded();
THROW_HR_IF_MSG(E_INVALIDARG, id.empty(), "You must provide an id for the TextBox");

loneursid marked this conversation as resolved.
Show resolved Hide resolved
m_textBoxList.push_back(wil::str_printf<std::wstring>(L"<input id='%ls' type='text' placeHolderContent='%ls' title='%ls'/>", id.c_str(), placeHolderText.c_str(), title.c_str()));
return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::AddButton(AppNotificationButton const& value)
{
THROW_HR_IF_MSG(E_INVALIDARG, m_buttonList.size() >= c_maxButtonElements, "Maximum number of buttons added");
Expand All @@ -203,6 +227,15 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::AddComboBox(AppNotificationComboBox const& value)
{
ThrowIfMaxInputItemsExceeded();

m_comboBoxList.push_back(value);

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AppNotificationBuilder::SetTag(hstring const& value)
{
m_tag = value;
loneursid marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -281,30 +314,34 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
return wil::str_printf<std::wstring>(L"%ls%ls%ls", m_inlineImage.c_str(), m_heroImage.c_str(), m_appLogoOverride.c_str());
}

std::wstring AppNotificationBuilder::GetButtons()
std::wstring AppNotificationBuilder::GetActions()
Copy link
Contributor Author

@loneursid loneursid Aug 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an opportunity here to do some extra validation that goes beyond what the xml schema prescribes. For example, we could ensure that a input-hint in a button elements, refers an existing texbox. That's probably something worth exploring in a future iteration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
if (m_buttonList.size())
{
std::wstring result{};
for (auto input : m_buttonList)
{
if (input.ButtonStyle() != AppNotificationButtonStyle::Default)
{
m_useButtonStyle = true;
}

result.append(input.as<winrt::Windows::Foundation::IStringable>().ToString().c_str());
}
std::wstring result{};
for (auto input : m_textBoxList)
{
result.append(input.c_str());
}

return wil::str_printf<std::wstring>(L"<actions>%ls</actions>", result.c_str());
for (auto input : m_comboBoxList)
{
result.append(input.as<winrt::Windows::Foundation::IStringable>().ToString().c_str());
}
else

for (auto input : m_buttonList)
{
return {};
if (input.ButtonStyle() != AppNotificationButtonStyle::Default)
{
m_useButtonStyle = true;
}

result.append(input.as<winrt::Windows::Foundation::IStringable>().ToString().c_str());
}

return (result.empty()) ? result : wil::str_printf<std::wstring>(L"<actions>%ls</actions>", result.c_str());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: return result.empty() ? ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #2813

}

// You must call GetButtons first to retrieve this value.
// You must call GetActions first to retrieve this value.
std::wstring AppNotificationBuilder::GetButtonStyle()
{
return m_useButtonStyle ? L" useButtonStyle='true'" : L"";
Expand All @@ -316,7 +353,7 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
xmlResult.reserve(c_maxAppNotificationPayload);

// Build the button string and fill m_useButtonStyle
std::wstring buttons{ GetButtons() };
std::wstring actions{ GetActions() };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be awesome to have a comment on how a final string would look like with the payload.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

//  <toast launch="action=AppNotificationClick;sequence={}">
//    <visual>
//      <binding template="ToastGeneric">
//        <image placement="appLogoOverride" hint-crop="circle" src="image.png"/>
//        <text>App Notification with Avatar Image< / text>
//        <text>This is an example message using XML< / text>
//      </binding>
//    </visual>
//    <actions>
//      <input id="ComboBox" type="selection" defaultInput="yes">
//        <selection id="yes" content="Going"/>
//        <selection id="maybe" content="Maybe"/>
//        <selection id="no" content="Decline"/>
//      </input>
//      <input id="textBox" type="text" placeHolderContent="reply"/>
//      <action
//        content="Send"
//        imageUri="ms-appx://images/Icon.png"
//        hint-inputId="textBox"
//        arguments="action=reply&amp;threadId=92187"/>
//      <action
//        content="Open App"
//        arguments="action=OpenApp&amp;sequence={}">
//    </actions>
//  </toast>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to cobble something together with an image, some text, a combobox, a textbox and two buttons and I'm not convainced this would be useful.

I think i't better/easier to lookup the schema online when working in the builder.

I'm also concerned that this kind of comment will get out of sync quickly and become a maintenance nightmare.

I could create a unittest that creates an AppNotification simillar to this example comment. At least we know that this would never get out of sync with the code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Examples in the spec and documentation are welcome (and encouraged).

Not so useful as a comment.

Maybe useful as a doc-comment, if it can be small and meaningful.


xmlResult.append(L"<toast");
xmlResult.append(m_timeStamp);
Expand All @@ -330,7 +367,7 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
xmlResult.append(GetImages());
xmlResult.append(L"</binding></visual>");
xmlResult.append(m_audio.c_str());
xmlResult.append(buttons);
xmlResult.append(actions);
xmlResult.append(L"</toast>");

winrt::Microsoft::Windows::AppNotifications::AppNotification appNotification{ xmlResult };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder MuteAudio();

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AddTextBox(hstring id);
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AddTextBox(hstring id, hstring placeHolderText, hstring title);

// Adds a button to the AppNotificationBuilder
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AddButton(AppNotificationButton const& value);

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder AddComboBox(AppNotificationComboBox const& value);

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder SetTag(winrt::hstring const& value);
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationBuilder SetGroup(winrt::hstring const& value);

Expand All @@ -59,13 +64,14 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
static bool IsUrgentScenarioSupported();

private:
void ThrowIfMaxInputItemsExceeded();
std::wstring GetDuration();
std::wstring GetScenario();
std::wstring GetArguments();
std::wstring GetButtonStyle();
std::wstring GetText();
std::wstring GetImages();
std::wstring GetButtons();
std::wstring GetActions();

std::wstring m_timeStamp{};
AppNotificationDuration m_duration{ AppNotificationDuration::Default };
Expand All @@ -79,6 +85,8 @@ namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
winrt::hstring m_audio{};
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring> m_arguments{ winrt::single_threaded_map<winrt::hstring, winrt::hstring>() };
std::vector<AppNotificationButton> m_buttonList{};
std::vector<std::wstring> m_textBoxList{};
std::vector<AppNotificationComboBox> m_comboBoxList{};
winrt::hstring m_tag{};
winrt::hstring m_group{};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,24 @@ namespace Microsoft.Windows.AppNotifications.Builder
AppNotificationButton SetInvokeUri(Windows.Foundation.Uri protocolUri, String targetAppId);
};

runtimeclass AppNotificationComboBox
{
AppNotificationComboBox(String id);

Windows.Foundation.Collections.IMap<String, String> Items;
String Title;
String SelectedItem;

// Add a selection to the AppNotificationComboBox. The id parameter identifies the item the user selected.
AppNotificationComboBox AddItem(String id, String content);

// Adds a title to display on top
AppNotificationComboBox SetTitle(String value);

// Sets the default selection to be displayed by the AppNotificationComboBox
AppNotificationComboBox SetSelectedItem(String id);
};

enum AppNotificationSoundEvent
{
Default,
Expand Down Expand Up @@ -167,9 +185,14 @@ namespace Microsoft.Windows.AppNotifications.Builder

AppNotificationBuilder MuteAudio();

AppNotificationBuilder AddTextBox(String id);
AppNotificationBuilder AddTextBox(String id, String placeHolderText, String title);

// Adds a button to the AppNotificationBuilder
AppNotificationBuilder AddButton(AppNotificationButton value);

AppNotificationBuilder AddComboBox(AppNotificationComboBox value);

// Constructs a WindowsAppSDK AppNotification object with the XML payload
Microsoft.Windows.AppNotifications.AppNotification BuildNotification();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)AppNotificationBuilder.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)AppNotificationButton.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)AppNotificationComboBox.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)AppNotificationTextProperties.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationBuilder.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationBuilderUtility.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationButton.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationComboBox.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)AppNotificationTextProperties.h" />
</ItemGroup>
</Project>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: GitHub dislikes files ending without a new line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: #2813

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
constexpr size_t c_maxAppNotificationPayload{ 5120 };
constexpr uint8_t c_maxTextElements{ 3 };
constexpr uint8_t c_maxButtonElements{ 5 };
constexpr uint8_t c_maxTextInputElements{ 5 };
constexpr uint8_t c_maxSelectionElements{ 5 };

namespace AppNotificationBuilder
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

#include "pch.h"
#include "AppNotificationComboBox.h"
#include "Microsoft.Windows.AppNotifications.Builder.AppNotificationComboBox.g.cpp"
#include "AppNotificationBuilderUtility.h"

namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
{
AppNotificationComboBox::AppNotificationComboBox(hstring const& id) : m_id(id)
{
THROW_HR_IF_MSG(E_INVALIDARG, id.empty(), "You must provide an id for the ComboBox");
};

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationComboBox AppNotificationComboBox::AddItem(winrt::hstring const& id, winrt::hstring const& content)
{
THROW_HR_IF_MSG(E_INVALIDARG, m_items.Size() >= c_maxSelectionElements, "Maximum number of items added");
loneursid marked this conversation as resolved.
Show resolved Hide resolved
THROW_HR_IF_MSG(E_INVALIDARG, id.empty(), "You must provide an id for the item");

m_items.Insert(id, content);

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationComboBox AppNotificationComboBox::SetTitle(winrt::hstring const& value)
{
m_title = value;
loneursid marked this conversation as resolved.
Show resolved Hide resolved

return *this;
}

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationComboBox AppNotificationComboBox::SetSelectedItem(winrt::hstring const& id)
{
THROW_HR_IF_MSG(E_INVALIDARG, id.empty(), "You must provide an id for the selected item");

m_selectedItem = id;
loneursid marked this conversation as resolved.
Show resolved Hide resolved

return *this;
}

std::wstring AppNotificationComboBox::GetSelectionItems()
{
std::wstring items{};

for (auto pair : m_items)
{
items.append(wil::str_printf<std::wstring>(L"<selection id='%ls' content='%ls'/>", pair.Key().c_str(), pair.Value().c_str()));
}

return items;
}

winrt::hstring AppNotificationComboBox::ToString()
{
std::wstring xmlResult{ wil::str_printf<std::wstring>(L"<input id='%ls' type='selection'%ls%ls>%ls</input>",
m_id.c_str(),
m_title.empty() ? L"" : wil::str_printf<std::wstring>(L" title='%ls'", m_title.c_str()).c_str(),
m_selectedItem.empty() ? L"" : wil::str_printf<std::wstring>(L" defaultInput='%ls'", m_selectedItem.c_str()).c_str(),
loneursid marked this conversation as resolved.
Show resolved Hide resolved
GetSelectionItems().c_str()) };

return xmlResult.c_str();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

#pragma once
#include "Microsoft.Windows.AppNotifications.Builder.AppNotificationComboBox.g.h"

namespace winrt::Microsoft::Windows::AppNotifications::Builder::implementation
{
struct AppNotificationComboBox : AppNotificationComboBoxT<AppNotificationComboBox, winrt::Windows::Foundation::IStringable>
{
AppNotificationComboBox(winrt::hstring const& id);

// Properties
void Items(winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring> const& value) { m_items = value; };
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring> Items() { return m_items; };

void Title(winrt::hstring const& value) { m_title = value; };
winrt::hstring Title() { return m_title; };

void SelectedItem(winrt::hstring const& value) { m_selectedItem = value; };
winrt::hstring SelectedItem() { return m_selectedItem; };

// Fluent Setters
winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationComboBox AddItem(winrt::hstring const& id, winrt::hstring const& content);

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationComboBox SetTitle(winrt::hstring const& value);

winrt::Microsoft::Windows::AppNotifications::Builder::AppNotificationComboBox SetSelectedItem(winrt::hstring const& id);

// IStringable
winrt::hstring ToString();

private:
winrt::hstring m_id{};
winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::hstring> m_items{ winrt::single_threaded_map<winrt::hstring, winrt::hstring>() };
winrt::hstring m_title{};
winrt::hstring m_selectedItem{};

std::wstring GetSelectionItems();
};
}

namespace winrt::Microsoft::Windows::AppNotifications::Builder::factory_implementation
{
struct AppNotificationComboBox : AppNotificationComboBoxT<AppNotificationComboBox, implementation::AppNotificationComboBox>
{
};
}
Loading