开发者

Automatically Cast, C#

开发者 https://www.devze.com 2023-04-12 17:14 出处:网络
Please, analyse th开发者_如何学Cis code.. I created thinking that we can join the label and control in one generic control. I implementing in this way:

Please, analyse th开发者_如何学Cis code.. I created thinking that we can join the label and control in one generic control. I implementing in this way:

//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;
}

and I can use, with something like this:

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;

The Only disadvantage is that I am forced to repeat what control type I want, but I am wondering if there is a way (maybe by reflection) of detecting the control type and return a object of this type and get the intellisense for this. like:

wc.ActualControl.Text = "123"; 
wc2.ActualControl.IsChecked = true;


If you're using C# 4 and .NET 4 you could just use dynamic typing. Change your property type to dynamic and you're away:

wc.WrappedControl = new CheckBox();
wc.WrappedControl.IsChecked = true;

Note that you can't detect the execution time type of a control and expect that to have an effect on the compile-time types.

Have you considered using generics though?

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;

If you also give T a new() constraint, WrappingControl could even create the nested control.

Another alternative is to use an object initializer to avoid having to refer to the control as often:

var wc = new WrappedControl
{
    MyLabel = "Test",
    MyControl = new CheckBox { IsChecked = true }
};


I think Jon's given you the answer. However you might want to consider using a Templated Control based on the ContentControl rather than a UserControl. Here is a starter for 10.

Add a new Silverlight Templated Control item to your project call its "LabeledControl".

Modify the .cs file create so that it looks like this:-

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
}

You'll note all that we have done is change the class being inherited to ContentControl and added a "Label" dependency property.

Now open the Themes/Generic.xaml file and find the default style for this control. Replace it with this:-

<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>

All we've done here is copied the original style for ContentControl and wrapped it up with a Grid so we can place a TextBlock that we bind to the Label property.

You will probably have noted by now that none of this actually solves the "problem" you wanted to solve. I'm just pointing out a much more "Silverlight-esq" approach to creating composite controls, its more flexible.

To your specific problem I would say its not actually a problem, in Jon's last sample he shows how you can construct your code to avoid duplication. With the above control that code would look like:-

var lc = new LabeledControl
{
    Label = "Check this:",
    Content = new CheckBox {IsChecked = True}

};

OR in Xaml:-

<local:LabeledControl Label="Check this:">
    <CheckBox IsChecked="True" />
</local>

As vcsjones points out to Jon using using a Generic class is not a very Silverlight friendly approach, I would avoid that.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号