如何在WPF的一个UserControl中传递信息到另一个UserControl?

5
我有一个WPF应用程序。
左侧是一个充满按钮的stackpanel。
右侧是一个空的dockpanel。
当用户点击一个按钮时,它会将相应的UserControl(视图)加载到dockpanel中:
private void btnGeneralClick(object sender, System.Windows.RoutedEventArgs e)
{
    PanelMainContent.Children.Clear();
    Button button = (Button)e.OriginalSource;
    Type type = this.GetType();
    Assembly assembly = type.Assembly;

    IBaseView userControl = UserControls[button.Tag.ToString()] as IBaseView;
    userControl.SetDataContext();

    PanelMainContent.Children.Add(userControl as UserControl);
}

这种模式非常有效,因为每个UserControl都是一个View,它有一个ViewModel类,该类提供来自Model的信息,因此用户可以从页面到页面进行点击,每个页面都可以执行隔离功能,例如编辑所有客户、保存到数据库等。

问题:

然而,现在,在其中一个页面上,我想要一个包含客户列表的ListBox,并且每个客户都有一个“编辑”按钮,当单击该编辑按钮时,我想要使用EditSingleCustomer UserControl填充DockPanel并将其传递给它所需编辑的客户。

我可以加载EditCustomer usercontrol,但是如何传递要编辑的客户并设置其DataContext以编辑该客户

  • 由于所有的UserControls都已经在MainWindow.xaml.cs中的字典中被创建并存在,所以我无法在构造函数中传递参数。
  • 因此,我为每个UserControl创建了一个PrepareUserControl方法,并将Customer作为参数传递给它。虽然可以通过x:Name="..."从代码后台使用文本框显示它,但这不是重点。当然,我需要将ItemsControl绑定到ObservableCollection以利用WPF的数据绑定功能。
  • 因此,我尝试像这样将ListBox ItemSource在视图中与其代码后台绑定:

<UserControl.Resources>
    <local:ManageSingleCustomer x:Key="CustomersDataProvider"/>
</UserControl.Resources>

<DockPanel>
    <ListBox ItemsSource="{Binding Path=CurrentCustomersBeingEdited, Source={StaticResource CustomersDataProvider}}"
             ItemTemplate="{DynamicResource allCustomersDataTemplate}"
             Style="{DynamicResource allCustomersListBox}">
    </ListBox>
</DockPanel>

出现了一个堆栈溢出错误,原因是在该视图的IntializeComponent()中发生了无限循环。 所以我认为我走错了路,必须有一些更简单的范例来在WPF中从一个UserControl传递命令到另一个UserControl(在有人说“使用WPF命令”之前,我已经在我的UserControl上使用了命令,允许用户编辑所有客户,这很好用,但是我不得不在我的视图的代码后台处理它(而不是在我的视图模型中),因为我需要父窗口上下文才能在完成保存后加载另一个用户控件:

<Button Style="{StaticResource formButton}" 
        Content="Save" 
        Command="local:Commands.SaveCustomer"
        CommandParameter="{Binding}"/>

private void OnSave(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
    Customer customer = e.Parameter as Customer;
    Customer.Save(customer);

    MainWindow parentShell = Window.GetWindow(this) as MainWindow;
    Button btnCustomers = parentShell.FindName("btnCustomers") as Button;
    btnCustomers.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
}

在WPF中,我应该如何简单地将UserControl加载到DockPanel中,在该UserControl内部放置一个带有命令的按钮,该命令会加载另一个UserControl并发送一个特定对象以将其绑定到其控件上?我想我目前对WPF命令了解不够,如果有人能指点我方向,那就太好了,或者如果您认为“在DockPanel中加载UserControls”这种模式对WPF来说是陌生的,应该避免使用并用另一种方式来构建应用程序,那也会是有帮助的消息。你可以在这里下载我的应用程序的当前状态以了解它的结构。谢谢。
3个回答

4
我刚刚完成了一个使用WPF的LOB应用程序,其中这种问题/模式经常出现,因此以下是我如何解决您的问题的方法:
1)在DataTemplate中创建每个ListBox中的项目以及其编辑按钮时,请将Button的tag属性绑定到该列表框项下面的Customer对象。
2)为按钮创建Click事件处理程序,并将Button的Click事件设置为触发处理程序。
3)在事件处理程序中,设置UserControl的Content属性。
4)在User Control的范围内设置一个DataTemplate(可能在其直接容器的资源中),该DataTemplate描述了单个客户的编辑器。
另一种可行的方法是在EditCustomer类上声明一个Customer依赖属性,然后在单击按钮时设置该属性(可能通过XAML触发器)。
我希望这不会太模糊。如果没有别的,知道您面临的问题在WPF中非常可解决。

3
这是使用中介者模式的地方。有关此主题的几篇博客文章(例如此示例)以及某些WPF框架中模式的实现(例如Prism中的EventAggregator)。请注意,HTML标签应保留。

1

我没有时间深入研究这个问题(这是一个有趣的问题,希望你能得到一个好的答案——我可以看到自己在未来遇到类似的情况)。

你考虑过放弃一些 WPF 的特性,改为在源 UserControl 上触发一个包含客户信息的 EventArgs 事件,在事件处理程序中再触发目标控件上的适当命令吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接