如何将信息从一个 WPF UserControl 传递到另一个 WPF UserControl?

Edw*_*uay 5 c# wpf user-controls application-design

我有一个 WPF 应用程序。

在左侧有一个充满按钮的堆栈面板。

右侧有一个空的停靠面板。

当用户单击按钮时,它会将相应的 UserControl (View)加载到停靠面板中:

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);
}
Run Code Online (Sandbox Code Playgroud)

这种模式很有效,因为每个 UserControl 都是一个 View,它有一个 ViewModel 类,该类向它提供从模型中获取的信息,因此用户可以在页面之间单击,并且每个页面都可以执行独立的功能,例如编辑所有客户,保存到数据库等

问题:

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

我可以加载 EditCustomer 用户控件,但是如何将它传递给客户以编辑并设置其 DataContext 以编辑该客户?

  • 我无法在构造函数中传递它,因为所有 UserControl 都已创建并存在于 MainWindow.xaml.cs 的字典中。
  • 所以我在每个 UserControl 上创建了一个 PrepareUserControl 方法并将 Customer 传递给它,并且可以使用 x:Name="..." 代码后面的文本框显示它,但这不是重点,我需要将 ItemsControl 数据绑定到ObservableCollection 当然可以利用 WPF 的数据绑定功能。
  • 所以我尝试将 View 中的 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>
Run Code Online (Sandbox Code Playgroud)

这会导致该视图中的 IntializeComponent() 中的无限循环导致计算器溢出错误。所以我想我会以错误的方式解决这个问题,必须有一些更简单的范例来简单地将命令从一个 UserControl 传递到 WPF 中的另一个 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));
}
Run Code Online (Sandbox Code Playgroud)

那么,在 WPF 中,我如何才能简单地在 DockPanel 中加载一个 UserControl,在该 UserControl 内有一个带有命令的按钮,该按钮加载另一个 UserControl并向该 UserControl 发送一个可以绑定其控件的特定对象?

我可以想象我此时对 WPF 命令的了解还不够,如果有人能从这里向我指出正确的方向,那就太好了,或者如果您认为“在 DockPanel 模式中加载 UserControls 对 WPF 和应该避免并用另一种构建应用程序的方式代替”,这也是有用的消息。您可以在此处下载我的应用程序的当前状态,以了解它的结构。谢谢。

Mar*_*ark 4

我刚刚使用 WPF 完成了一个 LOB 应用程序,其中经常出现此类问题/模式,因此我将如何解决您的问题:

1) 在 DataTemplate 中创建 ListBox 中的每个项目及其编辑按钮,将 Button 的 tag 属性绑定到该列表框项目下的 Customer 对象。

2) 为按钮创建 Click 事件处理程序,并设置按钮的 Click 事件来触发该处理程序。

3) 在事件处理程序中,设置 UserControl 的 Content 属性。

4) 在用户控件范围内(可能在其直接容器的资源中)设置一个 DataTemplate,它描述了该单个客户的编辑器。

另一种可行的方法是在 EditCustomer 类上声明 Customer 依赖属性,然后在单击按钮时设置该属性(可能通过 XAML 触发器)。

我希望这不是太模糊。如果没有别的事,请知道您所面临的问题在 WPF 中是可以解决的。