In some obscure way a derived class which doesn't add new functionality (yet) behaves different from it's base class. The derived class:
public class MyCheckButton : CheckButton
{
public MyCheckButton(string label) : base(label)
{
}
}
MyCheckButton inherits from a (GTK#, part of the Mono project) CheckButton. However in the following code snippet they behave differently:
var button1 = new CheckButton("_foo");
var button2 = new MyCheckButton("_foo");
// code omitted
The underscore in the label makes sure that the label gets a mnemonic. For button1 this works in my testcode: I get "foo" where the f is underlined. However for button2 this fails. I just get "_foo" as a label in my dialog.
Can anyone explain how the derived class in this example could behave differently or is there some magic going on behind the screen that maybe checks the type of the actual class?
[I]s there some magic going on behind the screen that maybe checks the
type of the actual class?
Actually, there is:
public CheckButton(string label) : base(IntPtr.Zero)
{
if (base.GetType() != typeof(CheckButton))
{
ArrayList arrayList = new ArrayList();
ArrayList arrayList2 = new ArrayList();
arrayList2.Add("label");
arrayList.Add(new Value(label));
this.CreateNativeObject((string[])arrayList2.ToArray(typeof(string)), (Value[])arrayList.ToArray(typeof(Value)));
}
else
{
IntPtr intPtr = Marshaller.StringToPtrGStrdup(label);
this.Raw = CheckButton.gtk_check_button_new_with_mnemonic(intPtr);
Marshaller.Free(intPtr);
}
}
It looks like your subclass will be going the former route. Not sure why that would mess up the mnemonic, though; the latter method is a P/Invoke on the native gtk library. It's possible that wrapping label in a Value object is mucking up the mnemonic stuff.
Let that be a lesson (to the GTK# designers): don't violate the Liskov Substitution Principle. It's confusing!
Here's why, look at the source for the CheckButton ctor:
public CheckMenuItem (string label) : base (IntPtr.Zero)
{
if (GetType() != typeof (CheckMenuItem)) {
CreateNativeObject (new string [0], new GLib.Value [0]);
AccelLabel al = new AccelLabel ("");
al.TextWithMnemonic = label;
al.SetAlignment (0.0f, 0.5f);
Add (al);
al.AccelWidget = this;
return;
}
IntPtr native = GLib.Marshaller.StringToPtrGStrdup (label);
Raw = gtk_check_menu_item_new_with_mnemonic (native);
GLib.Marshaller.Free (native);
}
Derived types do not follow the same code path as CheckButton in the .ctor
Related
Sorry for my verry badly written title, I'm a beginner programmer and I just started on a c# winforms app. In one function I create an object of some type and then in other functions I iterate through a list of that type of objects, however I'm switching the type of control I'm using and when I do, I have to change the type declaration of my object in over twenty places. Is there a way to create a variable that holds that type and than define all my objects off that variable so I only have to specify the type once and then change that variable. Because I'm using winforms controls as my class types all the functions I call are all then same no matter what type my objects are, so all I need to do is change the type declaration and that's it, sorry if this is a stupid question and any help would be appreciated.
Here is a snippet of my code for context:
private void function1(object sender, EventArgs e) //not my actual function because the real function has lots of other unrelated code
{
ListView PlaceType = new ListView(); // these ListView types i would like to replace with a placeholder if possible
ListView listview = new ListView();
int count2 = autolayoutGroups.Controls.OfType<ListView>().ToList().Count();
listview.Size = new System.Drawing.Size(150, 100);
listview.BackColor = normalColor;
listview.BorderStyle = BorderStyle.Fixed3D;
listview.ForeColor = System.Drawing.Color.Black;
listview.Name = "Group" + count2;
listview.MouseDown += Select;
}
private void function2(object sender, EventArgs e)
{
List<ListView> list_of_groups = autolayoutGroups.Controls.OfType<ListView>().ToList(); // a place where I need some type of placeholder
foreach (ListView l in list_of_groups)
{
// do something here
}
}
private void function3(object sender, EventArgs e) // I have several functions like this
//and if I change the control I'm using I have to change the types in every function
{
List<ListView> list_of_groups = autolayoutGroups.Controls.OfType<ListView>().ToList(); // a place where I need some type of placeholder
foreach (ListView l in list_of_groups)
{
// do something here
}
}
If I understand your problem correctly, you currently have some code where you use a ListView, and you want the same code, but instead of ListView you want some other class, for instance a DataGridView, or a ComboBox. Of course this other class must also have the methods that you used on the ListView.
In C# this concept is called a generic. You have generic classes and generic methods.
You define the generic by typing an identifier instead of the part that you want to replace with another type.
In your case: you want to replace ListView by DataGridView. In function1 you create a ListView, and set some properties. First we'll put this creation in a separate method, you will have something like this:
private ListView CreateListView()
{
ListView listview = new ListView();
int count2 = autolayoutGroups.Controls.OfType<ListView>().Count();
listview.Size = new System.Drawing.Size(150, 100);
listview.BackColor = normalColor;
listview.BorderStyle = BorderStyle.Fixed3D;
listview.ForeColor = System.Drawing.Color.Black;
listview.Name = "Group" + count2;
listview.MouseDown += Select;
return listView;
}
private void function1(object sender, EventArgs e)
{
ListView createdListView = this.CreateListView();
// TODO: do something with the created ListView
}
(Small optimization, out of scope of the question): to calculate count2, don't create a List of all ListViews, and then Count them; use Count() on the IEnumerable<ListView>.
To change CreateListView such that it can create anything of type TMyType, define the generic method like this:
private TMyType Create<TMyType>()
{
TMyType createdObject = new TMyType();
int count2 = autolayoutGroups.Controls
.OfType<TMyType>()
.Count();
createdObject.Size = new System.Drawing.Size(150, 100);
createdObject.BackColor = normalColor;
createdObject.BorderStyle = BorderStyle.Fixed3D;
createdObject.ForeColor = System.Drawing.Color.Black;
createdObject.Name = "Group" + count2;
createdObject.MouseDown += Select;
return createdObject ;
}
So all I did was, that whenever I save ListView, I replaced it with TMyType, the type that should be created.
Usage:
ListView createdListView = this.Create<ListView>();
DataGridView createdDataGridView = this.Create<DataGridView>();
ComboBox createdComboBox = this.Create<ComboBox>();
There is only one problem. You'll have to tell the compiler that TMyType has a default constructor (you want to do new TMyControl()), and that is has methods like Size, BackColor, ForeColor, etc.
If TMyType would be a class derived from Control, then you would be certain that it has the desired constructor and knows all methods that you need to use.
To say that a generic type is derived from a certain type, you use the following structure:
private TMyType Create<TMyType>() where TMyType: Control
{
// because you are certain the TMyType is derived from Control
// you can use all methods of class Control
}
This answers your question: create a generic method
Some other things about generics
Another example: If you want to inform the compiler that the generic type implements IComparable:
private T Process<T>(T input) where T: IComparable {...}
Or multiple:
private T Process<T>(T input) where T: IComparable, IEquatable {...}
And finally if you want to require that the generic type has a default constructor:
private T Process<T> () where T: new
It's not really clear what the goal is but I suppose you can make a property that returns your commonly used list:
private List<ListView> AutolayoutGroupControls =>
autolayoutGroups.Controls.OfType<ListView>().ToList()
Then you can
foreach(var lv in AutolayoutGroupControls)}
...
}
But it doesn't offer much; if you change that prop to return something else you still have a stack of changes to make. If your loops always do the same thing put it into a method and call it from N event handlers
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!..";
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.
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.
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;
}
}
}
}
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);
}
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.
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.
See the code below (C#):
Control button = new Button(100, 200, "Click Me!");
Control textBlock = new TextBlock(20, 20, "Hello World!");
List<Control> controls = new List<Control>();
controls.Add(button);
controls.Add(textBlock);
foreach (Control ctrl in controls)
{
ctrl.DrawMe(); //The objects will behave polymorphically, because they derive from
//a shared base class.
}
Control is an abstract class that I created myself. If I change Control in the declaration to their equivalent derived classes (like you see below) I get the exact same functionality. Why is that? Is there any difference when making an assignment to an abstract base class instead of its derived class?
Button button = new Button(100, 200, "Click Me!");
TextBlock textBlock = new TextBlock(20, 20, "Hello World!");
When your Button class has a property called i.e. ButtonImage, but your Control class doesn't have, you wont be able to access it when numerate through a control List.
Though, your object will be kind of "downgraded" (not practically) when saving it as a Control.
However, what exactly is the difference, that is, if there is any.
Well, this doesn't makes any difference when you're calling a virtual and overridden method.
Main difference is when you shadow a method.
Let's consider the following
class Control
{
public void DrawMe()
{ }
}
class Button
{
public new void DrawMe()
{ }
}
class TextBlock
{
public new void DrawMe()
{ }
}
foreach (Control ctrl in controls)
{
ctrl.DrawMe();//this will always call Control's version of DrawMe
}
Where as this code calls DrawMe of corresponding classes
Button button = new Button(100, 200, "Click Me!");
TextBlock textBlock = new TextBlock(20, 20, "Hello World!");
button.DrawMe();//calls button's drawme and textblock will calls its version
As pointed in comments I'll recommend you to take a look at polymorphism in detail.
Basically, I want to make bunch of Shapes and make them animated. So I came up with following custom class:
public class FunkyShape : DependencyObject
{
public double Animator
{
get { return (double)GetValue(AnimatorProperty); }
set { SetValue(AnimatorProperty, value); }
}
public static readonly DependencyProperty AnimatorProperty =
DependencyProperty.Register("Animator", typeof(double), typeof(FunkyShape),
new PropertyMetadata(0, new PropertyChangedCallback(Animator_Changed)));
private static void Animator_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
double delta = (double)e.NewValue - (double)e.OldValue;
((FunkyShape)d).ProcessDelta((double)e.NewValue, delta);
}
private void ProcessDelta(double val, double delta)
{
Holder.Width = val;
Holder.Height = val;
// Keep shape centered
HolderPosition.X = delta / 2;
HolderPosition.Y = delta / 2;
}
private Shape Holder;
public TranslateTransform HolderPosition
{
get { return (TranslateTransform)Holder.RenderTransform; }
}
public FunkyShape(Canvas playground, Shape shapeToInit)
{
Holder = shapeToInit;
Holder.Width = 10;
Holder.Height = 10;
Holder.Fill = new SolidColorBrush(Colors.Blue);
Holder.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center;
Holder.RenderTransform = new TranslateTransform()
{
X = 500,
Y = 500
};
Holder.RenderTransformOrigin = new Point(0.5, 0.5);
// init done
playground.Children.Add(Holder);
Animate();
}
public void Animate()
{
DoubleAnimation g1 = GrowAnimation();
Storyboard sb = new Storyboard();
Storyboard.SetTarget(g1, this);
// CAN'T FIND ANIMATOR PROPERTY
Storyboard.SetTargetProperty(g1, "Animator");
sb.Children.Add(g1);
sb.Begin(); // THROWS EXCEPTION
}
private static DoubleAnimation GrowAnimation()
{
DoubleAnimation growAnimation = new DoubleAnimation();
growAnimation.Duration = TimeSpan.FromMilliseconds(3000);
growAnimation.From = 0;
growAnimation.To = 100;
growAnimation.AutoReverse = true;
growAnimation.EnableDependentAnimation = true;
growAnimation.RepeatBehavior = new RepeatBehavior(5);
return growAnimation;
}
}
However, when I try making an instance of the class and adding it to the canvas, I get Exception - Storyboard.Being() throws it and tells me that it can't find Animator property.
So - what am I doing wrong?
EDIT: After 3 code changes - it is still not working; I get "Cannot resolve TargetProperty Animator on specified object" error. So if somebody knows the answer - please help out by modifying the code. Thanks!
EDIT: OK, after 24 hours of banging head against the wall there is some progress - if I add shape through XAML it animates, but if I add it through code behind (Canvas.Children.Add), it doesn't work. Let me see if I can figure out why.
OK,
I've found the workaround for what is obviously a bug within the framework (although I'm sure some MS employee will post response and say it's a feature/it-is-by-design). Several things need to be done:
Add default/parameter-less constructor
Change base class of FunkyShape to UserControl.
Open up XAML view of the Page class where you want to add shapes
Add one instance of FunkyShape as a child within the Canvas XAML (<tm:FunkyShape /> for example). IT WON'T WORK WITHOUT THIS.
Make an instance of FunkyShape in code-behind, add it to canvas, start animation and enjoy seeing it works
Switch to less buggy technology.
In Windows 8 you cannot animate custom properties without also setting the enabledependentanimation property to true. This is because non-deterministic animations are disabled by default.
Reference: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.animation.pointanimation.enabledependentanimation.aspx
Yes, you must define this property as a dependency property, not just a regular CLR property. This involves quite a bit of simple boiler plate code. See thus blog post for a complete example:
http://timheuer.com/blog/archive/2012/03/07/creating-custom-controls-for-metro-style-apps.aspx
OK, I had this problem too, but I didn't want to include a public parameterless constructor in my class, so I found another way.
Basically, the issue is that WinRT is a native platform, and it can't do reflection on .NET code. That's why the build process for WinRT apps generates metadata about the types used in XAML (you can find the relevant code in obj/(Debug|Release)/XamlTypeInfo.g.cs).
If a type is never used in XAML, no metadata about this type is generated, which means (among other things) that you can't animate the properties of the type.
If you're writing a class library, you can just include a XAML resource dictionary and declare a dummy instance of the type; it will cause metadata to be generated. However, it requires that the type has a public parameterless constructor, which might not be desirable.
So there is another solution: provide the metadata yourself. There are a several interfaces to implement, and they have many members, so it can be quite tedious to do manually. Fortunately, you don't have to! Here's what you can do:
add a public parameterless constructor to the class (temporarily)
create a XAML ResourceDictionary and declare an instance of the class in it (as described above)
copy the XamlTypeInfo.g.cs file into your project (I renamed it to XamlTypeInfo.cs)
replace the call to the constructor with throw new NotImplementedException()
delete the ResourceDictionary file
remove the public parameterless constructor
And you're done, the animation now works properly.
The process is still quite tedious, so it would be nice to have a tool to do the work for us...
EDIT: much easier solution: apply the [Bindable] attribute to the class. It makes the metadata generator take the type into account even if it's not used in XAML. (ignore the fact that the doc says it's for C++ types; it works just fine on C# classes as well)
I'm writing some user controls for the first time and I'm wondering if there's a way I can clean up some of my code. (If you'd like more background on what I'm working on, see this question.)
I have a BaseControl class that, basically, parses some XML data and then, depending on what is contained in that data, calls the appropriate UserControl and sends the data on its way. Here's an example:
public partial class BaseControl : User Control
{
protected void Page_Load(object sender, EventArgs e)
{
... //code that parses the data
var renewalDef = effort.Attributes["renewal_def"].Value;
var effortNumber = effort.Attributes["renewal_effort_number"].Value;
if (effortNumber == "1")
{
var effortControl = (NAVLEffort1) Page.LoadControl("~/NAVLSeriesControls/NAVLEffort1.ascx");
effortControl.transactionData = transaction; //'transaction' is a Hashtable object
HtmlContent.Controls.Add(effortControl); //'HtmlContent' is a PlaceHolder control on BaseControl.ascx page
}
if (effortNumber == "2")
{
var effortControl = (NAVLEffort2) Page.LoadControl("~/NAVLSeriesControls/NAVLEffort2.ascx");
effortControl.transactionData = transaction; //'transaction' is a Hashtable object
HtmlContent.Controls.Add(effortControl); //'HtmlContent' is a PlaceHolder control on BaseControl.ascx page
}
if (effortNumber == "3")
{
var effortControl = (NAVLEffort3) Page.LoadControl("~/NAVLSeriesControls/NAVLEffort3.ascx");
effortControl.transactionData = transaction; //'transaction' is a Hashtable object
HtmlContent.Controls.Add(effortControl); //'HtmlContent' is a PlaceHolder control on BaseControl.ascx page
}
// and so on...
}
}
This isn't the actual code I've written, it's just an example of where I could be headed. What I'd like to do is something more like this:
...
var effortControlFileString = string.Format("~/NAVLSeriesControls/{0}Effort{1}.ascx", renewalDef, effortNumber);
var effortControl = (renewalDef + "Effort" + effortNumber) Page.LoadControl(effortControlFileString);
effortControl.transactionData = transaction;
HtmlContent.Controls.Add(effortControl)
...
Any ideas how I can clean this mess up?
Interface
You could have all controls implement a common interface and cast to that.
public interface IMyInterface
{
object TransactionData
{
get;
set;
}
}
Control effortControl = Page.LoadControl(path);
HtmlContent.Controls.Add(effortControl);
IMyInterface obj = (IMyInterface)effortControl;
obj.TransactionData = transaction;
See this working example in an online IDE.
Base Class
You could also use an abstract base class and cast to that type with the same results. You will need to use a base class which inherits from UserControl. This would avoid having two object references (as in my example above) because it can be cast to UserControl.
The example above becomes:
MyCustomControlType c = (MyCustomControlType)Page.LoadControl(path);
HtmlContent.Controls.Add(c);
c.TransactionData = transaction;
If the logic for each control type is different, then you will probably need to cast to each specific type (basically a big if/else block) and deal with each control individually. In other words, if you need to perform different actions based on the type of the control, you will need logic that is type-aware.
For completeness sake I will mention that you could also use the DLR but I would suggest against it. You would be giving up compile-time type safety and performance to reduce a little code.
you can create an interface and add your control to html page.
ex:
private Control _contentControl;
_contentControl = Page.LoadControl("~/Administration/Projects/UserControls/" + controlName);
((IEditProjectControl)_contentControl).ProjectId = ProjectId;
plhContent.Controls.Clear();
plhContent.Controls.Add( _contentControl );
_contentControl.ID = "ctlContent";
Image2.Visible = ((IEditProjectControl)_contentControl).ShowSaveButton;
SaveButton.Visible = ((IEditProjectControl)_contentControl).ShowSaveButton;
((IEditProjectControl)_contentControl).Initialize();