C# 从ElementTree的根以CommandParameter的形式传递元素

C# 从ElementTree的根以CommandParameter的形式传递元素,c#,wpf,xaml,data-binding,mvvm,C#,Wpf,Xaml,Data Binding,Mvvm,我在谷歌和StackOverflow上搜索了很多,但都没有找到答案 我有两个Xaml文件: main window.xaml <Window x:Name="mainWindow"> <Window.DataContext> <!-- Instantiate ViewModel of the MainWindow --> <vm:MainWindowViewModel x:Name="viewModel"/>

我在谷歌和StackOverflow上搜索了很多,但都没有找到答案

我有两个Xaml文件:

main window.xaml

<Window x:Name="mainWindow">
    <Window.DataContext>
        <!-- Instantiate ViewModel of the MainWindow -->
        <vm:MainWindowViewModel x:Name="viewModel"/>
    </Window.DataContext>

    <!-- Create the Menu of the MainWindow -->
    <custom:MainMenu Grid.Row="0"/>

    <ad:DockingManager x:Name="dockingManager">
    <!-- ... -->
</Window>
<UserControl>
    <Menu>
        <MenuItem Header="{t:Translate MENU_LAYOUT_SAVE}" Command="{Binding SaveLayoutCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
        <MenuItem Header="{t:Translate MENU_LAYOUT_LOAD}" Command="{Binding LoadLayoutCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
    </Menu>
</UserControl>


因此,如何从xaml中的ElementTree中查找和引用对象(
dockingManager
)。我想避免在代码隐藏中使用额外的代码。

尝试
CommandParameter=“{Binding ElementName=dockingManager,Path=。}”

编辑: 前面的答案行不通。这里有一个可行的想法

在Window.xaml中:

<custom:MainMenu Grid.Row="0" Tag="{Binding ElementName=dockingManager}" />

在main menu.xaml中:

<UserControl x:Name="UcMainMenu" />
...
    <MenuItem Header="{t:Translate MENU_LAYOUT_SAVE}" Command="{Binding SaveLayoutCommand}" CommandParameter="{Binding ElementName=UcMainMenu, Path=Tag}"/>

...

试试
CommandParameter=“{Binding ElementName=dockingManager,Path=.}”

编辑: 前面的答案行不通。这里有一个可行的想法

在Window.xaml中:

<custom:MainMenu Grid.Row="0" Tag="{Binding ElementName=dockingManager}" />

在main menu.xaml中:

<UserControl x:Name="UcMainMenu" />
...
    <MenuItem Header="{t:Translate MENU_LAYOUT_SAVE}" Command="{Binding SaveLayoutCommand}" CommandParameter="{Binding ElementName=UcMainMenu, Path=Tag}"/>

...

既然您使用的是MVVM,那么您应该做些什么来提出一个稍微不同的解决方案:

  • 去掉
    CommandParameter
  • 该命令将在
    MainWindowViewModel
    实例中触发回调
  • 此回调将更改
    MainWindowViewModel
    实例中的某些状态/属性
  • DockingManager
    实例通过绑定对
    MainWindowViewModel
    实例的调整状态作出反应
你现在做这件事的方式太复杂了。除此之外,你们还在这里疯狂地混合模式。MVVM试图将业务逻辑与实际元素分开。您正在使用具有智能UI/代码隐藏技术的MVVM元素


也可以考虑使用单独的视图模型来进行单独的控件。主菜单控件是独立的,停靠管理器也是独立的。为什么?因为你想把所有的东西分解成更小的部分,但更重要的是,你可能会考虑到可重用性。当主菜单试图访问

窗口中的停靠管理器时,这是不可能的。

由于您使用的是MVVM,因此您应该采取以下措施来提出稍微不同的解决方案:

  • 去掉
    CommandParameter
  • 该命令将在
    MainWindowViewModel
    实例中触发回调
  • 此回调将更改
    MainWindowViewModel
    实例中的某些状态/属性
  • DockingManager
    实例通过绑定对
    MainWindowViewModel
    实例的调整状态作出反应
你现在做这件事的方式太复杂了。除此之外,你们还在这里疯狂地混合模式。MVVM试图将业务逻辑与实际元素分开。您正在使用具有智能UI/代码隐藏技术的MVVM元素

也可以考虑使用单独的视图模型来进行单独的控件。主菜单控件是独立的,停靠管理器也是独立的。为什么?因为你想把所有的东西分解成更小的部分,但更重要的是,你可能会考虑到可重用性。主菜单试图访问

窗口中的停靠管理器,这是不可能的。

您可以使用:

CommandParameter="{x:Reference Name=yourElementName}"
您可以使用:

CommandParameter="{x:Reference Name=yourElementName}"


这会更优雅,但问题很简单,这并不能回答问题。@CodeMonkey你完全正确。我忍不住给出建议而不是回答(事实上我现在没有)。这是可以理解的,我会敦促用户823、5353考虑使用这个建议:你能再详细地说明一下你的建议吗?我通过绑定传递
dockingManager
的方法有什么不好?@user2823573我调整了我的答案。这会更优雅,但问题很简单,这并不能回答问题。@CodeMonkey你完全正确。我忍不住给出建议而不是回答(事实上我现在没有)。这是可以理解的,我会敦促用户823、5353考虑使用这个建议:你能再详细地说明一下你的建议吗?我通过绑定传递
dockingManager
的方法有什么不好?@user2823573我调整了我的答案。感谢快速重播。我也试过了。失败,返回
System.Windows.Data错误:4:找不到引用为“ElementName=dockingManager”的绑定源。BindingExpression:Path=。;DataItem=null;目标元素是“MenuItem”(名称=“”);目标属性为“CommandParameter”(类型为“Object”)
谢谢。这对我来说很有效,但看起来有点像肮脏的解决办法。可能我会保留一段时间,然后按照meilke描述的方式进行。这是一种变通方法,原因很简单:如果您有一个直接依赖于自身之外的控件的UserControl,那么可能这不是真正的UserControl。你试图做的事情并不是很好的实践,所以我强烈建议你试试梅尔克所描述的或类似的东西。一般来说,尽量避免UI中的横向依赖性(可能除了涉及简单外观和样式的任何情况),并坚持使用VM数据。只是对我发布的解决方案的一点评论:要做到这一点,一个稍微好一点的方法(不是黑客式的)是使用专用的DependencyProperty(例如,“DockingManagerDependencyProperty”)实际上,我只是考虑了我刚才说过的话:在我看来,这是一个很好的实践。为什么?MVVM的一个陷阱是试图把所有东西都推到VM中。总是这样想:你能想象一个没有特征A的应用程序的UI吗?(例如,没有停靠的静态UI)?如果是这样,那么功能A就不应该合并到VM中,因为VM应该是UI不可知的。感谢快速重播。也尝试过。失败原因是
System.Windows。数据错误:4:找不到引用“ElementName=dockingManager”的绑定源。BindingExpression:Path=;DataItem=null;目标元素是“MenuItem”(Name=“”);目标属性为“CommandParameter”(类型)