MainPage.xaml.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. //*********************************************************
  2. //
  3. // Copyright (c) Microsoft. All rights reserved.
  4. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
  5. // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
  6. // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
  7. // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  8. //
  9. //*********************************************************
  10. //
  11. // MainPage.xaml.cpp
  12. // Implementation of the MainPage.xaml class.
  13. //
  14. #include "pch.h"
  15. #include "MainPage.xaml.h"
  16. #include "App.xaml.h"
  17. #include <collection.h>
  18. using namespace Windows::UI::Xaml;
  19. using namespace Windows::UI::Xaml::Controls;
  20. using namespace Windows::Foundation;
  21. using namespace Windows::Foundation::Collections;
  22. using namespace Platform;
  23. using namespace SDKSample;
  24. using namespace Windows::UI::Xaml::Navigation;
  25. using namespace Windows::UI::Xaml::Interop;
  26. using namespace Windows::Graphics::Display;
  27. using namespace Windows::UI::ViewManagement;
  28. MainPage^ MainPage::Current = nullptr;
  29. MainPage::MainPage()
  30. {
  31. InitializeComponent();
  32. // This frame is hidden, meaning it is never shown. It is simply used to load
  33. // each scenario page and then pluck out the input and output sections and
  34. // place them into the UserControls on the main page.
  35. HiddenFrame = ref new Windows::UI::Xaml::Controls::Frame();
  36. HiddenFrame->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
  37. ContentRoot->Children->Append(HiddenFrame);
  38. FeatureName->Text = FEATURE_NAME;
  39. this->SizeChanged += ref new SizeChangedEventHandler(this, &MainPage::MainPage_SizeChanged);
  40. Scenarios->SelectionChanged += ref new SelectionChangedEventHandler(this, &MainPage::Scenarios_SelectionChanged);
  41. MainPage::Current = this;
  42. autoSizeInputSectionWhenSnapped = true;
  43. }
  44. /// <summary>
  45. /// We need to handle SizeChanged so that we can make the sample layout property
  46. /// in the various layouts.
  47. /// </summary>
  48. /// <param name="sender"></param>
  49. /// <param name="e"></param>
  50. void MainPage::MainPage_SizeChanged(Object^ sender, SizeChangedEventArgs^ e)
  51. {
  52. InvalidateSize();
  53. MainPageSizeChangedEventArgs^ args = ref new MainPageSizeChangedEventArgs();
  54. args->ViewState = ApplicationView::Value;
  55. MainPageResized(this, args);
  56. }
  57. void MainPage::InvalidateSize()
  58. {
  59. // Get the window width
  60. double windowWidth = this->ActualWidth;
  61. if (windowWidth != 0.0)
  62. {
  63. // Get the width of the ListBox.
  64. double listBoxWidth = Scenarios->ActualWidth;
  65. // Is the ListBox using any margins that we need to consider?
  66. double listBoxMarginLeft = Scenarios->Margin.Left;
  67. double listBoxMarginRight = Scenarios->Margin.Right;
  68. // Figure out how much room is left after considering the list box width
  69. double availableWidth = windowWidth - listBoxWidth;
  70. // Is the top most child using margins?
  71. double layoutRootMarginLeft = ContentRoot->Margin.Left;
  72. double layoutRootMarginRight = ContentRoot->Margin.Right;
  73. // We have different widths to use depending on the view state
  74. if (ApplicationView::Value != ApplicationViewState::Snapped)
  75. {
  76. // Make us as big as the the left over space, factoring in the ListBox width, the ListBox margins.
  77. // and the LayoutRoot's margins
  78. InputSection->Width = ((availableWidth) -
  79. (layoutRootMarginLeft + layoutRootMarginRight + listBoxMarginLeft + listBoxMarginRight));
  80. }
  81. else
  82. {
  83. // Make us as big as the left over space, factoring in just the LayoutRoot's margins.
  84. if (autoSizeInputSectionWhenSnapped)
  85. {
  86. InputSection->Width = (windowWidth - (layoutRootMarginLeft + layoutRootMarginRight));
  87. }
  88. }
  89. }
  90. InvalidateViewState();
  91. }
  92. void MainPage::InvalidateViewState()
  93. {
  94. // Are we going to snapped mode?
  95. if (ApplicationView::Value == ApplicationViewState::Snapped)
  96. {
  97. Grid::SetRow(DescriptionText, 3);
  98. Grid::SetColumn(DescriptionText, 0);
  99. Grid::SetRow(InputSection, 4);
  100. Grid::SetColumn(InputSection, 0);
  101. Grid::SetRow(FooterPanel, 2);
  102. Grid::SetColumn(FooterPanel, 0);
  103. }
  104. else
  105. {
  106. Grid::SetRow(DescriptionText, 1);
  107. Grid::SetColumn(DescriptionText, 1);
  108. Grid::SetRow(InputSection, 2);
  109. Grid::SetColumn(InputSection, 1);
  110. Grid::SetRow(FooterPanel, 1);
  111. Grid::SetColumn(FooterPanel, 1);
  112. }
  113. // Since we don't load the scenario page in the traditional manner (we just pluck out the
  114. // input and output sections from the page) we need to ensure that any VSM code used
  115. // by the scenario's input and output sections is fired.
  116. VisualStateManager::GoToState(InputSection, "Input" + LayoutAwarePage::DetermineVisualState(ApplicationView::Value), false);
  117. VisualStateManager::GoToState(OutputSection, "Output" + LayoutAwarePage::DetermineVisualState(ApplicationView::Value), false);
  118. }
  119. void MainPage::PopulateScenarios()
  120. {
  121. ScenarioList = ref new Platform::Collections::Vector<Object^>();
  122. // Populate the ListBox with the list of scenarios as defined in Constants.cpp.
  123. for (unsigned int i = 0; i < scenarios->Length; ++i)
  124. {
  125. Scenario s = scenarios[i];
  126. ListBoxItem^ item = ref new ListBoxItem();
  127. item->Name = s.ClassName;
  128. item->Content = (i + 1).ToString() + ") " + s.Title;
  129. ScenarioList->Append(item);
  130. }
  131. // Bind the ListBox to the scenario list.
  132. Scenarios->ItemsSource = ScenarioList;
  133. Scenarios->ScrollIntoView(Scenarios->SelectedItem);
  134. }
  135. /// <summary>
  136. /// This method is responsible for loading the individual input and output sections for each scenario. This
  137. /// is based on navigating a hidden Frame to the ScenarioX.xaml page and then extracting out the input
  138. /// and output sections into the respective UserControl on the main page.
  139. /// </summary>
  140. /// <param name="scenarioName"></param>
  141. void MainPage::LoadScenario(String^ scenarioName)
  142. {
  143. autoSizeInputSectionWhenSnapped = true;
  144. // Load the ScenarioX.xaml file into the Frame.
  145. TypeName scenarioType = {scenarioName, TypeKind::Custom};
  146. HiddenFrame->Navigate(scenarioType, this);
  147. // Get the top element, the Page, so we can look up the elements
  148. // that represent the input and output sections of the ScenarioX file.
  149. Page^ hiddenPage = safe_cast<Page^>(HiddenFrame->Content);
  150. // Get each element.
  151. UIElement^ input = safe_cast<UIElement^>(hiddenPage->FindName("Input"));
  152. UIElement^ output = safe_cast<UIElement^>(hiddenPage->FindName("Output"));
  153. if (input == nullptr)
  154. {
  155. // Malformed input section.
  156. NotifyUser("Cannot load scenario input section for " + scenarioName +
  157. " Make sure root of input section markup has x:Name of 'Input'", NotifyType::ErrorMessage);
  158. return;
  159. }
  160. if (output == nullptr)
  161. {
  162. // Malformed output section.
  163. NotifyUser("Cannot load scenario output section for " + scenarioName +
  164. " Make sure root of output section markup has x:Name of 'Output'", NotifyType::ErrorMessage);
  165. return;
  166. }
  167. // Find the LayoutRoot which parents the input and output sections in the main page.
  168. Panel^ panel = safe_cast<Panel^>(hiddenPage->FindName("LayoutRoot"));
  169. if (panel != nullptr)
  170. {
  171. unsigned int index = 0;
  172. UIElementCollection^ collection = panel->Children;
  173. // Get rid of the content that is currently in the intput and output sections.
  174. collection->IndexOf(input, &index);
  175. collection->RemoveAt(index);
  176. collection->IndexOf(output, &index);
  177. collection->RemoveAt(index);
  178. // Populate the input and output sections with the newly loaded content.
  179. InputSection->Content = input;
  180. OutputSection->Content = output;
  181. ScenarioLoaded(this, nullptr);
  182. }
  183. else
  184. {
  185. // Malformed Scenario file.
  186. NotifyUser("Cannot load scenario: " + scenarioName + ". Make sure root tag in the '" +
  187. scenarioName + "' file has an x:Name of 'LayoutRoot'", NotifyType::ErrorMessage);
  188. }
  189. }
  190. void MainPage::Scenarios_SelectionChanged(Object^ sender, SelectionChangedEventArgs^ e)
  191. {
  192. if (Scenarios->SelectedItem != nullptr)
  193. {
  194. NotifyUser("", NotifyType::StatusMessage);
  195. LoadScenario((safe_cast<ListBoxItem^>(Scenarios->SelectedItem))->Name);
  196. InvalidateSize();
  197. }
  198. }
  199. void MainPage::NotifyUser(String^ strMessage, NotifyType type)
  200. {
  201. switch (type)
  202. {
  203. case NotifyType::StatusMessage:
  204. // Use the status message style.
  205. StatusBlock->Style = safe_cast<Windows::UI::Xaml::Style^>(this->Resources->Lookup("StatusStyle"));
  206. break;
  207. case NotifyType::ErrorMessage:
  208. // Use the error message style.
  209. StatusBlock->Style = safe_cast<Windows::UI::Xaml::Style^>(this->Resources->Lookup("ErrorStyle"));
  210. break;
  211. default:
  212. break;
  213. }
  214. StatusBlock->Text = strMessage;
  215. // Collapsed the StatusBlock if it has no text to conserve real estate.
  216. if (StatusBlock->Text != "")
  217. {
  218. StatusBlock->Visibility = Windows::UI::Xaml::Visibility::Visible;
  219. }
  220. else
  221. {
  222. StatusBlock->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
  223. }
  224. }
  225. void MainPage::Footer_Click(Object^ sender, RoutedEventArgs^ e)
  226. {
  227. auto uri = ref new Uri((String^)((HyperlinkButton^)sender)->Tag);
  228. Windows::System::Launcher::LaunchUriAsync(uri);
  229. }
  230. /// <summary>
  231. /// Populates the page with content passed during navigation. Any saved state is also
  232. /// provided when recreating a page from a prior session.
  233. /// </summary>
  234. /// <param name="navigationParameter">The parameter value passed to
  235. /// <see cref="Frame::Navigate(Type, Object)"/> when this page was initially requested.
  236. /// </param>
  237. /// <param name="pageState">A map of state preserved by this page during an earlier
  238. /// session. This will be null the first time a page is visited.</param>
  239. void MainPage::LoadState(Object^ navigationParameter, IMap<String^, Object^>^ pageState)
  240. {
  241. (void) navigationParameter; // Unused parameter
  242. PopulateScenarios();
  243. // Starting scenario is the first or based upon a previous state.
  244. ListBoxItem^ startingScenario = nullptr;
  245. int startingScenarioIndex = -1;
  246. if (pageState != nullptr && pageState->HasKey("SelectedScenarioIndex"))
  247. {
  248. startingScenarioIndex = safe_cast<int>(pageState->Lookup("SelectedScenarioIndex"));
  249. }
  250. Scenarios->SelectedIndex = startingScenarioIndex != -1 ? startingScenarioIndex : 0;
  251. InvalidateViewState();
  252. }
  253. /// <summary>
  254. /// Preserves state associated with this page in case the application is suspended or the
  255. /// page is discarded from the navigation cache. Values must conform to the serialization
  256. /// requirements of <see cref="SuspensionManager::SessionState"/>.
  257. /// </summary>
  258. /// <param name="pageState">An empty map to be populated with serializable state.</param>
  259. void MainPage::SaveState(IMap<String^, Object^>^ pageState)
  260. {
  261. int selectedListBoxItemIndex = Scenarios->SelectedIndex;
  262. pageState->Insert("SelectedScenarioIndex", selectedListBoxItemIndex);
  263. }