FirstFloor ModernUI 无法通过 TitleLinks.LinkNavigator 导航
FirstFloor ModernUI Unable to Navigate via TitleLinks.LinkNavigator
我试图在按下键盘快捷键时通过以下代码导航到 XAML 控件(特别是 ModernFrame 控件):
LinkNavigator.Navigate(new Uri("/Controls/SettingsManager.xaml", UriKind.Relative), this);
键盘快捷键触发,然后出现异常:
System.ArgumentException: 'Unable to navigate to /Controls/SettingsManager.xaml, could not find a ModernFrame target '''
以下是作为 ModernFrame
的 SettingsManager 的来源——请注意,如果将其更改为 UserControl
,它仍然有效。我将其更改为 ModernFrame
因为上述异常正在寻找 ModernFrame
.
现在,如果我通过 window 中的 TitleLink 导航到它,SettingsManager.xaml
控件可以正常工作。但是,当我尝试以编程方式导航到它时,我收到了异常。您可以将控件完全留空,但仍会抛出异常。
SettingsManager.xaml.cs:
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using FirstFloor.ModernUI.Presentation;
using FirstFloor.ModernUI.Windows.Controls;
using KeystoneEstimating.Containers;
namespace KeystoneEstimating.Controls {
/// <summary>
/// Interaction logic for SettingsManager.xaml
/// </summary>
public partial class SettingsManager : ModernFrame {
public SettingsManager() {
InitializeComponent();
/// Load settings into the Link interface of MUI.
List<AppSettings> settings = AppInfo.SettingsContainers;
foreach (AppSettings set in settings) {
Link lnk = new Link();
lnk.DisplayName = set.SettingsName;
lnk.Source = set.ControlPath;
SettingsLinks.Links.Add(lnk);
}
// Load up the very first registered settings page.
if (SettingsLinks.Links.First() != null)
SettingsLinks.SelectedSource = SettingsLinks.Links.First().Source;
}
}
}
SettingsManage.xaml:
<mui:ModernFrame xmlns:mui="http://firstfloorsoftware.com/ModernUI"
x:Class="KeystoneEstimating.Controls.SettingsManager"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:KeystoneEstimating"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Style="{StaticResource ContentRoot}">
<mui:ModernTab Layout="List" Name="SettingsLinks"/>
</Grid>
</mui:ModernFrame>
ModernUI 包含两个标记为 ModernUI.WPFCore
的 NugetPackage。一个是版本 2.0.0
,另一个是版本 3.1.2
。问题在两者上都可重现。
似乎 FirstFloor ModernUI 的导航命令存在固有问题,它无法找到 MainWindow.xaml 的 ContentFrame
类型的样式控件 ModernFrame
调用时 Navigate()
.
我从源代码中搜索了样式,发现通过 XAML 可以通过 WPF 绑定找到 ContentFrame
。
<Button Content="{Binding DisplayName}"
Command="navigation:LinkCommands.NavigateLink"
CommandParameter="{Binding Source}"
CommandTarget="{Binding ElementName=ContentFrame}"
Style="{StaticResource SystemButtonLink}" />
当您单击 ModernWindow
中的任何 Link
时,这就是代码的处理方式,当您在 XAML 中对 UI 元素进行预编码时,代码将完美运行因为所有 XAML 元素将自动继承 ModernWindow
作为它们的 parent object。这是 Navigate 命令所必需的,因为它会向上搜索 parent 的元素层次结构以找到要填充到的 ModernFrame。请参阅 DefaultLinkNavigator.Navigate
调用函数 NavigationHelper.FindFrame(parameter, source)
:
/// <summary>
/// Finds the frame identified with given name in the specified context.
/// </summary>
/// <param name="name">The frame name.</param>
/// <param name="context">The framework element providing the context for finding a frame.</param>
/// <returns>The frame or null if the frame could not be found.</returns>
public static ModernFrame FindFrame(string name, FrameworkElement context)
{
if (context == null) {
throw new ArgumentNullException("context");
}
// collect all ancestor frames
var frames = context.AncestorsAndSelf().OfType<ModernFrame>().ToArray();
if (name == null || name == FrameSelf) {
// find first ancestor frame
return frames.FirstOrDefault();
}
if (name == FrameParent) {
// find parent frame
return frames.Skip(1).FirstOrDefault();
}
if (name == FrameTop) {
// find top-most frame
return frames.LastOrDefault();
}
// find ancestor frame having a name matching the target
var frame = frames.FirstOrDefault(f => f.Name == name);
if (frame == null) {
// find frame in context scope
frame = context.FindName(name) as ModernFrame;
if (frame == null) {
// find frame in scope of ancestor frame content
var parent = frames.FirstOrDefault();
if (parent != null && parent.Content != null) {
var content = parent.Content as FrameworkElement;
if (content != null) {
frame = content.FindName(name) as ModernFrame;
}
}
}
}
return frame;
}
但是在代码中情况并非如此...在代码中执行链接时,您希望导航到的控件的 XAML 页面尚不存在,因此没有 parent 并且不能用于在导航中查找 parent 的 ModernFrame
。
然而,解决方案是在代码中创建绑定并将绑定作为参数传递给 Navigate 命令——我还不知道该怎么做——或者在 ModernWindow
控件并手动搜索名称为 ContentFrame
的所有 ModernFrame
类型的源元素(这是显示您的 ModernWindow.xaml
中的 window 的显示元素内容。
首先向您的 MainWindow.cs
class 添加一个分层搜索功能——它应该扩展 ModernWindow
而不是 WPF 中的 Window
:
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject {
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++) {
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null) {
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
} else if (!string.IsNullOrEmpty(childName)) {
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName) {
// if the child's name is of the request name
foundChild = (T)child;
break;
}
} else {
// child element found.
foundChild = (T)child;
break;
}
}
在同一个 class 中通过代码导航到控件——在我的例子中,当执行键绑定时——你可以使用三种不同的方法:
var target = FindChild<ModernFrame>(this, "ContentFrame");
// A:
LinkCommands.NavigateLink.Execute(new Uri("/Controls/SettingsManager.xaml", UriKind.RelativeOrAbsolute), target);
// B:
NavigationCommands.GoToPage.Execute("/Controls/SettingsManager.xaml", target);
// C:
this.LinkNavigator.Navigate(new Uri("/Controls/SettingsManager.xaml", UriKind.Relative), target as FrameworkElement);
层次结构来源 child 搜索:
我试图在按下键盘快捷键时通过以下代码导航到 XAML 控件(特别是 ModernFrame 控件):
LinkNavigator.Navigate(new Uri("/Controls/SettingsManager.xaml", UriKind.Relative), this);
键盘快捷键触发,然后出现异常:
System.ArgumentException: 'Unable to navigate to /Controls/SettingsManager.xaml, could not find a ModernFrame target '''
以下是作为 ModernFrame
的 SettingsManager 的来源——请注意,如果将其更改为 UserControl
,它仍然有效。我将其更改为 ModernFrame
因为上述异常正在寻找 ModernFrame
.
现在,如果我通过 window 中的 TitleLink 导航到它,SettingsManager.xaml
控件可以正常工作。但是,当我尝试以编程方式导航到它时,我收到了异常。您可以将控件完全留空,但仍会抛出异常。
SettingsManager.xaml.cs:
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using FirstFloor.ModernUI.Presentation;
using FirstFloor.ModernUI.Windows.Controls;
using KeystoneEstimating.Containers;
namespace KeystoneEstimating.Controls {
/// <summary>
/// Interaction logic for SettingsManager.xaml
/// </summary>
public partial class SettingsManager : ModernFrame {
public SettingsManager() {
InitializeComponent();
/// Load settings into the Link interface of MUI.
List<AppSettings> settings = AppInfo.SettingsContainers;
foreach (AppSettings set in settings) {
Link lnk = new Link();
lnk.DisplayName = set.SettingsName;
lnk.Source = set.ControlPath;
SettingsLinks.Links.Add(lnk);
}
// Load up the very first registered settings page.
if (SettingsLinks.Links.First() != null)
SettingsLinks.SelectedSource = SettingsLinks.Links.First().Source;
}
}
}
SettingsManage.xaml:
<mui:ModernFrame xmlns:mui="http://firstfloorsoftware.com/ModernUI"
x:Class="KeystoneEstimating.Controls.SettingsManager"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:KeystoneEstimating"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Style="{StaticResource ContentRoot}">
<mui:ModernTab Layout="List" Name="SettingsLinks"/>
</Grid>
</mui:ModernFrame>
ModernUI 包含两个标记为 ModernUI.WPFCore
的 NugetPackage。一个是版本 2.0.0
,另一个是版本 3.1.2
。问题在两者上都可重现。
似乎 FirstFloor ModernUI 的导航命令存在固有问题,它无法找到 MainWindow.xaml 的 ContentFrame
类型的样式控件 ModernFrame
调用时 Navigate()
.
我从源代码中搜索了样式,发现通过 XAML 可以通过 WPF 绑定找到 ContentFrame
。
<Button Content="{Binding DisplayName}"
Command="navigation:LinkCommands.NavigateLink"
CommandParameter="{Binding Source}"
CommandTarget="{Binding ElementName=ContentFrame}"
Style="{StaticResource SystemButtonLink}" />
当您单击 ModernWindow
中的任何 Link
时,这就是代码的处理方式,当您在 XAML 中对 UI 元素进行预编码时,代码将完美运行因为所有 XAML 元素将自动继承 ModernWindow
作为它们的 parent object。这是 Navigate 命令所必需的,因为它会向上搜索 parent 的元素层次结构以找到要填充到的 ModernFrame。请参阅 DefaultLinkNavigator.Navigate
调用函数 NavigationHelper.FindFrame(parameter, source)
:
/// <summary>
/// Finds the frame identified with given name in the specified context.
/// </summary>
/// <param name="name">The frame name.</param>
/// <param name="context">The framework element providing the context for finding a frame.</param>
/// <returns>The frame or null if the frame could not be found.</returns>
public static ModernFrame FindFrame(string name, FrameworkElement context)
{
if (context == null) {
throw new ArgumentNullException("context");
}
// collect all ancestor frames
var frames = context.AncestorsAndSelf().OfType<ModernFrame>().ToArray();
if (name == null || name == FrameSelf) {
// find first ancestor frame
return frames.FirstOrDefault();
}
if (name == FrameParent) {
// find parent frame
return frames.Skip(1).FirstOrDefault();
}
if (name == FrameTop) {
// find top-most frame
return frames.LastOrDefault();
}
// find ancestor frame having a name matching the target
var frame = frames.FirstOrDefault(f => f.Name == name);
if (frame == null) {
// find frame in context scope
frame = context.FindName(name) as ModernFrame;
if (frame == null) {
// find frame in scope of ancestor frame content
var parent = frames.FirstOrDefault();
if (parent != null && parent.Content != null) {
var content = parent.Content as FrameworkElement;
if (content != null) {
frame = content.FindName(name) as ModernFrame;
}
}
}
}
return frame;
}
但是在代码中情况并非如此...在代码中执行链接时,您希望导航到的控件的 XAML 页面尚不存在,因此没有 parent 并且不能用于在导航中查找 parent 的 ModernFrame
。
然而,解决方案是在代码中创建绑定并将绑定作为参数传递给 Navigate 命令——我还不知道该怎么做——或者在 ModernWindow
控件并手动搜索名称为 ContentFrame
的所有 ModernFrame
类型的源元素(这是显示您的 ModernWindow.xaml
中的 window 的显示元素内容。
首先向您的 MainWindow.cs
class 添加一个分层搜索功能——它应该扩展 ModernWindow
而不是 WPF 中的 Window
:
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject {
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++) {
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null) {
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
} else if (!string.IsNullOrEmpty(childName)) {
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName) {
// if the child's name is of the request name
foundChild = (T)child;
break;
}
} else {
// child element found.
foundChild = (T)child;
break;
}
}
在同一个 class 中通过代码导航到控件——在我的例子中,当执行键绑定时——你可以使用三种不同的方法:
var target = FindChild<ModernFrame>(this, "ContentFrame");
// A:
LinkCommands.NavigateLink.Execute(new Uri("/Controls/SettingsManager.xaml", UriKind.RelativeOrAbsolute), target);
// B:
NavigationCommands.GoToPage.Execute("/Controls/SettingsManager.xaml", target);
// C:
this.LinkNavigator.Navigate(new Uri("/Controls/SettingsManager.xaml", UriKind.Relative), target as FrameworkElement);
层次结构来源 child 搜索: