Not sure I got the vernacular right, so hopefully a code example will clarify.
public class myClassObj
{
public string aProperty {get;}
}
public class anotherClassObj
{
public string bProperty {get;}
}
Then I have a static extension method:
public static anotherClassObj getOtherObj(this myClassObj obj)
{
anotherClassObj returnObj = new anotherClassObj();
return returnObj;
}
Then in XAML:
<DataTemplate>
<TextBlock Text="{Binding aProperty}"/>
<TextBlock Text="{Binding getOtherObj().bProperty}"/>
</DataTemplate>
Overlooking the obvious syntax errors and lack of constructors and such, is the idea of something like this possible?
Basically I want to extend the binding object to expose more properties than are part of the actual object being bound.
is the idea of something like this possible?
The idea? Yes. The exact mechanism you're asking for? No.
WPF's XAML binding syntax requires a property path on the source object. An extension method is a compile-time construct. At run-time, it's just a call to a static method in a completely different class from the one being passed to the method. The binding system has no practical way to efficiently look up extension methods.
IMHO, the best alternative would be to use the "decorator pattern" or similar technique to wrap your original model object in a model object that exposes the extension method as a property, and then bind to the decorated object. E.g.:
public class myClassObj
{
public string aProperty {get;}
}
public class DecoratedClassObj : myClassObj
{
public anotherClassObj OtherObj { get { return this.getOtherObj(); } }
}
then…
<DataTemplate>
<TextBlock Text="{Binding aProperty}"/>
<TextBlock Text="{Binding OtherObj}"/>
</DataTemplate>
Naturally, your model object would have to be instantiated as DecoratedClassObj instead of myClassObj, and that instance used as the model object (wherever your template is being used). The above shows decorating via inheritance. An alternative is to use composition instead; in that approach, you'd have to replicate in the decorator object all of the properties (and other features) you need from the decorated object.
Note that by decorating, you then also have the option of implementing INotifyPropertyChanged, to allow the bound state to be updated if in fact the underlying data that affects the return value of the getOtherObj() method changes. It even allows property-setter access to that underlying data, should there be a need to modify it through the model object.
Other options include:
Write your own XAML markup extension, to handle the extension-method syntax you want to use. This will give you similar syntax in the XAML (but using your own extension rather than the {Binding} extension). You'll probably want in this approach to still create a general-purpose proxy object that can be configured similar to the decorator object suggested above, so that it can participate in binding to the actual target property (i.e. Text).
Write an attached property. In this case, the XAML will not look like what you have; instead of binding to the Text property, you'd have some attached property like MyAttachedPropertyClass.MyAttachedProperty="MyStaticClass.getOtherObj", where your attached property sets the Text property by finding (presumably by reflection) and calling the getOtherObj() extension method. You could make the attached property value as complicated as you like/need to, such as making it a parseable string value containing the target property name as well as the extension method class and name, or even making it a user-defined object that stores such details. For that matter, instead of just setting the target property once, you could have a proxy object similar to that as suggested in the previous alternative.
Personally, I much prefer the idea of simply decorating the original model object. It's a lot easier, and IMHO is much easier to understand in its implementation. I merely offer these other options for completeness, to give you an idea of what would be needed to avoid having to write an explicit decorator. :)
I don't know if this is possible, and how it would be possible. I basicly want to use this later that like:
//setting a single item as known.
label1.BackColor=Color.FromARGB(255,255,255);
/*setting multiple items in something like a container (wanted, not yet possible)*/
sContainer.BackColor=Color.FromARGB(255,255,255);
//and that's how it works recently with my class...
sContainer.SetValues("BackColor",Color.FromARGB(255,255,255));
The container will have to use Generics and Reflection I guess.
The container class should "copy" all Set-able properties of the T-Class (here Control) into itself. So if I'm using SetContainer<Control> I can set all backcolor values in my container by sContainer1.BackColor=... .
My code until know looks that like:
public class SetContainer<T>:IList<T>
{
/*I've implemented all methods of IList by using the elements-List*/
private List<T> elements;
public void SetValues(string propname,object value)
{
FieldInfo f=typeof(T).GetField(propname);
elements.ForEach(x=>f.SetField(x,value);
}
}
I'm sorry that I don't know how to describe this well understandable.
By using this a modified version of this, you can add "link" the properties of the generic class to the container class.
This makes it possible to apply one value to a whole collection of values.
Thank you #Sagi !
So I have a class; lets use the ScrollViewer class as an example. It has a dependency property called Content which accepts anything of type System.Object, great!
Let's say I derive a class from ScrollViewer, lets call it ZoomScrollViewer, it adds some basic zooming and panning using the mouse with a keyboard press. It also adds a dependency property of it's own, AutoscaleContent.
Now, I want to be able to put a ZoomScrollViewer into a UI window, but I only want it to accept a Canvas as it's content. Naturally, I go about creating a ZoomScrollViewer<T> class.
However, how can I change the Content property so that only accepts elements of type <T>? Can I override the dependency property? I got a little confused and tried:
public new T Content
{
get { return (T)base.Content; }
set { base.Content = value; }
}
But of course this makes it no longer a dependency property, so all the XAML code fails when I set up the bindings.
Edit: It should also be noted that I've taken a look at using:
ZoomScrollViewer.ContentProperty.OverrideMetadata(typeof(ZoomScrollControl2<T>), new PropertyMetadata(...?));
To see if I could do anything using that, but it seems you can only override the default value, unless I'm missing something?
Update: I've now tried using the following:
public class ZoomScrollControl2<T> : ZoomScrollViewer where T : FrameworkElement
{
static ZoomScrollControl2()
{
ContentProperty.OverrideMetadata(typeof(ZoomScrollControl2<T>), new FrameworkPropertyMetadata(typeof(ZoomScrollControl2<T>)));
}
}
public class CanvasZoomControl : ZoomScrollControl2<Canvas>
{
}
Which I thought would work, but it still seems to accept a Content of any type.
Update: In short I'm not sure if what I want to do is even possible, so I've marked the discussion as the answer, even though it isn't an answer per-se.
I suggest to try that approach as it suggested by this MSDN article.
It should override the referal type, so you can refer to it using derived type.
Dependency Property visibility is not made esplicit in .NET Framework for derived types, as searching right property among the types tree has a cost in terms of performance, and considering that we use DP on UI binding, it can lead to non desirable performance issues.
So we have a C# WinForms project with a Form that contains a bazillion UserControls. Each UserControl naturally exposes all the UserControl methods, properties, etc. in addition to its own specific members.
I've been thinking that one way to reduce the complexity of dealing with these UserControls is to access them through an interface. So instead of drag-and-drop to put the UserControl on the form, something like this in the constructor:
public class MyGiantForm
{
ICustomerName cName;
public MyForm()
{
InitializeComponent();
var uc = new SomeCustomerNameUserControl();
this.Controls.Add(uc);
cName = uc;
}
}
SomeCustomerNameUserControl implements ICustomerName, naturally, and ICustomerName contains the specific properties I really care about (say, FirstName and LastName). In this way I can refer to the UserControl through the cName member and, instead of being bowled over by all the UserControl members, I get only those in ICustomerName.
All well and good, but the problem is that if I do it this way, I can't see SomeCustomerNameUserControl in the Designer. Does anybody know I way I can do this but still see the UserControl on the form's design surface?
EDIT: One way to do this, which isn't overly complicated, is to put the controls on a base form. By default (in C#) the control members are private. Then I create a property for each control exposing it through the interface.
However, I'd be interested in some other way to do this, even if it's more complex. There seems to be some way to do it with IDesignerHost, but I can't find any applicable examples.
If SomeCustomerNameUserControl is defined like this:
class SomeCustomerNameUserControl : UserControl, ICustomerName
{
}
You can still drop this control in the designer (which creates someCustomerNameUserControl1) and do this whenever you need to:
ICustomerName cName = someCustomerNameUserControl1;
Maybe I'm missing something, but I think it's that simple.
There's a way to accomplish what you want -- hiding the members you don't want to see -- but make it apply automatically, without requiring others' cooperation in terms of them using a custom interface. You can do it by reintroducing all the members you don't want to see, and tagging them with attributes.
This is what Windows Forms does when, for example, a base-class property doesn't mean anything for a particular descendant. For example, Control has a Text property, but a Text property is meaningless on, say, a TabControl. So TabControl overrides the Text property, and adds attributes to its override saying "By the way, don't show my Text property in the Property Grid or in Intellisense." The property still exists, but since you never see it, it doesn't get in your way.
If you add an [EditorBrowsable(EditorBrowsableState.Never)] attribute to a member (property or method), then Intellisense will no longer show that member in its code-completion lists. If I'm understanding your question correctly, this is the big thing you're trying to achieve: make it hard for application code to use the member by accident.
For properties, you probably also want to add [Browsable(false)] to hide the property from the Property Grid, and [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] to prevent the designer from writing the property's value to the .designer.cs file.
These will make it very difficult to accidentally use the method/property. They're still not a guarantee, though. If you do need a guarantee, then throw in an [Obsolete] attribute too, and build with "Treat warnings as errors" -- then you're taken care of.
If the base member is virtual, you probably want to override it, and have your override simply call base. Don't throw an exception, since the overridden member will probably be called by the base class during the normal course of events. On the other hand, if the base member isn't virtual, then you want to use "new" instead of "override", and you can decide whether your implementation should call base, or just throw an exception -- nobody should be using your reintroduced member anyway, so it shouldn't matter.
public class Widget : UserControl
{
// The Text property is virtual in the base Control class.
// Override and call base.
[EditorBrowsable(EditorBrowsableState.Never)]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Obsolete("The Text property does not apply to the Widget class.")]
public override string Text
{
get { return base.Text; }
set { base.Text = value; }
}
// The CanFocus property is non-virtual in the base Control class.
// Reintroduce with new, and throw if anyone dares to call it.
[EditorBrowsable(EditorBrowsableState.Never)]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Obsolete("The CanFocus property does not apply to the Widget class.")]
public new bool CanFocus
{
get { throw new NotSupportedException(); }
}
// The Hide method is non-virtual in the base Control class.
// Note that Browsable and DesignerSerializationVisibility are
// not needed for methods, only properties.
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("The Hide method does not apply to the Widget class.")]
public new void Hide()
{
throw new NotSupportedException();
}
}
Yes, this is a fair bit of work, but you only have to do it once... per member, per class... umm, yeah. But if those base-class members really don't apply to your class, and having them there will cause confusion, then it may be worth going to the effort.
'I want ICustomerName to be the only option for accessing the UserControl's variable. The idea is that a developer doesn't have to "just remember" to cast it.'
The problem you are having is that you have two completely divergent uses for your form and the controls it hosts. There is no trick built into Visual Studio or winforms which solves this neatly for you. It may be possible, but there is a much cleaner and object oriented way to separate the two methods of interacting with the controls.
If you want to hide the fact that these objects inherit from UserControl, and just want to treat them as IDoSomeThingYouShouldDealWith, you need to separate the logic that deals with the presentation concerns (designer + UI logic) from your business logic.
Your form class, should rightly deal with the controls as UserControls, docking, anchoring etc etc, nothing special here. You should put all the logic that needs to deal with ICustomerName.FirstName = etc into a completely separate class. This class doesn't care or know about fonts and layout, it just knows that there is another instance that can present a customer name; or a DateTime as a 'date of birth choosing' control properly etc.
This is a really lame example, but I have to go right now. You should be able to get the idea covered here in more detail:
public interface ICustomerName
{
void ShowName(string theName);
}
public partial class Form1 : Form, ICustomerName
{
public Form1()
{
InitializeComponent();
}
#region ICustomerName Members
public void ShowName(string theName)
{
//Gets all controls that show customer names and sets the Text propert
//totheName
}
#endregion
}
//developers program logic into this class
public class Form1Controller
{
public Form1Controller(ICustomerName theForm) //only sees ICustomerName methods
{
//Look, i can't even see the Form object from here
theForm.ShowName("Amazing Name");
}
}
After you add the UserControl using the designer, you can set GenerateMember to false in the Properties window to suppress generation of a member.
You could then use some other technique in the constructor to assign your cName reference, e.g.:
foreach(Control control in this.Controls)
{
cName = control as ICustomerName;
if (cName != null) break;
}
cName would then be the only reference to the UserControl.
You could write an extension method that would allow you to return any controls on the form that implement an interface.
public static class FormExtensions
{
public static IDictionary<string, T> GetControlsOf<T>(this Form form)
where T: class
{
var result = new Dictionary<string, T>();
foreach (var control in form.Controls)
{
if ((control as T) != null)
result.Add((control as T).Tag, control as T);
}
return result;
}
}
Then in your form you could call it whereever you want by:
this.GetControlsOf<ICustomerName>()["NameOfControlHere"];
In the event that it returns more than one user control you would need to handle that some how, perhaps by adding Tag property to the interface to uniquely keep track of each user control or something, like so
public partial class UserControl1 : UserControl, ICustomerName
{
public string Tag { get { return this.Name; } }
}
You can then drag and drop the user controls onto your form from the designer. Tag will always return the name of your control, which will allow you to directly access the control through the IDictionary's interface. You're developers could put whatever unique identifier they want in the name of the control, and it would carry through to the interface.
Also, it should be noted that this approach will ALSO allow you to use this on ALL forms in your solution.
The only other thing you would need to do is set your GenerateMember to false.
you could as well do as Bob said but assign all your member variables in the constructor, then you have it in one place.
It almost seems like you want to implement a mediator pattern. Instead of having to deal with each of the bazillion UserControls directly, you'd interact with them through the mediator. Each mediator would define the slim interface you want to see from each control. This would reduce the overall complexity by making your design more explicit and concise. For example, you wouldn't need the 20 properties and 50 methods available on one of your controls. Instead you'd deal with the mediator for that control which defines the 2 properties and 5 methods you really care about. Everything would still show up in the designer, but other parts of your app would not be interacting with those controls -- they'd interact with the mediators.
One of the big advantages to this approach is it greatly simplifies your maintenance. If you decide the MyCrappyUserControl needs to be rewritten because the implementation is bad, you just need to update the mediator class for that control. All the other classes that interact with the control do so through the mediator and would be unchanged.
Ultimately it comes down to discipline: you and your team need to be disciplined enough to use the mediators/interfaces/whatever instead of the directly hitting the controls. Institute an over the shoulder code review by a leader programmer if your team is on the low end of the discipline scale.
Assume that MyUserControl is defined like this:
class MyUserControl : UserControl, IMyInterface
{
// ...
}
Then in your form, you should have something like this:
public class MyForm : Form
{
IMyInterface cName;
public MyForm()
{
InitializeComponent();
cName = new MyUserControl();
Controls.Add((UserControl)cName);
}
}
This way, cName is the only way to access this instance of our usercontrol.
I have read a bit about Design-Time Attributes for Components. There I found an attribute called CategoryAttribute. On that page it says that
The CategoryAttribute class defines the following common categories:
And then lists up a number of common categories. One of them are for example Appearance. I thought, brilliant! Then I can use [Category.Appearance] instead of [Category("Appearance")]! But apparently I couldn't? Tried to write it, but Intellisense wouldn't pick it up and it wouldn't compile. Am I missing something here? Was it maybe not this those properties were for? If not, what are they for? If they are, how do I use them?
And yes, I do have the correct using to have access to the CategoryAttribute, cause [Category("Whatever")] do work. I'm just wondering how I use those defined common categories.
As you can see on MSDN it's only a getter property, not a setter.
public static CategoryAttribute Appearance { get; }
In fact, here's what the code looks like using Reflector:
public static CategoryAttribute Appearance
{
get
{
if (appearance == null)
{
appearance = new CategoryAttribute("Appearance");
}
return appearance;
}
}
So it doesn't do a heck of a lot.
The only use I can see for it, is something like this:
foreach (CategoryAttribute attrib in prop.GetCustomAttributes(typeof(CategoryAttribute), false))
{
bool result = attrib.Equals(CategoryAttribute.Appearance);
}
Basically, when using reflection to look at the class, you can easily check which category this belongs to without having to do a String comparison. But you can't use it in the manner you're trying to unfortunately.
The static property is accessed via CategoryAttribute.Appearance. But the attribute system does not allow you to invoke code in an attribute declaration and I guess that is why it wont compile for you. You will probably have to settle for [Category("Appearance")].
Starting from C# 6 there is finally a better alternative: [Category(nameof(CategoryAttribute.Appearance))].