WPF 中嵌套用户控件之间的复杂命令数据绑定
Complex Command DataBinding between nested UserControls in WPF
我的 TestAdmin Class 库中有一个名为 PAInstructionsControl 的用户控件。
<UserControl x:Class="TestAdmin.Controls.PAInstructionsControl">
<Button Command="{Binding ???}"
CommandParameter="{Binding ???}"/>
</UserControl>
在此 UserControl 的使用者中:我需要一个 ViewModel 用作 Button 的命令绑定,并需要一个不同的 ViewModel 用于其 CommandParameter,但我不确定如何执行此操作。
在我的 WMT Class 库中,我有一个 WmtPAInstructionsView UserControl 使用 PAInstructionsControl
<UserControl x:Class="WMT.View.WmtPAInstructionsView"
xmlns:controls="clr-namespace:TestAdmin.Controls;assembly=TestAdmin">
<StackPanel>
<TextBlock Text="WMT PA Instructions View"
Margin="10"/>
<controls:PAInstructionsControl />
</StackPanel>
</UserControl>
WmtPAInstructionsView 嵌套在 WMT.WmtMainWindow 用户控件中
如果 Button 只是在 WmtPAInstructionsView UserControl 内,那么我需要这些 ViewModel 绑定:
<Button
Command="{Binding DataContext.DisplayNextIndexedViewCommand, RelativeSource=
{RelativeSource AncestorType={x:Type local:WmtMainWindow}}, Mode=OneWay}"
CommandParameter="{Binding}"/>
因此该命令将绑定到 WmtMainWindow 的 DataContext 中的命令。 CommandParameter 将是 WmtPAInstructionView 的 DataContext,即 WmtPAInstructionsViewModel
但我需要 PAInstructionsControl 中的按钮,因此它可以是 re-used 我解决方案中的其他地方。我将使用什么来绑定 Command 和 CommandParameter?我需要依赖属性吗?
希望以上信息能帮助您回答我的问题。如果您需要,这里有更多信息:
我还有一个 MSVT Class 库,它有一个 MsvtPAInstructionsView 使用 PAInstructionsControl 的用户控件 以类似的方式。
如果 Button 只是在 MsvtPAInstructionsView UserControl 内,那么我需要这些 ViewModel 绑定:
<Button
Command="{Binding DataContext.DisplayNextIndexedViewCommand, RelativeSource=
{RelativeSource AncestorType={x:Type local:MsvtMainWindow}}, Mode=OneWay}"
CommandParameter="{Binding}"/>
WMT 和 MSVT Class 库都引用了 TestAdmin 库. WMT 和 MVST 不相互引用。
这是主应用程序 Window (WpfTestBase.MainWindow):
单击“新 WMT 测试”将打开一个新的 WpfTestBase.TestView Window。
这个 TestView Window 有几个嵌套的用户控件:
这是视觉树:
“简单”(但有点糟糕)的解决方案是:
<Button
Command="{Binding DataContext.DisplayNextIndexedViewCommand, RelativeSource=
{RelativeSource AncestorType={x:Type Window}}, Mode=OneWay}"
CommandParameter="{Binding}"/>
这适用于 Window
的 任何 子类。虽然它确实“解决”了您的问题,但它做出了许多假设。最大的问题是你会假设你总是希望你的 Button
绑定到父 Window
,并且 Window
的 DataContext
总是有一个属性 完全命名为 DisplayNextIndexedViewCommand
.
更好的解决方案是在每个 UserControl
中定义一个 DependencyProperty
链,您可以在其中将每个子项绑定到其父项。这将使您在使用控件时具有完全的灵活性。
从PAInstructionsControl
开始定义一个DisplayNextIndexedViewCommand
DependencyProperty
。然后,您可以像这样将 Buton.Command
绑定到那个 属性:
<Button
Command="{Binding DisplayNextIndexedViewCommand, RelativeSource=
{RelativeSource AncestorType={x:Type local:PAInstructionsControl}}, Mode=OneWay}"
CommandParameter="{Binding}"/>
这使您的嵌套更接近顶部。接下来,还要在WmtPAInstructionsView
中声明一个DisplayNextIndexedViewCommand
DependencyProperty
。这使您可以像这样将 PAInstructionsControl.DisplayNextIndexedViewCommand
绑定到 WmtPAInstructionsView.DisplayNextIndexedViewCommand
:
<UserControl x:Class="WMT.View.WmtPAInstructionsView"
xmlns:controls="clr-namespace:TestAdmin.Controls;assembly=TestAdmin">
<StackPanel>
<TextBlock Text="WMT PA Instructions View"
Margin="10"/>
<controls:PAInstructionsControl DisplayNextIndexedViewCommand="{Binding DisplayNextIndexedViewCommand, RelativeSource={RelativeSource AncestorType={x:Type local:WmtPAInstructionsView}}}"/>
</StackPanel>
</UserControl>
现在,您终于可以将 WmtPAInstructionsView.DisplayNextIndexedViewCommand
绑定到 实际 命令,您在 Window
的 DataContext
中拥有该命令:
<local:WmtPAInstructionsView DisplayNextIndexedViewCommand="{Binding DataContext.DisplayNextIndexedViewCommand, RelativeSource={RelativeSource AncestorType={x:Type local:WmtMainWindow}}, Mode=OneWay}"/>
(此外,由于 DataContext
是继承的,您可以从 Binding
中省略“DataContext.
”和整个 RelativeSource
)
我的 TestAdmin Class 库中有一个名为 PAInstructionsControl 的用户控件。
<UserControl x:Class="TestAdmin.Controls.PAInstructionsControl">
<Button Command="{Binding ???}"
CommandParameter="{Binding ???}"/>
</UserControl>
在此 UserControl 的使用者中:我需要一个 ViewModel 用作 Button 的命令绑定,并需要一个不同的 ViewModel 用于其 CommandParameter,但我不确定如何执行此操作。
在我的 WMT Class 库中,我有一个 WmtPAInstructionsView UserControl 使用 PAInstructionsControl
<UserControl x:Class="WMT.View.WmtPAInstructionsView"
xmlns:controls="clr-namespace:TestAdmin.Controls;assembly=TestAdmin">
<StackPanel>
<TextBlock Text="WMT PA Instructions View"
Margin="10"/>
<controls:PAInstructionsControl />
</StackPanel>
</UserControl>
WmtPAInstructionsView 嵌套在 WMT.WmtMainWindow 用户控件中
如果 Button 只是在 WmtPAInstructionsView UserControl 内,那么我需要这些 ViewModel 绑定:
<Button
Command="{Binding DataContext.DisplayNextIndexedViewCommand, RelativeSource=
{RelativeSource AncestorType={x:Type local:WmtMainWindow}}, Mode=OneWay}"
CommandParameter="{Binding}"/>
因此该命令将绑定到 WmtMainWindow 的 DataContext 中的命令。 CommandParameter 将是 WmtPAInstructionView 的 DataContext,即 WmtPAInstructionsViewModel
但我需要 PAInstructionsControl 中的按钮,因此它可以是 re-used 我解决方案中的其他地方。我将使用什么来绑定 Command 和 CommandParameter?我需要依赖属性吗?
希望以上信息能帮助您回答我的问题。如果您需要,这里有更多信息:
我还有一个 MSVT Class 库,它有一个 MsvtPAInstructionsView 使用 PAInstructionsControl 的用户控件 以类似的方式。
如果 Button 只是在 MsvtPAInstructionsView UserControl 内,那么我需要这些 ViewModel 绑定:
<Button
Command="{Binding DataContext.DisplayNextIndexedViewCommand, RelativeSource=
{RelativeSource AncestorType={x:Type local:MsvtMainWindow}}, Mode=OneWay}"
CommandParameter="{Binding}"/>
WMT 和 MSVT Class 库都引用了 TestAdmin 库. WMT 和 MVST 不相互引用。
这是主应用程序 Window (WpfTestBase.MainWindow):
单击“新 WMT 测试”将打开一个新的 WpfTestBase.TestView Window。
这个 TestView Window 有几个嵌套的用户控件:
这是视觉树:
“简单”(但有点糟糕)的解决方案是:
<Button
Command="{Binding DataContext.DisplayNextIndexedViewCommand, RelativeSource=
{RelativeSource AncestorType={x:Type Window}}, Mode=OneWay}"
CommandParameter="{Binding}"/>
这适用于 Window
的 任何 子类。虽然它确实“解决”了您的问题,但它做出了许多假设。最大的问题是你会假设你总是希望你的 Button
绑定到父 Window
,并且 Window
的 DataContext
总是有一个属性 完全命名为 DisplayNextIndexedViewCommand
.
更好的解决方案是在每个 UserControl
中定义一个 DependencyProperty
链,您可以在其中将每个子项绑定到其父项。这将使您在使用控件时具有完全的灵活性。
从PAInstructionsControl
开始定义一个DisplayNextIndexedViewCommand
DependencyProperty
。然后,您可以像这样将 Buton.Command
绑定到那个 属性:
<Button
Command="{Binding DisplayNextIndexedViewCommand, RelativeSource=
{RelativeSource AncestorType={x:Type local:PAInstructionsControl}}, Mode=OneWay}"
CommandParameter="{Binding}"/>
这使您的嵌套更接近顶部。接下来,还要在WmtPAInstructionsView
中声明一个DisplayNextIndexedViewCommand
DependencyProperty
。这使您可以像这样将 PAInstructionsControl.DisplayNextIndexedViewCommand
绑定到 WmtPAInstructionsView.DisplayNextIndexedViewCommand
:
<UserControl x:Class="WMT.View.WmtPAInstructionsView"
xmlns:controls="clr-namespace:TestAdmin.Controls;assembly=TestAdmin">
<StackPanel>
<TextBlock Text="WMT PA Instructions View"
Margin="10"/>
<controls:PAInstructionsControl DisplayNextIndexedViewCommand="{Binding DisplayNextIndexedViewCommand, RelativeSource={RelativeSource AncestorType={x:Type local:WmtPAInstructionsView}}}"/>
</StackPanel>
</UserControl>
现在,您终于可以将 WmtPAInstructionsView.DisplayNextIndexedViewCommand
绑定到 实际 命令,您在 Window
的 DataContext
中拥有该命令:
<local:WmtPAInstructionsView DisplayNextIndexedViewCommand="{Binding DataContext.DisplayNextIndexedViewCommand, RelativeSource={RelativeSource AncestorType={x:Type local:WmtMainWindow}}, Mode=OneWay}"/>
(此外,由于 DataContext
是继承的,您可以从 Binding
中省略“DataContext.
”和整个 RelativeSource
)