4 america
12-14 September, 2024

Days of Knowledge Americas 2024

Days of Knowledge is a Directions for Partners event focused on educating consultants and developers, sharing knowledge and upgrading Business Central professionals to enable quality customer solutions. Training and acquiring knowledge are the magic words at Days of Knowledge. 

Error executing template "Designs/Swift/Navigation/COMM_EventTabs.cshtml"
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
   at System.ThrowHelper.ThrowKeyNotFoundException()
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at CompiledRazorTemplates.Dynamic.RazorEngine_886d8cef676648c79d4a0444c43b9d22.Execute() in C:\inetpub\wwwroot\directions2023_dev\Files\Templates\Designs\Swift\Navigation\COMM_EventTabs.cshtml:line 7
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.Navigation.NavigationTreeViewModel> 2 @using Dynamicweb 3 @using System.Text.RegularExpressions 4 @using Dynamicweb.Frontend 5 6 @{ 7 string theme = !string.IsNullOrEmpty(Model.Parameters["theme"].ToString()) ? Model.Parameters["theme"].ToString() : string.Empty; 8 string navOrientation = !string.IsNullOrEmpty(Model.Parameters["navOrientation"].ToString()) ? Model.Parameters["navOrientation"].ToString() : string.Empty; 9 string navAlignment = !string.IsNullOrEmpty(Model.Parameters["navAlignment"].ToString()) ? Model.Parameters["navAlignment"].ToString() : string.Empty; 10 string linkFontWeight = !string.IsNullOrEmpty(Model.Parameters["LinkFontWeight"].ToString()) ? Model.Parameters["LinkFontWeight"].ToString() : string.Empty; 11 string linkCasing = !string.IsNullOrEmpty(Model.Parameters["LinkCasing"].ToString()) ? Model.Parameters["LinkCasing"].ToString() : string.Empty; 12 string linkFontSize = !string.IsNullOrEmpty(Model.Parameters["LinkFontSize"].ToString()) ? Model.Parameters["LinkFontSize"].ToString() : string.Empty; 13 string layout = !string.IsNullOrEmpty(Model.Parameters["Layout"].ToString()) ? Model.Parameters["Layout"].ToString() : string.Empty; 14 15 string iconSize = "icon-3"; 16 17 if (linkFontSize == "fs-7") 18 { 19 iconSize = "icon-2"; 20 } 21 if (linkFontSize == "fs-5") 22 { 23 iconSize = "icon-4"; 24 } 25 } 26 <div class="grid"> 27 <div class="g-col-12"> 28 <nav class="navbar navbar-expand-lg d-flex py-0 overflow-y-auto @navOrientation @navAlignment"> 29 @{@RenderFirstLevelNodes(Model.Nodes, theme, navOrientation, linkFontWeight, linkCasing, linkFontSize, iconSize, layout)} 30 </nav> 31 </div> 32 </div> 33 34 @helper RenderFirstLevelNodes(IEnumerable<Dynamicweb.Frontend.Navigation.NavigationTreeNodeViewModel> nodes, string theme, string navOrientation, string linkFontWeight, string linkCasing, string linkFontSize, string iconSize, string layout) 35 { 36 int imageHeight = 50; 37 string logo = Model.Parameters.ContainsKey("Logo") ? Model.Parameters["Logo"].ToString() : string.Empty; 38 int logoHeight = Model.Parameters.ContainsKey("LogoHeight") ? Convert.ToInt32(Model.Parameters["LogoHeight"]) : 50; 39 string rootPageId = Model.Parameters.ContainsKey("RootPageId") ? Model.Parameters["RootPageId"].ToString() : string.Empty; 40 var rootPageFriendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl("Default.aspx?ID=" + rootPageId); 41 string theme = Model.Parameters.ContainsKey("theme") ? Model.Parameters["theme"].ToString() : string.Empty; 42 string themeSticky = Model.Parameters.ContainsKey("themeSticky") ? Model.Parameters["themeSticky"].ToString() : string.Empty; 43 bool showOnlyFirstNavLevel = Model.Parameters.ContainsKey("ShowOnlyFirstNavLevel") ? Convert.ToBoolean(Model.Parameters["ShowOnlyFirstNavLevel"].ToString()) : false; 44 int gridRowId = Model.Parameters.ContainsKey("GridRowId") ? Convert.ToInt32(Model.Parameters["GridRowId"].ToString()) : 0; 45 int currentParagraphId = Pageview.CurrentParagraph != null ? Pageview.CurrentParagraph.ID : gridRowId; 46 string menuId = Model.Parameters.ContainsKey("menu-id") ? $"menu_{Model.Parameters["menu-id"].ToString().ToLower()}" : string.Empty; 47 48 string firstItemActive = !nodes.Any(node => node.InPath || node.IsActive) ? "active" : string.Empty; 49 50 <ul class="overflow-y-auto align-items-center w-100 gap-lg-3 gap-1 navbar-nav flex-nowrap @(navOrientation == "vertical" ? "flex-column" : navOrientation)"> 51 <li class="nav-item flex-1"> 52 <div class="item-container first @firstItemActive"> 53 <a href="@rootPageFriendlyUrl" class="first-item fw-bold p-2 nav-link text-nowrap text-decoration-underline-hover @linkFontSize @linkFontWeight @linkCasing"> 54 @Translate("Intro") 55 </a> 56 57 @if (!string.IsNullOrEmpty(logo)) 58 { 59 var parms = new Dictionary<string, object>(); 60 parms.Add("alt", "logo"); 61 parms.Add("height", logoHeight); 62 63 <a href="@rootPageFriendlyUrl" class="logo d-none"> 64 @RenderPartial("../Components/Image.cshtml", new FileViewModel { Path = logo }, parms) 65 </a> 66 } 67 </div> 68 </li> 69 70 @foreach (var node in nodes) 71 { 72 var page = Dynamicweb.Content.Services.Pages.GetPage(node.PageId); 73 var pageType = !string.IsNullOrEmpty(page.ItemType) ? page.ItemType : "Swift_Page"; 74 string pageIcon = string.Empty; 75 if (page.PropertyItem is object && page.PropertyItem.TryGetValue("Icon", out object pageIconValue)) 76 { 77 pageIcon = Dynamicweb.Core.Converter.ToString(pageIconValue); 78 } 79 string preferencesLayout = page.Item?["PreferencesLayout"] != null ? page.Item["PreferencesLayout"].ToString() : ""; 80 string preferencesType = "language"; 81 bool countrySelector = page.Item?["CountrySelector"] != null ? Convert.ToBoolean(page.Item["CountrySelector"].ToString()) : false; 82 bool languageSelector = page.Item?["LanguageSelector"] != null ? Convert.ToBoolean(page.Item["LanguageSelector"].ToString()) : false; 83 bool currencySelector = page.Item?["CurrencySelector"] != null ? Convert.ToBoolean(page.Item["CurrencySelector"].ToString()) : false; 84 string dropdownAttributes = string.Empty; 85 string dropdownClasses = string.Empty; 86 87 var hasChildren = node.Nodes.Count() > 0 || pageType == "Swift_SignIn"; 88 89 if (hasChildren && !showOnlyFirstNavLevel) 90 { 91 dropdownAttributes = hasChildren ? " role=\"button\" aria-haspopup=\"true\" aria-expanded=\"false\" data-bs-toggle=\"dropdown\" data-bs-offset=\"0,0\"" : ""; 92 } 93 94 string isActive = node.InPath || node.IsActive ? " active" : ""; 95 96 97 string nodeId = !string.IsNullOrEmpty(node.GroupId) ? "Navigation_" + node.GroupId + "_" + currentParagraphId : "Navigation_Page_Desktop_" + node.PageId.ToString() + "_" + currentParagraphId; 98 99 if (pageType != "Swift_Preferences") 100 { 101 <li class="nav-item@(hasChildren ? " dropdown" : "") flex-1 @(isActive)"> 102 <div class="item-container @(isActive)"> 103 @if (node.IsClickable) 104 { 105 <a href="@node.Link" class="fw-bold p-2 nav-link text-nowrap text-decoration-underline-hover @linkFontSize @linkFontWeight @linkCasing@(isActive)@(hasChildren ? " dropdown-toggle" : "")" @dropdownAttributes @(node.IsActive ? " aria-current='page'" : "") id="@nodeId"> 106 @{@RenderNavigationItem(node, pageType, pageIcon, iconSize, layout)} 107 </a> 108 } 109 else 110 { 111 <span class="fw-bold p-2 nav-link text-nowrap @linkFontSize @linkFontWeight @linkCasing@(hasChildren ? " dropdown-toggle " : "")" @dropdownAttributes id="@nodeId"> 112 @{@RenderNavigationItem(node, pageType, pageIcon, iconSize, layout)} 113 </span> 114 } 115 </div> 116 117 @if (hasChildren) 118 { 119 if (!showOnlyFirstNavLevel) 120 { 121 <ul class="dropdown-menu @(theme)" aria-labelledby="@nodeId"> 122 @foreach (var subnode in node.Nodes) //Standard pages 123 { 124 nodeId = !string.IsNullOrEmpty(subnode.GroupId) ? "Navigation_" + subnode.GroupId + "_" + currentParagraphId : "Navigation_Page_" + subnode.PageId.ToString() + "_" + currentParagraphId; 125 int count = 1; 126 @RenderSubNodes(subnode, 2, nodeId, count) 127 } 128 @if (pageType == "Swift_SignIn") //Sign out link 129 { 130 if (Pageview.User != null) 131 { 132 string link = "/Admin/Public/ExtranetLogoff.aspx?redirect=no"; 133 134 <li><hr class="dropdown-divider"></li> 135 if (Dynamicweb.Security.UserManagement.User.GetCurrentSecondaryUser() != null) 136 { 137 <li> 138 <a href="Default.aspx?ID=@(Pageview.ID)&DwExtranetRemoveSecondaryUser=1" class="dropdown-item py-2 text-decoration-underline-hover swift_sign-out-as-customer-link @linkFontSize @linkFontWeight @linkCasing" id="SignInButton_@currentParagraphId">@Translate("Sign out as a customer")</a> 139 </li> 140 } 141 <li> 142 <a href="@link" class="dropdown-item py-2 text-decoration-underline-hover swift_sign-out-link @linkFontSize @linkFontWeight @linkCasing">@Translate("Sign out")</a> 143 </li> 144 } 145 } 146 </ul> 147 } 148 } 149 </li> 150 } 151 else 152 { 153 if (preferencesLayout == "modal") 154 { 155 string groupId = Dynamicweb.Context.Current.Request["GroupID"] != null ? Dynamicweb.Context.Current.Request["GroupID"].ToString() : ""; 156 string productId = Dynamicweb.Context.Current.Request["ProductID"] != null ? Dynamicweb.Context.Current.Request["ProductID"].ToString() : ""; 157 string variantId = Dynamicweb.Context.Current.Request["VariantID"] != null ? Dynamicweb.Context.Current.Request["VariantID"].ToString() : ""; 158 159 <li class="nav-item@(hasChildren ? " dropdown" : "")"> 160 <form action="/Default.aspx?ID=@node.PageId" data-response-target-element="PreferencesModalContent" data-layout-template="Swift_Preferences.cshtml" data-preloader="inline"> 161 <input type="hidden" name="CurrentPageID" value="@Pageview.ID"> 162 <input type="hidden" name="GroupID" value="@groupId"> 163 <input type="hidden" name="ProductID" value="@productId"> 164 <input type="hidden" name="VariantID" value="@variantId"> 165 <button type="button" onmouseover="swift.PageUpdater.Update(event)" onclick="swift.PageUpdater.Update(event)" class="btn nav-link p-2 text-nowrap border-0 swift_open-preferences-modal @linkFontSize @linkFontWeight @linkCasing" data-bs-toggle="modal" data-bs-target="#PreferencesModal" id="OpenPreferences_@currentParagraphId"> 166 @if (languageSelector) 167 { 168 {@RenderNavigationItem(node, pageType, pageIcon, iconSize, layout, "language")} 169 } 170 else 171 { 172 {@RenderNavigationItem(node, pageType, pageIcon, iconSize, layout)} 173 } 174 </button> 175 </form> 176 </li> 177 } 178 else 179 { 180 var ecomCountries = Dynamicweb.Ecommerce.Services.Countries.GetCountries(); 181 var currencies = Dynamicweb.Ecommerce.Services.Currencies.GetAllCurrencies(); 182 183 if (languageSelector) 184 { 185 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>(); 186 187 if (Pageview.Page.Area.IsMaster) 188 { 189 languages.Add(Pageview.Page); 190 if (Pageview.Page.Languages != null) 191 { 192 foreach (var language in Pageview.Page.Languages) 193 { 194 if (language.Area.Active == true) 195 { 196 languages.Add(language); 197 } 198 } 199 } 200 } 201 else 202 { 203 languages.Add(Pageview.Page.MasterPage); 204 if (Pageview.Page.MasterPage != null) 205 { 206 if (Pageview.Page.MasterPage.Languages != null) 207 { 208 foreach (var language in Pageview.Page.MasterPage.Languages) 209 { 210 if (language.Area.Active == true) 211 { 212 languages.Add(language); 213 } 214 } 215 } 216 } 217 } 218 219 if (languages.Count > 1) 220 { 221 preferencesType = "language"; 222 223 {@RenderPreferencesDropdown(node, preferencesType, linkFontSize, linkFontWeight, linkCasing, theme, pageType, pageIcon, iconSize, layout)} 224 } 225 } 226 if (countrySelector && ecomCountries.Count > 1) 227 { 228 preferencesType = "country"; 229 {@RenderPreferencesDropdown(node, preferencesType, linkFontSize, linkFontWeight, linkCasing, theme, pageType, pageIcon, iconSize, layout)} 230 } 231 if (currencySelector && currencies.Count() > 1) 232 { 233 preferencesType = "currency"; 234 {@RenderPreferencesDropdown(node, preferencesType, linkFontSize, linkFontWeight, linkCasing, theme, pageType, pageIcon, iconSize, layout)} 235 } 236 } 237 } 238 } 239 </ul> 240 } 241 242 @helper RenderNavigationItem(Dynamicweb.Frontend.Navigation.NavigationTreeNodeViewModel node, string pageType, string pageIcon, string iconSize, string layout, string preferencesType = "") 243 { 244 var page = Dynamicweb.Content.Services.Pages.GetPage(node.PageId); 245 if (pageType == "Swift_Cart") //Mini cart 246 { 247 string cartId = ""; 248 if (page.Item["ContextCart"] != null) 249 { 250 cartId = !string.IsNullOrEmpty(page.Item["ContextCart"].ToString()) ? "ID=\"Cart_" + page.Item["ContextCart"].ToString() + "\"" : ""; 251 } 252 253 string jsCartClass = string.IsNullOrEmpty(cartId) ? "js-cart-qty" : ""; 254 double totalProducts = 0; 255 256 257 Dynamicweb.Ecommerce.Common.Context.CartContext = null; 258 if (page.Item["ContextCart"] != null) 259 { 260 var orderContext = Dynamicweb.Ecommerce.Services.OrderContexts.GetOrderContextById(page.Item["ContextCart"].ToString()); 261 Dynamicweb.Ecommerce.Common.Context.CartContext = orderContext; 262 } 263 264 if (Dynamicweb.Ecommerce.Common.Context.Cart != null) 265 { 266 bool renderOrderlineCountInsteadOfProductCount = page.Item["RenderOrderlineCountInsteadOfProductCount"] != null ? Convert.ToBoolean(page.Item["RenderOrderlineCountInsteadOfProductCount"]) : false; 267 if (!renderOrderlineCountInsteadOfProductCount) 268 { 269 totalProducts = Dynamicweb.Ecommerce.Common.Context.Cart.GetParentProductLineQuantityCount(Dynamicweb.Ecommerce.Common.Context.Cart.OrderLines); 270 } 271 else 272 { 273 totalProducts = Dynamicweb.Ecommerce.Common.Context.Cart.GetParentOrderLineCount(Dynamicweb.Ecommerce.Common.Context.Cart.OrderLines); 274 } 275 } 276 277 278 switch (layout) 279 { 280 case "linksOnly": 281 <span class="align-middle">@node.Name</span> 282 <span class="@jsCartClass mini-cart-quantity align-middle" @cartId>(@totalProducts)</span> 283 break; 284 285 case "iconsOnly": 286 {@RenderIcon(pageIcon, iconSize)} 287 <span class="@jsCartClass mini-cart-quantity align-middle" @cartId>(@totalProducts)</span> 288 break; 289 case "iconsAndLinks": 290 {@RenderIcon(pageIcon, iconSize)} 291 <span class="@jsCartClass mini-cart-quantity align-middle" @cartId>(@totalProducts)</span> 292 <span class="align-middle">@node.Name</span> 293 break; 294 case "linksAndIcons": 295 <span class="align-middle">@node.Name</span> 296 <span class="@jsCartClass mini-cart-quantity align-middle" @cartId>(@totalProducts)</span> 297 {@RenderIcon(pageIcon, iconSize)} 298 break; 299 } 300 } 301 else 302 { 303 string name = node.Name; 304 305 if (preferencesType == "country") 306 { //Country 307 name = Translate("Deliver to") + ": " + Dynamicweb.Ecommerce.Common.Context.Country.GetName(Dynamicweb.Ecommerce.Common.Context.LanguageID); 308 } 309 310 if (preferencesType == "language") 311 { //Languange 312 string iconFolder = "/Files/FlagIcons/"; 313 pageIcon = iconFolder + Pageview.Area.CultureInfo.Name.ToLower() + ".svg"; 314 Regex reg = new Regex(@"\(([^\)]+)\)"); 315 name = reg.Replace(Pageview.Area.CultureInfo.DisplayName, ""); 316 317 layout = layout == "linksOnly" ? "iconsAndLinks" : layout; 318 bool hideIcon = page.Item?["HideIcon"] != null ? Convert.ToBoolean(page.Item["HideIcon"].ToString()) : false; 319 bool hideName = page.Item?["HideName"] != null ? Convert.ToBoolean(page.Item["HideName"].ToString()) : false; 320 layout = hideIcon ? "linksOnly" : layout; 321 layout = hideName ? "iconsOnly" : layout; 322 } 323 324 if (preferencesType == "currency") 325 { //Country 326 name = Dynamicweb.Ecommerce.Common.Context.Currency.Code; 327 } 328 329 switch (layout) 330 { 331 case "linksOnly": 332 <span class="align-middle">@name</span> 333 break; 334 335 case "iconsOnly": 336 <span class="visually-hidden">@name</span> 337 {@RenderIcon(pageIcon, iconSize)} 338 break; 339 case "iconsAndLinks": 340 {@RenderIcon(pageIcon, iconSize)} 341 <span class="align-middle">@name</span> 342 break; 343 case "linksAndIcons": 344 <span class="align-middle">@name</span> 345 {@RenderIcon(pageIcon, iconSize)} 346 break; 347 } 348 } 349 } 350 351 @helper RenderPreferencesDropdown(Dynamicweb.Frontend.Navigation.NavigationTreeNodeViewModel node, string preferencesType, string linkFontSize, string linkFontWeight, string linkCasing, string theme, string pageType, string pageIcon, string iconSize, string layout) 352 { 353 string groupId = Dynamicweb.Context.Current.Request["GroupID"] != null ? Dynamicweb.Context.Current.Request["GroupID"].ToString() : ""; 354 string productId = Dynamicweb.Context.Current.Request["ProductID"] != null ? Dynamicweb.Context.Current.Request["ProductID"].ToString() : ""; 355 string variantId = Dynamicweb.Context.Current.Request["VariantID"] != null ? Dynamicweb.Context.Current.Request["VariantID"].ToString() : ""; 356 int currentParagraphId = Pageview.CurrentParagraph.ID; 357 358 string nodeId = !string.IsNullOrEmpty(node.GroupId) ? "PreferencesLink_" + node.GroupId + "_" + currentParagraphId : "PreferencesLink_" + node.PageId.ToString() + "_" + currentParagraphId; 359 360 <li class="nav-item dropdown"> 361 <form class="d-none d-lg-block" action="/Default.aspx?ID=@node.PageId" data-response-target-element="@(preferencesType)Dropdown_@currentParagraphId" data-layout-template="Swift_Preferences.cshtml" data-preloader="inline"> 362 <input type="hidden" name="Type" value="@preferencesType"> 363 <input type="hidden" name="CurrentPageID" value="@Pageview.ID"> 364 <input type="hidden" name="GroupID" value="@groupId"> 365 <input type="hidden" name="ProductID" value="@productId"> 366 <input type="hidden" name="VariantID" value="@variantId"> 367 <input type="hidden" name="FontSize" value="@linkFontSize"> 368 <input type="hidden" name="FontWeight" value="@linkFontWeight"> 369 <input type="hidden" name="Casing" value="@linkCasing"> 370 371 <a id="@nodeId" onmouseover="swift.PageUpdater.Update(event)" onclick="swift.PageUpdater.Update(event)" class="nav-link p-2 text-nowrap text-decoration-underline-hover @linkFontSize @linkFontWeight @linkCasing@(node.IsActive ? " active" : "") dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" @(node.IsActive ? " aria-current='page'" : "")> 372 @{@RenderNavigationItem(node, pageType, pageIcon, iconSize, layout, preferencesType)} 373 </a> 374 375 <ul class="dropdown-menu @(theme)" id="@(preferencesType)Dropdown_@currentParagraphId"> 376 @* The content here comes from an external request *@ 377 </ul> 378 </form> 379 380 <form class="d-block d-lg-none" action="/Default.aspx?ID=@node.PageId" data-response-target-element="PreferencesModalContent" data-layout-template="Swift_Preferences.cshtml" data-preloader="inline"> 381 <input type="hidden" name="Layout" value="modal"> 382 <input type="hidden" name="CurrentPageID" value="@Pageview.ID"> 383 <input type="hidden" name="GroupID" value="@groupId"> 384 <input type="hidden" name="ProductID" value="@productId"> 385 <input type="hidden" name="VariantID" value="@variantId"> 386 <button type="button" onmouseover="swift.PageUpdater.Update(event)" onclick="swift.PageUpdater.Update(event)" class="btn nav-link p-2 text-nowrap border-0 swift_open-preferences-modal @linkFontSize @linkFontWeight @linkCasing" data-bs-toggle="modal" data-bs-target="#PreferencesModal"> 387 @{@RenderNavigationItem(node, pageType, pageIcon, iconSize, layout, preferencesType)} 388 </button> 389 </form> 390 </li> 391 } 392 393 @helper RenderIcon(string pageIcon, string iconSize) 394 { 395 if (pageIcon.EndsWith(".svg", StringComparison.OrdinalIgnoreCase) && !pageIcon.EndsWith("none.svg", StringComparison.OrdinalIgnoreCase)) 396 { 397 string iconPath = Dynamicweb.Context.Current.Server.MapPath(pageIcon); 398 399 <span class="@iconSize"> 400 @ReadFile(iconPath) 401 </span> 402 } 403 } 404 405 @helper RenderSubNodes(Dynamicweb.Frontend.Navigation.NavigationTreeNodeViewModel subnode , int maxLevel , string nodeId , int count) 406 { 407 <li class="nav-item@(subnode.Nodes.Any() ? " dropdown" : "") d-flex align-items-center"> 408 @if (subnode.IsClickable) 409 { 410 <a href="@subnode.Link" class="dropdown-item py-2 text-decoration-underline-hover" @(subnode.IsActive ? " aria-current='page'" : "") id="@nodeId">@subnode.Name</a> 411 if (subnode.Nodes.Any() && (count != maxLevel)) 412 { 413 <ul class="dropdown-menu dropdown-submenu" aria-labelledby="@nodeId"> 414 @foreach (var item in subnode.Nodes) 415 { 416 if (item.Nodes.Any()) 417 { 418 count++; 419 @RenderSubNodes(item , 2 , nodeId , count) 420 } 421 else 422 { 423 <li class="d-flex align-items-center"> 424 <a href="@item.Link" class="dropdown-item py-2 text-decoration-underline-hover" title="@item.Name">@item.Name</a> 425 </li> 426 } 427 } 428 </ul> 429 430 <span class="px-2 lh-1 arrow_wrapper"> 431 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-right" viewBox="0 0 16 16"> 432 <path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"/> 433 </svg> 434 </span> 435 } 436 437 } 438 else 439 { 440 <span class="dropdown-item py-2" @(subnode.IsActive ? " aria-current='page'" : "") id="@nodeId">@subnode.Name</span> 441 } 442 </li> 443 }

Check the programe

At this time we can only share the general program to give you a first impression of the conference schedule and enable you to start making travel arrangements.  More details on the content and sessions will follow as we get nearer to the conference.

Pre-conference training

Join us on 11 September for a full day of pre-conference training sessions led by the industry's best trainers and MVP's. Please note that these Pre-Conference training sessions are NOT included in your conference ticket and must be purchased separately.

09:00 - 17:00
Days of Knowledge Americas 2024 - Day 1

Get ready for the first day at Days of Knowledge Americas 2024. More details on the content and sessions will follow as we get nearer to the conference.

09:00 - 17:00
Expo reception
17:00 - 18:30
Days of Knowledge Americas 2024 - Day 2

Get ready for the second day at Days of Knowledge Americas 2024. More details on the content and sessions will follow as we get nearer to the conference.

09:00 - 16:00

Full schedule coming soon