从子用户控件中获取父用户控件的属性值

4

我有一个ChildUserControl,它被加载在ParentUserControl中。主机页面加载ParentUserControl。

我需要从ChildUserControl访问ParentUserControl的属性。

感谢您的时间。

7个回答

10

由于平台/语言等不明确,因此这个答案必然是含糊的... 但是通常情况下,子控件不能直接访问父控件的属性,因为多种不同类型的父控件都可以托管子控件。子控件不应该被硬编码到单一的父控件中,否则它可能就像父控件的一部分。

通常,您可能想尝试简单地删除这个要求 - 这听起来像是一种奇怪的设计。但是,一些框架支持类似于此的功能-例如WPF中的依赖属性。

基于接口的设计(对于父对象)是一种方法,但这并不太干净。对于.NET,事件等是子元素与父元素通信的另一种常见方式-子元素公开事件,不同的父元素可以以不同的方式使用这些事件。

除此之外,您将涉及测试/强制转换父对象(针对类或接口),以从父对象中访问详细信息-例如:

ParentControlType parent = this.Parent as ParentControlType;
if(parent != null) {
    // access properties etc of "parent"
}

(这里也可以使用接口; 无论哪种方式都有点笨拙...)

个人而言,与其从子类中使用这种类型的强制转换,我更喜欢父类掌控;父类在子类上设置属性并侦听事件,而不是子类将属性设置回父类:

// in the parent
child.SomeProperty = 132;
child.SomePropertyChangd += delegate {
    // do something at the parent
};

这样,子组件不知道也不关心它的父组件是谁。它只知道自己有属性等,并且可以通知其他人发生了有趣的变化。


1

通过 ((ParentType)Me.Parent) 可以从子控件访问父级。但这不被推荐。无法知道该控件是否会在另一个页面/控件中使用。编译器不会捕获这一点,该强制转换会在运行时引发异常。

最好的处理方式是,父控件提供子控件需要的任何信息(在控件上创建公共属性或方法)。甚至可以意味着父控件为子控件提供其自身的强类型引用(可能通过接口)。这样,编译器就能确保您不会遇到子控件假定错误类型的父控件的情况。


0
如果您有2个嵌套的用户控件(UC):

UC1.ascx
      |— UC2.ascx

在UC1.ascx中,您定义一个公共函数或属性来执行所需操作:
   fnUC1(param)

在UC2.ascx中,您可以通过以下代码访问此函数:

CType(Parent.Parent,UC1).fnUC1(param)

如果您的UC2控件位于另一个容器内(例如重复器),您还必须从该容器中退出,因此代码将如下所示:

CType(Parent.Parent.Parent,UC1).fnUC1(param)

我承认这不是“艺术的状态”...但它适用于始终一起工作的嵌套控件,例如父(UC1)/子(UC2)数据显示。

希望这会有所帮助。

Pierre。


0

很抱歉没有表达清楚。平台是.NET,语言是C#。

我有一个单一的父控件,它托管多个子控件。这是在C#中实现可视化继承的一种方式,因为有许多UI控件是在子控件之间共享的。

通过接口设计,您是否建议父控件和子控件都实现一个公共接口?


只有在同一子控件由多个父控件托管时,接口(所有父控件都实现的)才是可接受的选项。个人而言,我更喜欢父控件接管并设置子控件的属性/订阅事件。 - Marc Gravell

0
你可以使用子控件的this.Parent属性,但如果你在寻找更合适的面向对象(OO)解决方案的话,你就不应该这么做。让子控件知道父控件的任何信息最终会以某种方式将它们绑定起来,并限制它们的重用性。在大多数情况下,这只是理论上的问题,如果你正在处理一些快速开发的临时站点,你可以违反这个规则。但更好的方式是使用基于事件的通信机制。

0

感谢回复。

我会考虑使用反射。不过,我听说它有性能瓶颈。

Jim - 你说:

~~

最好的处理方法是让父控件提供子控件需要的任何信息(在控件上创建公共属性或方法)。这甚至可能意味着父控件向子控件提供其自身的强类型引用(可能通过接口)。这样编译器就可以确保您不会出现子控件假设了错误类型的父控件的情况。

~~

在我的情况下,父类和子类都实现了相同的接口。这是不好的设计吗?如果我在接口中添加一个父类引用的属性,考虑到父类也实现了相同的接口,这会起作用吗?

0
您可以这样使用反射:
public static T GetData<T>(this Control c, string propertyName, T defaultValue){
  Type t = obj.GetType();
  var prop = t.GetProperties().FirstOrDefault(p => p.Name == propertyName);
  if(prop == null) return defaultValue;
  else {
    object val = prop.GetValue(obj, null);
    if(val == null) return defaultValue;
    else return (T)val;
  }
}

这个简单的扩展方法扩展了“Control”,但你可以轻松地将其放在任何东西上(当我传递匿名类时,我曾经在object上使用它,这本身就是一个坏主意!)

然后使用方法如下:

string someData = this.Parent.GetData("someProperty", string.Empty);

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