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

时间:2009-05-08 14:57:53

标签: c# wpf user-controls application-design

我有一个WPF应用程序。

在左侧有一个堆满了按钮的堆叠面板。

在右侧有一个空的停靠区。

当用户点击按钮时,会将相应的UserControl (查看)加载到停靠栏中:

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类,它从模型中获取信息,因此用户可以在页面之间点击,每个页面都可以携带隔离功能,例如编辑所有客户,保存到数据库等等。

问题:

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

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

  • 我无法在构造函数中传递它,因为所有UserControl都已创建并存在于MainWindow.xaml.cs中的Dictionary中。
  • 所以我在每个UserControl上创建了一个PrepareUserControl方法并将Customer传递给它,并且可以使用x:Name =“...”后面的代码显示一个文本框,但这不是重点,我需要DataBind一个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>

它获取由该视图中的IntializeComponent()中的无限循环引起的stackoverflow错误。 所以我认为我会以错误的方式解决这个问题,必须有一些更简单的范例来简单地将命令从一个UserControl传递到WPF中的另一个UserControl (之后有人说“使用WPF命令” “,我已经在我的UserControl上使用命令,允许用户编辑所有客户,这工作正常,但我必须在我的视图后面的代码中处理它(而不是在我的viewmodel中),因为我需要父窗口上下文能够在完成保存后加载另一个用户控件:

<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,向UserControl发送一个它可以绑定的特定对象它的控制?

我可以想象我此时对WPF命令知之甚少,如果有人能从这里指出正确的方向,那就太好了,或者如果你认为这个“在DockPanel模式中加载UserControls是外来的对WPF应该避免并用另一种构建应用程序的方式替换“,这也是有用的新闻。您可以download the current state of my application here了解其结构。感谢。

3 个答案:

答案 0 :(得分:3)

这是您使用Mediator模式的地方。关于此主题有几篇博客文章(针对instance),并且在某些WPF框架中有模式的实现(例如EventAggregator中的Prism)。

答案 1 :(得分:3)

我刚刚使用WPF完成了一个LOB应用程序,这种问题/模式经常出现,所以这就是我如何解决你的问题:

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

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

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

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

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

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

答案 2 :(得分:1)

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

您是否考虑过少一点WPF-y并回退到使用包含客户的EventArgs在您的源UserControl上触发事件,然后在事件处理程序中,在目标控件上触发相应的命令?