请分析这段代码..我创建了一个认为我们可以在一个通用控件中加入标签和控件的想法。我以这种方式实施:
//my class
public partial class WrappingControl : UserControl
{
public string MyLabel { get { return lb.Text; } set { lb.Text = value; } }
public UIElement MyControl { get { return uc.Content; } set { uc.Content = value; } }
public T CastControl<T>()
{
return (T)Convert.ChangeType(MyControl, typeof(T), null);
}
}
//silverlight class
public partial class WrappingControl : UserControl
{
TextBlock lb;
UserControl uc;
}
我可以使用这样的东西:
var wc =new WrappingControl();
wc.MyLabel = "ID:";
wc.MyControl = new TextBox();
wc.CastControl<TextBox>().Text="123";
var wc2 = new WrappingControl();
wc2.MyLabel = "Is Ok?:";
wc2.MyControl = new CheckBox();
wc2.CastControl<CheckBox>().IsChecked = true;
唯一的缺点是我被迫重复我想要的控制类型,但我想知道是否有一种方法(可能通过反射)检测控件类型并返回此类型的对象并获取intellisense为这个。像:
wc.ActualControl.Text = "123";
wc2.ActualControl.IsChecked = true;
答案 0 :(得分:4)
如果您使用的是C#4和.NET 4,则可以使用动态类型。将您的媒体资源类型更改为dynamic
即可离开:
wc.WrappedControl = new CheckBox();
wc.WrappedControl.IsChecked = true;
请注意,您无法检测到控件的执行时间类型,并希望它对编译时类型产生影响。
您是否考虑过使用泛型?
public partial class WrappingControl<T> : UserControl where T : UIElement
{
public T WrappedControl { get; set; } // Add appropriate logic
}
var wc2 = new WrappingControl<CheckBox>();
wc2.WrappedControl = new CheckBox();
wc2.WrappedControl.IsChecked = true;
如果您还给T
new()
约束,WrappingControl
甚至可以创建嵌套控件。
另一种方法是使用对象初始化程序来避免经常引用控件:
var wc = new WrappedControl
{
MyLabel = "Test",
MyControl = new CheckBox { IsChecked = true }
};
答案 1 :(得分:0)
我认为乔恩给了你答案。但是,您可能需要考虑使用基于ContentControl
而不是UserControl
的模板化控件。这是10的首发。
将新的Silverlight Templated Control项添加到项目中,调用其“LabeledControl”。
修改.cs文件创建,使其如下所示: -
public class LabeledControl : ContentControl
{
public LabeledControl()
{
this.DefaultStyleKey = typeof(LabeledControl);
}
#region public string Label
public string Label
{
get { return GetValue(LabelProperty) as string; }
set { SetValue(LabelProperty, value); }
}
public static readonly DependencyProperty LabelProperty =
DependencyProperty.Register(
"Label",
typeof(string),
typeof(LabeledControl),
new PropertyMetadata(null));
#endregion public string Label
}
您将注意到我们所做的就是将继承的类更改为ContentControl
并添加“Label”依赖项属性。
现在打开Themes / Generic.xaml文件并找到此控件的默认样式。替换为: -
<Style TargetType="local:LabeledControl">
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:LabeledControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="{TemplateBinding Label}" />
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我们在此完成的所有内容都会复制ContentControl
的原始样式,并使用Grid
将其整理好,以便我们可以放置TextBlock
与Label
绑定的var lc = new LabeledControl
{
Label = "Check this:",
Content = new CheckBox {IsChecked = True}
};
} property。
你现在可能已经注意到,这些都没有解决你想要解决的“问题”。我只是指出了更多“Silverlight-esq”方法来创建复合控件,它更灵活。
对于您的具体问题,我会说它实际上不是问题,在Jon的最后一个示例中,他展示了如何构建代码以避免重复。使用上面的控件代码看起来像: -
<local:LabeledControl Label="Check this:">
<CheckBox IsChecked="True" />
</local>
或者在Xaml中: -
{{1}}
正如vcsjones指出Jon使用Generic类不是一个非常Silverlight友好的方法,我会避免这种情况。