C# 如何将CommandParameter与子UserControl';子元素是什么?
我有以下xaml视图:C# 如何将CommandParameter与子UserControl';子元素是什么?,c#,wpf,xaml,prism,C#,Wpf,Xaml,Prism,我有以下xaml视图: <UserControl x:Class="MyViews.PersonView" xmlns:views="clr-namespace:MyViews" [...] > [...] <dxb:BarManager x:Name="MainBarManager"> <dxb:BarManager.Items> <dxb:BarButtonItem x:Name="bbiPrint"
<UserControl x:Class="MyViews.PersonView"
xmlns:views="clr-namespace:MyViews"
[...]
>
[...]
<dxb:BarManager x:Name="MainBarManager">
<dxb:BarManager.Items>
<dxb:BarButtonItem x:Name="bbiPrint"
Content="{Binding Print, Source={StaticResource CommonResources}}"
Command="{Binding PrintPersonsCommand}"
CommandParameter="{Binding PersonsCardView, ElementName=CardUserControl}"
/>
</dxb:BarManager.Items>
<Grid>
<Grid.RowDefinitions>
[...]
</Grid.RowDefinitions>
<views:CardView x:Name="CardUserControl" Grid.Row="2"/>
</Grid>
[...]
</UserControl>
printPersonCommand
在我的ViewModel中定义如下:
public class PersonViewModel
{
public PersonViewModel(...)
{
[...]
PrintPersonsCommand = new Prism.Commands.DelegateCommand<DataViewBase>(PrintPersons, CanPrintPersons);
}
public Prism.Commands.DelegateCommand<DataViewBase> PrintPersonsCommand { get; private set; }
private void PrintPersons(DataViewBase view)
{
_printService.ShowGridViewPrintPreview(view);
}
private bool CanPrintPersons(DataViewBase view)
{
return true;
}
}
让它工作
目前,我找到的解决此问题的唯一方法是将命令
和命令参数
替换为
ItemClick="OnPrintBtnClick"
然后在PersonView
的代码隐藏文件中执行以下操作:
private void OnPrintBtnClick(object sender, ItemClickEventArgs e)
{
var ctxt = DataContext as PersonViewModel;
ctxt.PrintPersonsCommand.Execute(CardUserControl.PersonsCardView);
}
这是可行的,但我不敢相信没有其他办法。我对这个解决方案不满意,因为我再也没有使用命令的好处了,比如自动评估命令的CanExecute
方法。我也可以将CardView
的xaml代码放在PersonView.xaml
中,但我喜欢我的控件放在单独的文件中,因为我觉得它更结构化,每个用户控件都有自己的职责,可以很好地拆分成单独的文件。此外,该解决方案将我的视图与视图模型绑定得太紧
有人能帮我吗?在不更改现有视图和viewmodel层次结构的情况下,我可以使用标记属性将GridControl.view传递给PersonViewModel
您可以将CardView分配给CardView用户控件底部的Tag属性,然后作为CommandParameter访问此标记
CardView用户控件
<UserControl x:Class="MyViews.CardView"
[...]>
[...]
<dxg:GridControl ItemsSource="{Binding Persons}" SelectedItems="{Binding SelectedPersons}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" SelectionMode="MultipleRow">
[...]
<dxg:GridControl.View>
<dxg:CardView x:Name="PersonsCardView"
[...]
CardTemplate="{StaticResource DisplayCardTemplate}"
PrintCardViewItemTemplate="{StaticResource PrintCardTemplate}"/>
</dxg:GridControl.View>
[...]
</dxg:GridControl>
<UserControl.Tag>
<Binding ElementName="PersonsCardView"/>
</UserControl.Tag>
</UserControl>
[...]
[...]
[...]
打印按钮Xaml:
<dxb:BarButtonItem x:Name="bbiPrint"
Content="{Binding Print, Source={StaticResource CommonResources}}"
Command="{Binding PrintPersonsCommand}"
CommandParameter="{Binding ElementName=CardUserControl, Path=Tag}"
/>
基于《疯狂》的宝贵输入,我提出了以下两个更干净的修复方案:
代码隐藏解决方案
在PersonView
中,使用项目单击打印按钮上的事件处理程序:
<dxb:BarButtonItem x:Name="bbiPrint"
Content="{Binding Print, Source={StaticResource CommonResources}}"
ItemClick="OnPrintBtnClick"/>
因为我想在没有选择的情况下灰显打印按钮,所以我仍然需要添加一些代码来实现这一点。我能应付得来
1.将按钮代码更新为
<dxb:BarButtonItem x:Name="bbiPrint"
Content="{Binding Print, Source={StaticResource CommonResources}}"
ItemClick="OnPrintBtnClick" IsEnabled="{Binding CanPrintPersons}"/>
其中,视图
是一个CardViewModel
的属性,该属性是在加载时设置的,例如
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="Loaded" Command="{Binding ViewLoadedCommand}" CommandParameter="{Binding ElementName=PersonsCardView}" />
</dxmvvm:Interaction.Behaviors>
因为我有两个子视图要打印,所以我需要为每一个子视图添加一个视图模型。此外,这两个视图模型加上PersonViewModel
需要访问要打印的人员列表。特别是,它们需要共享对相同数据的访问,以便同步。我们解释了一种简单的方法,它是完全可行的。但是我认为,对于我所拥有的简单用例来说,它不值得费心,因为它增加了比必要的更多的复杂性 你需要这个参数做什么?例如,PersonsCardView
中有哪些内容不在PersonViewModel
中?我想打印我的卡片视图中的卡片。我有其他视图,如栅格视图。PersonViewModel
没有关于该PersonsCardView
的信息。它只携带打印视图所需的逻辑。我不希望PersonViewModel
中有任何关于要打印的视图的信息。它会将视图模型与视图绑定得太紧。MyPersonView
的子视图(如上面提到的CardView
和上面没有提到的GridView
)都共享同一个视图模型。公平点,但将视图作为参数传递给视图模型看起来已经是我能想象到的最紧密的耦合了。不,因为我正在传递它的抽象概念。cardwiew
和GridView
都继承自DataViewBase
。我不希望我的应用程序中使用的任何视图都是不同类型的。这非常有效。这是继续WPF标准的方式,还是我用错误的方式做我的事情?有没有更好的方法来组织我的UserControls?MVVM通常不鼓励将UI控件传递给viewmodel。如果我们必须只打印视图,那么我们可以在代码隐藏中完成,因为打印控件与viewmodel无关。或者,如果必须在viewmodel中启动打印,则我会将打印命令放置在CardViewModel中。只要使用CommandParameter作为绑定,就可以使UI元素的传递更加清晰;我将发布一个我对你的两个建议的理解的答案
public partial class PersonView : UserControl
{
readonly IPrintService _printService;
public PersonView(IPrintService printService)
{
_printService = printService;
InitializeComponent();
}
private void OnPrintBtnClick(object sender, ItemClickEventArgs e)
{
_printService.ShowGridViewPrintPreview(CardUserControl.PersonsCardView);
}
}
<dxb:BarButtonItem x:Name="bbiPrint"
Content="{Binding Print, Source={StaticResource CommonResources}}"
ItemClick="OnPrintBtnClick" IsEnabled="{Binding CanPrintPersons}"/>
_printService.ShowGridViewPrintPreview(View);
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="Loaded" Command="{Binding ViewLoadedCommand}" CommandParameter="{Binding ElementName=PersonsCardView}" />
</dxmvvm:Interaction.Behaviors>