首页 文章

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

提问于
浏览
4

我有一个WPF应用程序 .

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

在右侧有一个空的dockpanel .

当用户 clicks a button 时,它 loads the corresponding 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);
}

This pattern works well 因为每个UserControl都是一个View,它有一个ViewModel类,它为它提供从Model获取的信息,因此用户可以在页面之间点击,每个页面都可以执行独立的功能,例如编辑所有客户,保存到数据库等

问题:

但是,现在,在其中一个页面上,我想要一个ListBox,其中包含Customers列表,每个客户都有一个“编辑”按钮,当单击该编辑按钮时,我想用EditSingleCustomer填充DockPanel 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错误 . So I'm thinking I'm going about this in the wrong way, there must be some easier paradigm to simply pass commands from one UserControl to another UserControl in WPF (在有人说"use WPF commanding"之前,我已经在我的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));
}

So how in WPF can I simply have a UserControl loaded in a DockPanel, inside that UserControl a button with a command on it that loads another UserControl and sends that UserControl a specific object to which it can bind its controls?

我可以想象,我现在对WPF命令知之甚少,如果有人能从这里指出正确的方向,那将是很好的,或者如果你认为这个"loading UserControls in a DockPanel pattern is foreign to WPF and should be avoided and replaced with another way to structure applications",这也是有用的新闻 . 您可以download the current state of my application here了解它的结构 . 谢谢 .

3 回答

  • 3

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

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

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

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

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

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

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

  • 1

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

  • 3

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

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

相关问题