How to add dependency property to FrameworkElement driven classes in WPF? - c#

I need key and Value property in all controls which are drives from FrameworkElement class in wpf. key and value property are needed for some internal purpose. I know we have a Tag property which is used for saving custom data. I need two more such properties.
Any suggestions?

You don't need to create another property, as you know Tag property will allow you to save custom data.
This is example of how you can store data in the Tag.
public class Customdata
{
public int Id { get; set; }
public int value { get; set; }
}
private void setDataInTag(FrameworkElement obj, Customdata objCustomData)
{
obj.Tag = objCustomData;
}
private Customdata GetValueFromElement(FrameworkElement obj)
{
Customdata objCustomData = new Customdata();
if (obj.Tag!=null && obj.Tag.GetType() == typeof(Customdata))
{
objCustomData = (Customdata)obj.Tag;
return objCustomData;
}
}
I think it is simple now :)

You should create your own attached property.
Just create new class, write propa codesnippet, press tab, tab :)
in xaml you can then set and get the property on any dependency object, just like you can use Grid.Column or Canvas.Left on any element.

Related

How to make a class that waits for instance to be created to instantiate variables?

I am trying to create a class with some subclasses for a color management system in my application.
I need to create a "Colorset" object that has some "Category" objects inside of it. The problem is I need to access members of one of the categories from another category.
Since I want to be able to set the values of the "Category" members when instantiating a new "Colorset", I can't make them static.
Here's an example of what I want to do.
public class Colorset
{
public General General { get; set; }
public Page Page { get; set; }
}
public class General
{
public Color Primary = Color.FromArgb("#399ed6");
public Color Secondary = Color.FromArgb("#fff");
public Color Text = Color.FromArgb("#000");
}
public class Page
{
public Color TitleBar = General.Primary; // General not static, cant access it
public Color TitleBarText = General.Secondary;
}
I want to set the TitleBar value to the value of "Primary" FROM THE COLORSET PARENT. I know a Page will always have a Colorset parent, and I want to access the value of Primary that has been set in the parent colorset.
This would be an example on how I want to instantiate a new Colorset:
Colorset = new()
{
General = new()
{
Primary = Color.FromArgb("#fff"),
Secondary = Color.FromArgb("#000")
}
Page = new()
{
TitleBar = Color.FromArgb("#123")
// Since TitleBarText not set it defaults to the value of "Secondary"
}
How can I achieve something like this?
Thanks in advance
create a constructor for Page that accepts a General parameter
public Page(General general)
{
TitleBarText = general.Secondary;
}
and pass in the reference when ColorSet creates Page
Page = new Page(this.General);

why we need accessor in autoimplemented property in c#?

I have some doubts on the auto-implemented property. Why do we first get, and then set the value?
What you've have posted is not an auto property.
Below is an example class that contains 1 auto property and a custom property similar to what you have done.
public class MyPropertyClass
{
public MyPropertyClass(bool affectLogic)
{
_affectLogic = affectLogic;
}
private readonly bool _affectLogic;
public string MyAutoProperty { get; set; }
private string _myPropertyWithLogic;
public string MyPropertyWithLogic
{
get
{
if (_affectLogic)
_myPropertyWithLogic = "Some value";
return _myPropertyWithLogic;
}
set
{
if (_affectLogic)
{
_myPropertyWithLogic = "Some value";
}
else
{
_myPropertyWithLogic = value;
}
}
}
}
The autoproperty "MyAutoProperty" provides a mechanism for simply getting and setting property values.
What you have posted in a standard property that allows you to perhaps manipulate or return the property value based upon certain conditions. In your post you are checking to see if the value posted in is null before setting.
If you do not need to access the property outside of the class then you do not need to have the get method. If you remove the get then you are creating a "WriteOnly" property which is bad practice.
Create a public method on the class that accepts the "Alert" value. If you dont need to access the property outside of the class then dont create a property at all.
public void SetMyProperty(string value)
{
_myPropertyWithLogic = value;
}

Make ComboBox accept only specific type

I currently have a ComboBox in my Windows Forms Application. In order to specify which values the ComboBox will contain, I set DataSource property of the ComboBox to some array so that ComboBox contains values from that array. I could also use Items.Add() to add new values to ComboBox. However, I want to make sure that ComboBox can be populated with objects of some specific type. So, if I have a class called X, then I want to make it so that only an array of type X can be used as a data source for the ComboBox. Right now, ComboBox accepts objects of type System.Object. How can I achieve it? Is there a property of ComboBox that I need to set to be equal to my data type's name? Or is there an event that will check whether an object added to my ComboBox is of the needed type and will throw an exception if not?
I was thinking of creating a new class as a subtype of ComboBox, and overriding the Add method of Items property so that Add checks whether its argument is of the needed type (not sure if and how I can do it). Even if I do that, there are still other ways to add new values into ComboBox (AddRange, CopyTo, etc.), so I think there should be a more elegant solution to this problem.
If you want to control the type of item that the ComboBox can contain, you could try creating a new class derived form ComboBox, but you'd run into the problem that it still has the ComboBox.ObjectCollection Items property which would still accept any type! And (unfortunately for your idea of overriding) the Add method isn't virtual.
The only practical solution that I could think of would be to abstract the ComboBox somehow. If this isn't shared code, I would recommend just creating a method that you would use to add items to the ComboBox. Something like:
// NOTE: All items that are added to comboBox1 need to be of type `SomeType`.
private void AddItemToComboBox(SomeType item)
{
comboBox1.Items.Add(item);
}
Any attempt to add a non-SomeType object to the ComboBox would be met with a compiler error. Unfortunately, there's no easy way to prevent someone from still adding a non-SomeType item to ComboBox.Items directly.
Again, if this isn't shared code, it shouldn't really be an issue.
You can hide Items property by your
own Items property of custom type which taking as parameter original ItemsCollection
Example class for testing
public class Order
{
public Int32 ID { get; set; }
public string Reference { get; set; }
public Order() { }
public Order(Int32 inID, string inReference)
{
this.ID = inID;
this.Reference = (inReference == null) ? string.Empty : inReference;
}
//Very important
//Because ComboBox using .ToString method for showing Items in the list
public override string ToString()
{
return this.Reference;
}
}
With next class I tried wrap ComboBox's items collection in own type.
Where adding items must be concrete type
Here you can add other methods/properties you need (Remove)
public class ComboBoxList<TCustomType>
{
private System.Windows.Forms.ComboBox.ObjectCollection _baseList;
public ComboBoxList(System.Windows.Forms.ComboBox.ObjectCollection baseItems)
{
_baseList = baseItems;
}
public TCustomType this[Int32 index]
{
get { return (TCustomType)_baseList[index]; }
set { _baseList[index] = value; }
}
public void Add(TCustomType item)
{
_baseList.Add(item);
}
public Int32 Count { get { return _baseList.Count; } }
}
Here custom combobox class derived from ComboBox
Added: generic type
public class ComboBoxCustomType<TCustomType> : System.Windows.Forms.ComboBox
{
//Hide base.Items property by our wrapping class
public new ComboBoxList<TCustomType> Items;
public ComboBoxCustomType() : base()
{
this.Items = new ComboBoxList<TCustomType>(base.Items);
}
public new TCustomType SelectedItem
{
get { return (TCustomType)base.SelectedItem; }
}
}
Next code used in the Form
private ComboBoxCustomType<Order> _cmbCustom;
//this method used in constructor of the Form
private void ComboBoxCustomType_Initialize()
{
_cmbCustom = new ComboBoxCustomType<Order>();
_cmbCustom.Location = new Point(100, 20);
_cmbCustom.Visible = true;
_cmbCustom.DropDownStyle = ComboBoxStyle.DropDownList;
_cmbCustom.Items.Add(new Order(0, " - nothing - "));
_cmbCustom.Items.Add(new Order(1, "One"));
_cmbCustom.Items.Add(new Order(2, "Three"));
_cmbCustom.Items.Add(new Order(3, "Four"));
_cmbCustom.SelectedIndex = 0;
this.Controls.Add(_cmbCustom);
}
Instead of overriding ComboBox (which wont work as stated in itsme86's answer) you could override usercontrol, add a combobox to this, and then only expose the elements that you wish to work with. Something similar to
public partial class MyComboBox<T> : UserControl where T: class
{
public MyComboBox()
{
InitializeComponent();
}
public void Add(T item)
{
comboBox1.Items.Add(item);
}
public IEnumerable<T> Items
{
get { return comboBox1.Items.Cast<T>(); }
}
}
Please note however that some pieces of automated software rely on access the the underlying controls however so this may cause some issues.
This approach never changes the Items of the combobox so they will still store as objects but when you access them, you are casting them to the correct type and only allowing them to be added of that type. You can create a new combobox via
var myCB = new MyComboBox<ItemClass>();

How should I set an image index of an ImageListBox item in a databinding scenario?

I have a Document object that looks like this:
public class Document
{
public Title { get; set; }
public Extension { get; set; }
public byte[] Data { get; set; }
}
The Extension is "pdf", "doc", "docx" and the like. This document is used for storing documents in a database (it's actually a DevExpress XPO object).
The problem I'm having is, I am binding a list of these objects to an imagelistbox, which has an associated image list of the icons to display for each file type. How can I set the image index on the imagelistbox item based on the Extension without storing the index in the domain object?
In WPF, I would have used the MVVM pattern to solve that issue : the XPO object wouldn't be directly used by the UI, instead a ViewModel object would expose the necessary properties so that they can easily be used in binding scenarios. MVVM is specific to WPF, but I believe the MVP pattern is very similar and can easily be used in Windows Forms. So, you could create a Presenter object which would act as an adapter between the UI and the XPO object :
public class DocumentPresenter
{
private Document _document;
public DocumentPresenter(Document document)
{
_document = document;
}
public string Title
{
get { return _document.Title; };
set { _document.Title = value; };
}
public string Extension
{
get { return _document.Extension; };
set { _document.Extension = value; };
}
public byte[] Data
{
get { return _document.Data; };
set { _document.Data = value; };
}
public int ImageIndex
{
get
{
// some logic to return the image index...
}
}
}
Now you just have to set the DataSource to a collection of DocumentPresenter objects, and set the ImageIndexMember to "ImageIndex"
Disclaimer : I never actually used the MVP pattern, only MVVM, so I might have got it wrong... anyway, you get the picture I guess ;)

How to handle properties with dynamic defaults

I often have a situation like this when creating simple data objects. I have a property called Label that should have a default based on the Name of the object. So if no label is set then the Name is used otherwise use the set Label. A simple example in C#
public class FooBat {
public string Name { get; set; }
public string Label {
get {
if (_label == null) return Name;
return _label;
}
set { _label = value; }
}
}
Now the problem is if you want to edit this object you can't just bind to the Label property or you will get the default value and it will look as if there is a value there when there really isn't. So what I end up doing is create another, read-only property that does the defaulting and I use that is all instances except for when the base object is being edited. This leads to many extra properties with weird names like LabelWithDefault. Another alternative I've tried is to make Label handle the defaulting and make a new property called RealLabel that is used for editing the base object. This is just as bad.
I've thought of moving the defaulting code somewhere else but I haven't found a good place for it in any "normal" model that does not replicate the defaulting code many times.
What I have started to do now is initialize the Label field when the Name field is set (and the Label field is not) and then treat the Label field as a normal field. This works but now the code for defaulting is tied to the wrong property. Why should the Name know that the Label field cares about it? So this is also not "right."
Does anyone have any better ways of handling this problem?
I think there is a little confusion about what I'm asking for. Basically I need two different views to the same object for two different uses. In the first is the editing of the object itself where I want unset fields to show as empty (unset). The second is for all other cases (including when the object is the value of a field of another object) where I want to show each field with its dynamically determined default. Just setting the default the first time doesn't no help because if the (in this case) Name field changes then the Label field must also change until the Label field is set.
The answers are getting closer but I still think that they are too targeted to the example I gave. I was trying to give a concrete example for expository purposes but in reality this is more of a best-practices issue. The example I gave was C# and for a string property but I have the same problem with most languages and systems that I use that have frameworks where the data access and data display are handled for you as well as for data types other than strings. Changing the object that is queried from the data source is possible but often tricky and knowing when to make the change (use a sublclass in this case but not in that one) is particularly difficult.
public class FooBat {
public string Name { get; set; }
public string Label {
get {
if (_label == null)
_label = Name;
return _label;
}
set { _label = value; }
}
}
Regarding your update:
You could subclass your object. The base-class would return null if the field has not been set and the sub-class would return your default value. Thus if you need to query if a value has been set, you would cast to the base-class.
Deleted previous answers/updates for brevity.
Update 2:
I would have to say the best way is to track whether the property has been set or not with an IsPropertySet bool. The Getter for the property would check that value to see if it should be returning its own value or the default value. And the setter for the property would set the IsPropertySet according to the set value (true if the value is not null, false if it is). The code that is using the class could then look at the IsPropertySet value to determine if it is receiving a set value or the default when it calls the Property's Getter.
public class FooBat {
public string Name { get; set; }
public bool IsLabelSet { get; set; }
public string Label {
get {
if (IsLabelSet)
return _label;
else
return Name;
}
set {
IsLabelSet = value != null;
_label = value;
}
}
}
I use a Nameable interface a lot (with getName()). Before I start, I'll suggest that you don't want to do this at all. It should be the domain of your display logic, not your domain objects. Usually it's the code consuming the FooBat that is able to make this decision in a better way than the object itself. That aside...
public interface Label{
string getLabel();
boolean isDefault(); //or isValued() or use instanceof expressions
}
public interface Nameable{
string getName();
}
public class FooBat implements Nameable {
public string Name { get; set; }
public Label Label {
get {
if (_label == null) {
_label = new DefaultLabel(this);
}
return _label;
}
set { _label = value; }
}
}
public class DefaultLabel implements Label{
public DefaultCharSequence(Nameable named){
this.named = named;
}
public string getLabel(){
return named.getName();
}
public boolean isDefault(){ return true; }
}
public class StringLabel implements Label {
...
}
It all essentially boils down to returning a better class for your label object.

Categories