1

The usage of question is a bit odd.

I am trying to return one of the TextBox, Button or even Label object from a function when I give string name of the object, like code below:

public [I don't know the type] getObjectClass(string type) {
    switch(type) {
    case "textbox":
        return new TextBox();
    break;
    case "label":
        return new Label();
    break;
}

and finally I can access the object:

var obj = getObjectClass("label").Content = "I am new label!..";
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Alex
  • 715
  • 5
  • 14

6 Answers6

2

You probably want dynamic for your return type.

public dynamic getObjectClass(string type)

Using Control, the lowest common ancestor to both Label and TextBox, would not let you access properties of the specific class that you create.

Note that this approach has risks, because the code is no longer type-safe. Another approach would be to use generics, but then you would have to specify the type along with a matching string with the type name, defeating the purpose of getObjectClass method.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Isn't any issues for dynamic usage of it, like intellisense? – Alex May 02 '15 at 11:15
  • @AliTorabi Yes, intellisense is gone on `dynamic` types. Essentially, the compiler lets you access any properties and call any methods on it, with the understanding that it may fail at compile time. – Sergey Kalinichenko May 02 '15 at 11:17
1

Short answer: Find some class that is a superclass of all possible return types. For example, consider System.Windows.Controls.Control.

Additional info: You're trying to create a dynamic way of creating objects. This could be fine, for example for allowing your user to create their own interfaces, but I feel it is a potential code smell. For example, if you want to create a textbox and then set its text, you might do something like this:

Control myTextbox = CreateObjectFromTypename("textbox");
((TextBox)myTextbox).Text = "Hello, world!";

But now that you know the control will be cast into a textbox, why do you need to create it dynamically? Why couldn't you have used TextBox myTextbox = new TextBox()?

Again, I can't say for sure that your approach is bad, but I advice that you take care, and ensure that you really do need this dynamic creation.

MariusUt
  • 752
  • 4
  • 15
  • I couldn't use TextBox myt = new TextBox() because I am putting many types in switch case, so I can't Make TextBox object. – Alex May 02 '15 at 11:28
1

I am guessing you want to add controls to the UI dynamically. Since you have to set a property in the Control i.e. for TextBox you have to set the Text property, for Label you have you set the Content property. I suggest the following approach.

In the below sample I add a textbox and label to the UI dynamically.

The important piece in the below code is the Dictionary<Type, Action<Control, String>> property. In this Dictionary I define how to set the content for each Control depending on its Type.

Note: I would suggest you to design in such a way that you don't separate the instance creation and property assignment into two different method. Do it in one single go. Check the new method with signature getObjectClass(string type, String content, Thickness margin).

XAML:

<Window x:Class="SplashScreenDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="800">
    <StackPanel Name="StackPanelObj">

    </StackPanel>
</Window>

Codebehind:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace SplashScreenDemo
{

    public partial class MainWindow : Window
    {
        Dictionary<Type, Action<Control, String>> SetContent = new Dictionary<Type, Action<Control, String>> 
        {
            { typeof(TextBox), (control, content) =>  (control as TextBox).Text = content},
            { typeof(Label), (control, content) =>  (control as Label).Content = content}
        };

        public MainWindow()
        {
            InitializeComponent();

            Control control = getObjectClass("textbox");
            SetContent[control.GetType()](control, "This is a textbox");

            Control control2 = getObjectClass("label");
            SetContent[control2.GetType()](control2, "This is a label");

            StackPanelObj.Children.Add(control);
            StackPanelObj.Children.Add(control2);
        }

        public Control getObjectClass(string type)
        {
            switch (type)
            {
                case "textbox":
                    return new TextBox();
                case "label":
                    return new Label();
                default:
                    return null;
            }
        }


        public Control getObjectClass(string type, String content, Thickness margin)
        {
            switch (type)
            {
                case "textbox":
                    var textBox = new TextBox();
                    textBox.Text = content;
                    textBox.Margin = margin;
                    return textBox;
                case "label":
                    return new Label();
                default:
                    return null;
            }
        }

    }

}
Anand Murali
  • 4,091
  • 1
  • 33
  • 46
  • Very very complete answer and same mechanism I am using after all these answers. The dynamic keyword is the easiest possible but not the best solution. Simply, your solution is better for development. – Alex May 02 '15 at 11:45
  • I would suggest you to design in such a way that you don't separate the instance creation and property assignment into two different method. Do it in one single go. Check the new method with signature `getObjectClass(string type, String content, Thickness margin)` – Anand Murali May 02 '15 at 11:56
0

First you need have full name of the type. Since you want to create WPF controls, concat control type name with 'System.Windows.Controls'. Then you need to use Type.GetType to create an instance of underlying type, and finally use Activator.CreateInstance to create an instance of the Control.

public Control CreateControlByTypeName(string typeName) {
    string fullName = string.Format("System.Windows.Controls.{0}", typeName);
    Type type = Type.GetType(fullName);
    return (Control)Activator.CreateInstance(type);
}
Mehrzad Chehraz
  • 5,092
  • 2
  • 17
  • 28
0

Using dynamic keyword does the job

dynamic T;
switch (xnode.Type)
{
case "text":
T = new TextBox();
T.Text = "Enter your name";

Grid.SetColumn(T, 1);
Grid.SetRow(T, row);


break;
}

But I am not sure logically and overhead issues.

Alex
  • 715
  • 5
  • 14
0

So based on your current function:

public [I don't know the type] getObjectClass(string type) {

The type will have to be something more generic like Control or Object, because you don't know the specific return type. If you are going to return multiple different types likes (Label, and TextBox), you have to return a parent class which they both inherit from.

This gets a little trickier

 var obj = getObjectClass("label").Content = "I am new label!..";

as your base class (the return type) needs to have the Content property associated with it to be able access the property without casting. The easiest way around (although not my favorite) is to cast it ((Label) getObjectClass("label")).Content. This doesn't give you any compile time assurances though that the object you are returning actually has this property.

Personally I would write the method something like

public T getObjectClass<T> () where T: new() where T : Control {
     return new T();
}

This way you can specify what you want to return and the generic automatically makes it the correct type. You also don't run into the problem of doing something like "lable" when you pass it in as a string and have it fail at runtime.

kemiller2002
  • 113,795
  • 27
  • 197
  • 251