1 //*********************************************************
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.
9 //*********************************************************
13 // Implementation of the MainPage.xaml class.
17 #include "MainPage.xaml.h"
20 #include <collection.h>
22 using namespace Windows::UI::Xaml;
23 using namespace Windows::UI::Xaml::Controls;
24 using namespace Windows::Foundation;
25 using namespace Windows::Foundation::Collections;
26 using namespace Platform;
27 using namespace SDKSample;
28 using namespace Windows::UI::Xaml::Navigation;
29 using namespace Windows::UI::Xaml::Interop;
30 using namespace Windows::Graphics::Display;
31 using namespace Windows::UI::ViewManagement;
33 MainPage^ MainPage::Current = nullptr;
37 InitializeComponent();
39 // This frame is hidden, meaning it is never shown. It is simply used to load
40 // each scenario page and then pluck out the input and output sections and
41 // place them into the UserControls on the main page.
42 HiddenFrame = ref new Windows::UI::Xaml::Controls::Frame();
43 HiddenFrame->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
44 ContentRoot->Children->Append(HiddenFrame);
46 FeatureName->Text = FEATURE_NAME;
48 this->SizeChanged += ref new SizeChangedEventHandler(this, &MainPage::MainPage_SizeChanged);
49 Scenarios->SelectionChanged += ref new SelectionChangedEventHandler(this, &MainPage::Scenarios_SelectionChanged);
51 MainPage::Current = this;
52 autoSizeInputSectionWhenSnapped = true;
56 /// We need to handle SizeChanged so that we can make the sample layout property
57 /// in the various layouts.
59 /// <param name="sender"></param>
60 /// <param name="e"></param>
61 void MainPage::MainPage_SizeChanged(Object^ sender, SizeChangedEventArgs^ e)
64 MainPageSizeChangedEventArgs^ args = ref new MainPageSizeChangedEventArgs();
65 args->ViewState = ApplicationView::Value;
66 MainPageResized(this, args);
70 void MainPage::InvalidateSize()
72 // Get the window width
73 double windowWidth = this->ActualWidth;
75 if (windowWidth != 0.0)
77 // Get the width of the ListBox.
78 double listBoxWidth = Scenarios->ActualWidth;
80 // Is the ListBox using any margins that we need to consider?
81 double listBoxMarginLeft = Scenarios->Margin.Left;
82 double listBoxMarginRight = Scenarios->Margin.Right;
84 // Figure out how much room is left after considering the list box width
85 double availableWidth = windowWidth - listBoxWidth;
87 // Is the top most child using margins?
88 double layoutRootMarginLeft = ContentRoot->Margin.Left;
89 double layoutRootMarginRight = ContentRoot->Margin.Right;
91 // We have different widths to use depending on the view state
92 if (ApplicationView::Value != ApplicationViewState::Snapped)
94 // Make us as big as the the left over space, factoring in the ListBox width, the ListBox margins.
95 // and the LayoutRoot's margins
96 InputSection->Width = ((availableWidth) -
97 (layoutRootMarginLeft + layoutRootMarginRight + listBoxMarginLeft + listBoxMarginRight));
101 // Make us as big as the left over space, factoring in just the LayoutRoot's margins.
102 if (autoSizeInputSectionWhenSnapped)
104 InputSection->Width = (windowWidth - (layoutRootMarginLeft + layoutRootMarginRight));
108 InvalidateViewState();
111 void MainPage::InvalidateViewState()
113 // Are we going to snapped mode?
114 if (ApplicationView::Value == ApplicationViewState::Snapped)
116 Grid::SetRow(DescriptionText, 3);
117 Grid::SetColumn(DescriptionText, 0);
119 Grid::SetRow(InputSection, 4);
120 Grid::SetColumn(InputSection, 0);
122 Grid::SetRow(FooterPanel, 2);
123 Grid::SetColumn(FooterPanel, 0);
127 Grid::SetRow(DescriptionText, 1);
128 Grid::SetColumn(DescriptionText, 1);
130 Grid::SetRow(InputSection, 2);
131 Grid::SetColumn(InputSection, 1);
133 Grid::SetRow(FooterPanel, 1);
134 Grid::SetColumn(FooterPanel, 1);
137 // Since we don't load the scenario page in the traditional manner (we just pluck out the
138 // input and output sections from the page) we need to ensure that any VSM code used
139 // by the scenario's input and output sections is fired.
140 VisualStateManager::GoToState(InputSection, "Input" + LayoutAwarePage::DetermineVisualState(ApplicationView::Value), false);
141 VisualStateManager::GoToState(OutputSection, "Output" + LayoutAwarePage::DetermineVisualState(ApplicationView::Value), false);
144 void MainPage::PopulateScenarios()
146 ScenarioList = ref new Platform::Collections::Vector<Object^>();
148 // Populate the ListBox with the list of scenarios as defined in Constants.cpp.
149 for (unsigned int i = 0; i < scenarios->Length; ++i)
151 Scenario s = scenarios[i];
152 ListBoxItem^ item = ref new ListBoxItem();
153 item->Name = s.ClassName;
154 item->Content = (i + 1).ToString() + ") " + s.Title;
155 ScenarioList->Append(item);
158 // Bind the ListBox to the scenario list.
159 Scenarios->ItemsSource = ScenarioList;
160 Scenarios->ScrollIntoView(Scenarios->SelectedItem);
164 /// This method is responsible for loading the individual input and output sections for each scenario. This
165 /// is based on navigating a hidden Frame to the ScenarioX.xaml page and then extracting out the input
166 /// and output sections into the respective UserControl on the main page.
168 /// <param name="scenarioName"></param>
169 void MainPage::LoadScenario(String^ scenarioName)
171 autoSizeInputSectionWhenSnapped = true;
173 // Load the ScenarioX.xaml file into the Frame.
174 TypeName scenarioType = {scenarioName, TypeKind::Custom};
175 HiddenFrame->Navigate(scenarioType, this);
177 // Get the top element, the Page, so we can look up the elements
178 // that represent the input and output sections of the ScenarioX file.
179 Page^ hiddenPage = safe_cast<Page^>(HiddenFrame->Content);
182 UIElement^ input = safe_cast<UIElement^>(hiddenPage->FindName("Input"));
183 UIElement^ output = safe_cast<UIElement^>(hiddenPage->FindName("Output"));
185 if (input == nullptr)
187 // Malformed input section.
188 NotifyUser("Cannot load scenario input section for " + scenarioName +
189 " Make sure root of input section markup has x:Name of 'Input'", NotifyType::ErrorMessage);
193 if (output == nullptr)
195 // Malformed output section.
196 NotifyUser("Cannot load scenario output section for " + scenarioName +
197 " Make sure root of output section markup has x:Name of 'Output'", NotifyType::ErrorMessage);
201 // Find the LayoutRoot which parents the input and output sections in the main page.
202 Panel^ panel = safe_cast<Panel^>(hiddenPage->FindName("LayoutRoot"));
204 if (panel != nullptr)
206 unsigned int index = 0;
207 UIElementCollection^ collection = panel->Children;
209 // Get rid of the content that is currently in the intput and output sections.
210 collection->IndexOf(input, &index);
211 collection->RemoveAt(index);
213 collection->IndexOf(output, &index);
214 collection->RemoveAt(index);
216 // Populate the input and output sections with the newly loaded content.
217 InputSection->Content = input;
218 OutputSection->Content = output;
220 ScenarioLoaded(this, nullptr);
224 // Malformed Scenario file.
225 NotifyUser("Cannot load scenario: " + scenarioName + ". Make sure root tag in the '" +
226 scenarioName + "' file has an x:Name of 'LayoutRoot'", NotifyType::ErrorMessage);
230 void MainPage::Scenarios_SelectionChanged(Object^ sender, SelectionChangedEventArgs^ e)
232 if (Scenarios->SelectedItem != nullptr)
234 NotifyUser("", NotifyType::StatusMessage);
236 LoadScenario((safe_cast<ListBoxItem^>(Scenarios->SelectedItem))->Name);
241 void MainPage::NotifyUser(String^ strMessage, NotifyType type)
245 case NotifyType::StatusMessage:
246 // Use the status message style.
247 StatusBlock->Style = safe_cast<Windows::UI::Xaml::Style^>(this->Resources->Lookup("StatusStyle"));
249 case NotifyType::ErrorMessage:
250 // Use the error message style.
251 StatusBlock->Style = safe_cast<Windows::UI::Xaml::Style^>(this->Resources->Lookup("ErrorStyle"));
256 StatusBlock->Text = strMessage;
258 // Collapsed the StatusBlock if it has no text to conserve real estate.
259 if (StatusBlock->Text != "")
261 StatusBlock->Visibility = Windows::UI::Xaml::Visibility::Visible;
265 StatusBlock->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
269 void MainPage::Footer_Click(Object^ sender, RoutedEventArgs^ e)
271 auto uri = ref new Uri((String^)((HyperlinkButton^)sender)->Tag);
272 Windows::System::Launcher::LaunchUriAsync(uri);
277 /// Populates the page with content passed during navigation. Any saved state is also
278 /// provided when recreating a page from a prior session.
280 /// <param name="navigationParameter">The parameter value passed to
281 /// <see cref="Frame::Navigate(Type, Object)"/> when this page was initially requested.
283 /// <param name="pageState">A map of state preserved by this page during an earlier
284 /// session. This will be null the first time a page is visited.</param>
285 void MainPage::LoadState(Object^ navigationParameter, IMap<String^, Object^>^ pageState)
287 (void) navigationParameter; // Unused parameter
291 // Starting scenario is the first or based upon a previous state.
292 ListBoxItem^ startingScenario = nullptr;
293 int startingScenarioIndex = -1;
295 if (pageState != nullptr && pageState->HasKey("SelectedScenarioIndex"))
297 startingScenarioIndex = safe_cast<int>(pageState->Lookup("SelectedScenarioIndex"));
300 Scenarios->SelectedIndex = startingScenarioIndex != -1 ? startingScenarioIndex : 0;
302 InvalidateViewState();
306 /// Preserves state associated with this page in case the application is suspended or the
307 /// page is discarded from the navigation cache. Values must conform to the serialization
308 /// requirements of <see cref="SuspensionManager::SessionState"/>.
310 /// <param name="pageState">An empty map to be populated with serializable state.</param>
311 void MainPage::SaveState(IMap<String^, Object^>^ pageState)
313 int selectedListBoxItemIndex = Scenarios->SelectedIndex;
314 pageState->Insert("SelectedScenarioIndex", selectedListBoxItemIndex);