How can I use my inherited property in a User Control? - c#

I've got a UserControl class called A and that one contains a Border Property. Then others classes are inherited from A class, but I cannot use my new Property.
public class A : UserControl
{
public A()
{
Border2 = new Border();
Border2.BorderBrush = Media.Brushes.LightGray;
}
public static readonly DependendyProperty Border2Property = DependencyProperty.Register("Border2", typeof(Border), typeof(A));
public Border Border2
{
get { return (Border)GetValue(Border2Property); }
set { SetValue(Border2Property, value); }
}
}
Then when I use another class where is inherited from A, I cannot use this Border2 Property, I'm writing something like:
<local:A.Border2></...
But it tells me that Border2 property doesn't support values of type Grid.

That's because you've created a standard dependency property. If you want to be able to set it on other types besides A, then you want to create an attached property instead. This only takes a handful of code changes:
Register it by calling DependencyProperty.RegisterAttached (instead of .Register)
Add static GetBorder2 and SetBorder2 methods to class A. Even if your code doesn't call these methods, they're part of the pattern and need to be there -- they're how you tell the compiler that yes, you do intend for people to be able to set this attached property in XAML.
For example:
public static readonly DependencyProperty Border2Property =
DependencyProperty.RegisterAttached("Border2", typeof(Border), typeof(A));
public static Border GetBorder2(DependencyObject obj)
{
return (Border) obj.GetValue(Border2Property);
}
public static void SetBorder2(DependencyObject obj, Border2 value)
{
obj.SetValue(Border2Property, value);
}
If your property should only be available for certain element types -- e.g. if it should only apply to FrameworkElement and its descendants, or to Panel and its descendants, or something like that -- then use that as the type of the first parameter to GetBorder2 and SetBorder2.

Related

How to trigger property change on object class nested value change? [duplicate]

I'd first like to say I'm very new to Binding.. I've done some things in WPF already but I never used binding because concept is a bit too hard to understand for me right of the bat. Even this what I'm doing now is something i managed to salvage from a tutorial that I didn't fully understand.
In my application I have a static class with static properties and there's a static method that changes those static properties.
Example:
public static class AppStyle
{
public static SolidColorBrush property = Brushes.Red;
public static void ChangeTheme()
{
property = Brushes.Blue;
}
}
Inside the XAML I have a control that has it's background binded to this value. I even declared the namespace properly.
...
xmlns:style="clr-namespace:CorrectNamespace;assembly=RightAssembly"
...
<TextBox x:Name="TXT_PN"
Background="{Binding Source={x:Static style:AppStyle.property}}"
TextChanged="TXT_PN_TextChanged"
Text="Text"/>
When the application loads it will load the correct setting (Red color) however when things change and ChangeTheme() is called, the static class will get the new value, however the textbox's Background will not change.
What am I doing wrong here? As I said, I'm very new to this and I would appreciate the solution in laymen's terms.
Thank you!
First of all, your property is actually not a property, but a field. A minimal property declaration would look like this:
public static SolidColorBrush Property { get; set; }
Please note the name is starting with an uppercase letter, which is a widely accepted coding convention in C#.
Because you also want to have a change notification fired whenever the value of the property changes, you need to declare a property-changed event (which for non-static properties is usually done by implementing the INotifyPropertyChanged interface).
For static properties there is a new mechanism in WPF 4.5 (or 4.0?), where you can write a static property changed event and property declaration like this:
public static class AppStyle
{
public static event PropertyChangedEventHandler StaticPropertyChanged;
private static void OnStaticPropertyChanged(string propertyName)
{
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
}
private static SolidColorBrush property = Brushes.Red; // backing field
public static SolidColorBrush Property
{
get { return property; }
set
{
property = value;
OnStaticPropertyChanged("Property");
}
}
public static void ChangeTheme()
{
Property = Brushes.Blue;
}
}
The binding to a static property would be written with the property path in parentheses:
Background="{Binding Path=(style:AppStyle.Property)}"
To implement reaction on a change, you need to notify about the change. See INotifyPropertyChanged interface. However, you can't use it with a static class. What about a singleton (ideally using some dependency injection container) instead of a static class?

Update XAML TextBlock with value of public property from other class

I have in my C# WPF solution as follows:
Mainwindow with a startupControl (always running)
Dialogwindow with diffent other controls.
A public Helper-class containing some public static properties to indicate what department at customer is active, and for who i have focus on at the moment.
I want simply two XAML textBlocks displayed in my Startupcontrol to show the property names if and when the value for a department or costumer has been set.
I think it could properbly work smooth with some sort of binding, but i dont know anything about bindings, other than they exists.
Is it possible in any way from my controls in my dialogwindow, to change the value of the 2 textblocks in the Startupcontrol ?
As the program is small and I know exactly when the values change, I think i could make a function setting the value ex.:
activeDepartmentTextBlock.Text = HelperClass.ActiveDepartment.Name;
But from my control.cs in the DialogWindow, it seems to be possible to reach the activeDepartmentTextBlock.
Anyone who can help me ?
Since WPF 4.5, binding to static properties with property change notification is quite simple.
The example below assumes that you want to notify about the change of the ActiveDepartment property of the HelperClass (and not about the Name property of the Department object). In addition to the static property, declare a static event named StaticPropertyChanged and fire it when the static property changes:
public class Department
{
public string Name { get; set; }
}
public class HelperClass
{
public static event PropertyChangedEventHandler StaticPropertyChanged;
private static Department activeDepartment;
public static Department ActiveDepartment
{
get => activeDepartment;
set
{
activeDepartment = value;
StaticPropertyChanged?.Invoke(null,
new PropertyChangedEventArgs(nameof(ActiveDepartment)));
}
}
}
You can bind to a static property like this:
<TextBlock Text="{Binding Path=(local:HelperClass.ActiveDepartment).Name}"/>
Binding is a good solution but you have static property so you can't use binding infrastructure directly to get notified of updates since there's no DependencyObject (or object instance that implement INotifyPropertyChanged) involved.
If the value does change and you need to update TextBlock's value in main window yo can create a singleton instead of static class to contain the value and bind to that.
An example of the singleton:
public class HelperClass : DependencyObject {
public static readonly DependencyProperty ActiveDepartmentProperty =
DependencyProperty.Register( "ActiveDepartment", typeof( Department ),
typeof( HelperClass ), new UIPropertyMetadata( "" ) );
public Department ActiveDepartment {
get { return (Department) GetValue( ActiveDepartmentProperty ); }
set { SetValue( ActiveDepartmentProperty, value ); }
}
public static HelperClass Instance { get; private set; }
static HelperClass() {
Instance = new HelperClass();
}
}
So binding will work like in an example below:
<TextBox Text="{Binding Source={x:Static local:HelperClass.Instance}, Path=ActiveDepartment.Name}"/>
It might look like a hard way and that’s it. You can use events model instead and add the event to your HelperClass. MainWindow can add event handler and change activeDepartmentTextBlock value when event raised.
public MainWindow()
{
InitializeComponent();
HelperClass.Instance.DepartmentChanged += OnDepartmentChanged;
}
private void OnDepartmentChanged(Department newDepartment)
{
activeDepartmentTextBlock.Text = newDepartment.Name;
}
Update. If you want to have the simplest solution you can break encapsulation principle and pass MainWindow as a parameter to DialogWindow and make activeDepartmentTextBlock public. So you will be able to save the link to the MainWindow in the DialogWindow's field and just change the text when you need in DialogWindow:
this.mainWindow.activeDepartmentTextBlock.Text = HelperClass.ActiveDepartment.Name;

Access a hidden property from static method

Given the following
class BaseClass
{
public int Property {get; protected set;}
}
class DerivedClass : BaseClass
{
public new int Property {get; set;} //Hides BaseClass.Property
public static DerivedClass Build()
{
var result = new DerivedClass
{
Property = 17;
//base.Property = 17; // this doesn't compile
}
//((BaseClass)result).Property = 17; // this doesn't compile
}
}
Is there any way to set BaseClass.Property from a static method inside the DerivedClass.
Reflection or Unsafe code is not what I want! I want a non hacky way of setting something which we do legally have access to, but I just can't work out how to set.
Here is how to access an overridden property from a static method of the class:
Add to the class a new property that accesses the base property:
private double BaseProperty { get => base.MyProperty; set => base.MyProperty = value; }
Use that new property from your static:
var result = new DerivedClass
{
BaseProperty = 17;
}
Here is a situation where the above technique is the cleanest solution I have found.
Consider XAML that refers to a BindableProperty, in a class library.
(In my case, the class library is Xamarin Forms.)
Without changing the property name, I want to decouple the base property (used by code compiled into the library) from the XAML-visible property (in my subclass).
The specific use is making text auto-fit, which X-Forms doesn't yet support.
The detail that is relevant here, is that I have the following BindableProperty declaration:
public new static readonly BindableProperty FontSizeProperty =
BindableProperty.Create("FontSize", typeof(double), typeof(AutofitLabel), -1.0,
propertyChanged: (BindableObject bindable, object oldValue, object newValue) => {
((AutofitLabel)bindable).BaseFontSize = (double)newValue;
});
which uses this private property:
private double BaseFontSize { get => base.FontSize; set => base.FontSize = value; }
What this accomplishes, is to initially set base.FontSize - which will be used by layout logic inside library's Label or other text-containing view - to the value set in XAML. Elsewhere in my subclass, I have logic that lowers base.FontSize as needed, once the available width/height are known.
This approach makes it possible to use the library without altering its source code, yet make it appear, to clients of my subclass, that auto-fitting is built-in.
It wouldn't be valid to change FontSize that is visible to client code - that represents the requested size. However, that is the approach taken by Charles Petzold in XF Book Ch. 5 "EmpiricalFontSizePage". Also, Petzold has the page itself deal with the auto-sizing - which is not convenient.
The challenge is the need to tell the library what actual FontSize to use.
Ergo this solution.
All other approaches I've found online require complex custom renderers, replicating logic already existing in XF library.
Is there any way to set BaseClass.Property from a static method inside the DerivedClass.
Yes, rethink your design. It is flawed. Hiding a property and then wanting to set the exact same value on the base and derived class? There seems something really wrong.
You don't necessarily need to hide the property, you could override it, but then it wouldn't make too much sense. It seems the only objective you have is to have different access modifiers on your base class and derived class. This goes against OOP rules, and should be avoided.
If you can introduce another intermediate class, then you can obviously do this. But as others have said, it doesn't just have a code smell, it's positively poisonous.
class BaseClass
{
public int Property { get; protected set; }
}
class InterClass : BaseClass
{
protected void DoFunnyStuff(int value)
{
this.Property = value;
}
}
class DerivedClass : InterClass
{
public new int Property { get; set; } //Hides BaseClass.Property
public static DerivedClass Build()
{
DerivedClass result = new DerivedClass
{
Property = 17
//base.Property = 17; // this doesn't compile
};
result.DoFunnyStuff(17);
return result;
//((BaseClass)result).Property = 17; // this doesn't compile
}
}
So DerivedClass does inherit from BaseClass still, but not directly. You can apply various tricks to try to minimize how much other code is exposed to the existence of InterClass.
It seems you want to modify the APIs behaviour in such a way that something which was mutable before should not be mutable any more. So why not defining a new property, which is really immutable and make the existing one Obsolete instead o trying to hide the original property but not hiding it?
class LegacyClass
{
[Obsolete("Use NewMember instead")]
public string ExistingMember { get; set; } // should actually be immutable
public string NewMember { get { ... } }
}
This way you don´t break existing code.
Yes it's possible through reflection: Property hiding and reflection (C#)
No it's not possible in other ways, if you hide a property by design it's because you don't want give access to that from DerivedClass
Reflection allows you to access for particular purpose, it's not an hacky way the use of reflection.
It's an hacky way to access to a property that you have hidden by design.
If you want access in a legal way to a property you should not hide it.

Sharing dependency property in C# (WPF) between two classes

I want two share a DepedencyProperty between to classes using AddOwner (any other approach is welcome), e.g.
class ClassA : DependencyObject
{
public int Number
{
get { return (int)GetValue(NumberProperty); }
set { SetValue(NumberProperty, value); }
}
public static readonly DependencyProperty NumberProperty =
DependencyProperty.Register("Number", typeof(int), typeof(ClassA),
new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.Inherits));
}
and
class ClassB : DependencyObject
{
public int Number
{
get { return (int)GetValue(NumberProperty); }
set { SetValue(NumberProperty, value); }
}
public static readonly DependencyProperty NumberProperty =
ClassA.NumberProperty.AddOwner(typeof(ClassB),
new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.Inherits));
}
like described here. As you might guess: Of course it doesn't work. That makes perfect sense, because it would make it impossible to create multiple instances of the same class that all have their "own" dependency property.
How do I make sure that all classes (and especially all instances) of ClassA, ClassB and any other class which refers to the property are talking about the exact same property (and therefore value)? A Singleton is no option, since Class A is a MainWindow and Class B is an UserControl (protected constructors are therefore not possible).
Regards,
Ben
I think you're misunderstanding the purpose of DependencyProperties.
They are basically a Property Definition, without a property Value.
They define things like name, type, default value, location of the value, etc however they do not contain the actual value itself. This allows the value to be provided with a binding pointing to any other property in any other location.
Your best bet is to probably just create a property that is backed by a singleton property.
public int Number
{
get { return MySingleton.Number; }
set { MySingleton.Number = value; }
}
Edit
Based on comments below where you say you want all instances of the object to respond to change notifications from any of the other objects, you'd want to implement INotifyPropertyChanged on your singleton object, and subscribe to it's PropertyChange event in each class that uses that value.
For example,
public ClassA
{
public ClassA()
{
MySingleton.PropertyChanged += Singleton_PropertyChanged;
}
void Singleton_PropertyChanged(object sender, NotifyPropertyChangedEventArgs e)
{
// if singleton's Number property changed, raise change
// notification for this class's Number property too
if (e.PropertyName == "Number")
OnPropertyChanged("Number");
}
public int Number
{
get { return MySingleton.Number; }
set { MySingleton.Number = value; }
}
}
One possible solution to what you want here is to use another class where you store that
value. e.g.
public class SomeValueStore : IValueStore
{
int myValue {get; set;}
}
Then, whereever you need that value, you can use Dependency injection to get it.
somewhere at Bootstrapper:
RootContainer.Register<IValueStore>(new SomeValueStore);
and in code:
var valueStore = RootContainer.Resolve<IValueStore();
valueStore.myValue = 42;
This is just an idea (And I know we have a ServiceLocator here).
Perhaps you can store a reference to that ValueStore somewhere where you
can get it from both classes you need it as a simple solution.
public SomeClassYouHaveAccessToFromBothSides
{
public IValueStore _store = new SomeValueStore();
}
Please excuse me. I do not have access to my repo / visual studio right now
so I cannot give better example. But I think the underlying idea is clear.

Different behavior in DependencyProperty's RegisterAttached() and Register()

I find this question during code reading. After search MSDN, it has same issue too.
http://msdn.microsoft.com/en-us/library/ms597501.aspx
For DependencyProperty.Register method, it has code example like:
public static readonly DependencyProperty CurrentReadingProperty = DependencyProperty.Register(...);
public double CurrentReading
{
get { return (double)GetValue(CurrentReadingProperty); }
set { SetValue(CurrentReadingProperty, value); }
}
For RegisterAttached method http://msdn.microsoft.com/en-us/library/ms597496.aspx , it has code example like:
public static readonly DependencyProperty IsBubbleSourceProperty = DependencyProperty.RegisterAttached(....);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
return (Boolean)element.GetValue(IsBubbleSourceProperty);
}
My question is, RegisterAttached doesn't use property format and use 2 static functions. Why?
This is because RegisterAttached and the associated static methods are for registering attached properties like Canvas.Left, which are defined in one class, but can be set on instances of any other class (derived from DependencyObject). You can for example set Canvas.Left on a Button in code like this:
Canvas.SetLeft(button, 100);
You need a static set method since you cannot add a Left property to class Button.

Categories