自动转换,c#
本文关键字:转换 | 更新日期: 2023-09-27 18:11:07
请分析这段代码。我创造了这样的想法:我们可以将标签和控件合并到一个通用控件中。我是这样实现的:
//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;
唯一的缺点是我被迫重复我想要的控制类型,但我想知道是否有一种方法(可能是通过反射)检测控制类型并返回此类型的对象并获得此智能感知。如:
wc.ActualControl.Text = "123";
wc2.ActualControl.IsChecked = true;
如果你正在使用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 }
};
我想Jon已经给你答案了。但是,您可能想要考虑使用基于ContentControl
而不是UserControl
的模板化控件。这是10元的开胃菜。
在你的项目中添加一个新的Silverlight模板控件项,命名为"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"依赖属性。
现在打开主题/通用。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
属性。
你现在可能已经注意到,这些都不能真正解决你想要解决的"问题"。我只是指出一种更"Silverlight-esq"的方法来创建复合控件,它更灵活。
对于你的具体问题,我会说这实际上不是问题,在Jon的最后一个示例中,他展示了如何构造代码以避免重复。使用上面的控件,代码看起来像:-
var lc = new LabeledControl
{
Label = "Check this:",
Content = new CheckBox {IsChecked = True}
};
OR在Xaml:-
<local:LabeledControl Label="Check this:">
<CheckBox IsChecked="True" />
</local>
正如vcsjones向Jon指出的那样,使用泛型类并不是Silverlight非常友好的方法,我会避免使用泛型类。