/// <summary>
 /// Обработать событие по переходу по ссылке.
 /// </summary>
 /// <param name="sender">Источник события.</param>
 /// <param name="e">Событие.</param>
 /// <returns>true, если обработка произведена и действий по умолчанию не требуется.</returns>
 public bool HandleNavigationLinkClick(object sender, LinkClickEventArgs e)
 {
     var vm = ViewModel;
     if (vm == null)
     {
         return false;
     }
     var l0 = e?.Link?.CustomData as BoardLinkBase;
     if (l0 != null)
     {
         var l = ServiceLocator.Current.GetServiceOrThrow<ILinkTransformService>().GetPostLinkFromAnyLink(l0);
         if (l != null)
         {
             if (vm.PostsByLink.ContainsKey(l))
             {
                 var p = vm.PostsByLink[l];
                 if (p != null)
                 {
                     if (!SinglePostViewPopup.IsContentVisible)
                     {
                         singleNavigationStack.Clear();
                     }
                     var lvm = e.LinkContext as IPostViewModel;
                     var lc = lvm?.Link;
                     if (lc != null)
                     {
                         if (SinglePostViewPopup.IsContentVisible)
                         {
                             PushCurrentLink(lc);
                         }
                         PushCurrentLink(lvm, l);
                     }
                     else
                     {
                         PushCurrentLink(l);
                     }
                     SingleSelectedItem = p;
                     AppHelpers.DispatchAction(() =>
                     {
                         SinglePostViewPopup.IsContentVisible = true;
                         return Task.CompletedTask;
                     });
                     return true;
                 }
             }
         }
     }
     return false;
 }
 /// <summary>
 /// Обратный вызов.
 /// </summary>
 /// <param name="link">Ссылка.</param>
 public void OnLinkClick(ITextRenderLinkAttribute link)
 {
     if (link != null)
     {
         var e = new LinkClickEventArgs(link) { LinkContext = Parent };
         LinkClick?.Invoke(this, e);
         ViewModelEvents.LinkClick.RaiseEvent(this, e);
     }
 }
 private void TvOnLinkClick(object sender, LinkClickEventArgs e)
 {
     LinkClick?.Invoke(sender, e);
 }
 /// <summary>
 /// Обработать событие по переходу по ссылке.
 /// </summary>
 /// <param name="sender">Источник события.</param>
 /// <param name="e">Событие.</param>
 private async Task HandleNavigationLinkClick(object sender, LinkClickEventArgs e)
 {
     if (e.Link.Uri == null && e.Link.CustomData == null)
     {
         return;
     }
     var currentWindow = Shell.HamburgerMenu?.NavigationService?.FrameFacade?.Content as INavigationLinkCallback;
     if (currentWindow != null)
     {
         if (currentWindow.HandleNavigationLinkClick(sender, e))
         {
             return;
         }
     }
     var link = e.Link.CustomData as BoardLinkBase;
     string uri = e.Link.Uri;
     if (link != null)
     {
         if ((link.LinkKind & BoardLinkKind.Thread) != 0 || (link.LinkKind & BoardLinkKind.Post) != 0)
         {
             ServiceLocator.Current.GetServiceOrThrow<IPageNavigationService>().Navigate(new ThreadNavigationTarget(link));
             return;
         }
         if ((link.LinkKind & BoardLinkKind.BoardPage) != 0)
         {
             ServiceLocator.Current.GetServiceOrThrow<IPageNavigationService>().Navigate(new BoardInfoNavigationTarget(link));
             return;
         }
         if ((link.LinkKind & BoardLinkKind.Catalog) != 0 || (link.LinkKind & BoardLinkKind.ThreadTag) != 0)
         {
             ServiceLocator.Current.GetServiceOrThrow<IPageNavigationService>().Navigate(new BoardCatalogNavigationTarget(link));
             return;
         }
         if ((link.LinkKind & BoardLinkKind.Media) != 0)
         {
             ServiceLocator.Current.GetServiceOrThrow<IPageNavigationService>().Navigate(new MediaNavigationTarget(link));
             return;
         }
         if ((link.LinkKind & BoardLinkKind.Youtube) != 0)
         {
             if (await NavigateYoutube(link))
             {
                 return;
             }
         }
         if (uri == null || uri == "[data]")
         {
             var engines = ServiceLocator.Current.GetServiceOrThrow<INetworkEngines>();
             var engine = engines.FindEngine(link.Engine);
             if (engine != null)
             {
                 uri = engine.EngineUriService.GetBrowserLink(link)?.ToString();
             }
         }
     }
     if (uri != null && uri != "[data]")
     {
         var uriObj = new Uri(uri, UriKind.Absolute);
         var success = await Windows.System.Launcher.LaunchUriAsync(uriObj);
         if (!success)
         {
             throw new InvalidOperationException($"Ошибка запуска URL \"{uri}\"");
         }
     }
 }