Using bindings for dependency property XAML - c#

Apologies for yet another Dependency property question
Following these questions:
XAML Binding on Dependency Property
A 'Binding' can only be set on a DependencyProperty of a DependencyObject
and this tutorial:
http://wpftutorial.net/DependencyProperties.html
I am having a similar problem. and after trying the solutions not much has changed.
I have made a control library: WpfCustomControlLibrary1
public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
And added a dependency property with the required callbacks:
FrameworkPropertyMetadata meta = new FrameworkPropertyMetadata(null,FrameworkPropertyMetadataOptions.Inherits, PropertyChangedCallbackMethod, OnDictionaryCoerce,false);
public static readonly DependencyProperty DictionaryProperty = DependencyProperty.Register("DictionaryProperty",typeof(Dictionary<string,int>),
typeof(CustomControl1),new FrameworkPropertyMetadata(null,FrameworkPropertyMetadataOptions.Inherits));
private Dictionary<string, int> _Dictionary;
public static void PropertyChangedCallbackMethod(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// I am not entirely sure what code should be implemented here, leaving it blank for now
}
private static Object OnDictionaryCoerce(DependencyObject sender,Object data)
{
return data;
}
private static bool OnValidate(object data)
{
return data is Dictionary<string, int>;
}
public Dictionary<string, int> Dictionary
{
get
{
return _Dictionary;
}
set
{
_Dictionary = value;
}
}
}
}
I then try to set the property to a binding in an application but am given an error saying:
How do I set my dependancy property to be a dependancy object? or is their a way to set a binding to a dependency property?
And isn't the base class of a dependency property a dependency object?

Register DP with correct name:
DependencyProperty.Register("Dictionary", ...
and then in DP wrapper property use GetValue, SetValue methods
public Dictionary<string, int> Dictionary
{
get
{
return (Dictionary<string, int>)GetValue(DictionaryProperty);
}
set
{
SetValue(DictionaryProperty, value);
}
}
private Dictionary<string, int> _Dictionary; field is not necessary

Related

How to implement a thread safe singleton dictionary class for caching?

I am trying to implement a thread safe dictionary singleton class for caching purpose.
namespace SingletomDict
{
public sealed class MySingleton:IDisposable
{
private static readonly Lazy<MySingleton> coll = new Lazy<MySingleton>(() => new MySingleton());
private static Dictionary<string, object> mycoll;
public static MySingleton Instance
{
get
{
return coll.Value;
}
}
private MySingleton()
{
mycoll = new Dictionary<string, object>();
}
private void SetProperty<T>(string name, T value)
{
mycoll.Add(name, value);
}
private object GetProperty(string name)
{
object value = mycoll[name];
return value;
}
public dynamic this[string index]
{
get { return GetProperty(index); }
set { SetProperty(index, value); }
}
public void ReSet()
{
mycoll = new Dictionary<string, object>();
}
}
In the main method, I will be invoking the object as
MySingleton.Instance["LS"] = "AAA";
MySingleton.Instance["AB"] = "BBB";
MySingleton.Instance.ReSet();
I did some research to find the correct implementation. But I couldn't find the appropriate example. Thanks
First declare an interface that describes how you want to use this. Perhaps ICache with a get and set method. (I'd steer clear of dynamic.)
public interface ICache
{
T Get<T>(string key);
void Set(string key, object value);
}
Then write an implementation. Your implementation doesn't need to specify what the internals are.
public class Cache : ICache
{
private readonly ConcurrentDictionary<string, object> _cache
= new ConcurrentDictionary<string, object>();
public T Get<T>(string key)
{
object cached;
if(_cache.TryGetValue(key, out cached) && cached is T)
{
return(T) cached;
}
return default(T);
}
public void Set(string key, object value)
{
_cache.AddOrUpdate(key, value, (s, o) => value);
}
}
If you want to make this a singleton, you can make the constructor private and create a static singleton instance. I would lean toward not doing that. It's better for other classes to depend on the ICache interface than on the implementation, and an interface doesn't have static methods.
Depending on the interface means that you can substitute it with different implementations, like one that depends on MemoryCache.
public class InMemoryCache : ICache
{
private readonly MemoryCache _cache = MemoryCache.Default;
public T Get<T>(string key)
{
var cached = _cache[key];
return cached is T ? (T) cached : default(T);
}
public void Set(string key, object value)
{
_cache[key] = value;
}
}
If you use a dependency injection (IoC) container you can tell it which implementation of ICache to use for a class that needs an instance of it, and you can specify that the same instance should be provided each time. That way you get to use a single instance of your class as if it was a singleton without having to code it as a singleton.

Workaround for C# properties with arguments

I know the fact that C# doesn't support properties with arguments except the default properties. But I think still it's nice to have such feature in some situations. As an example, an application might have settings which are specific to the language currently used. So such settings property may look like this.
settings.IsContentDownloaded["en-US"] = true;
Event thought this doesn't support by default, we can come up with a workaround to simulate this with other great feature available in the language. But the problem is what is the best workaround which provide a generalized approach to this problem.
I have my own workaround for this and I have shared it as an answer. But I'm looking for a better approach or any improvement to my approach.
create a dictionary where the keys are your strings such as "en-US" and the values are a bool:
Dictionary<string, bool> aaa = new Dictionary<string, bool>();
aaa.Add("en-US", true);
if(aaa["en-US"].Equals(true))
{
}
Its an interesting question, here is a method I came up with:
public class LocalizableSetting<T> : IEnumerable<KeyValuePair<string, T>>
{
private Dictionary<string, T> _values;
public T this[string cultureName]
{
get { return _values[cultureName]; }
set
{
_values[cultureName] = value;
}
}
public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
{
return _values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _values.GetEnumerator();
}
public static implicit operator T(LocalizableSetting<T> value)
{
return value[CultureInfo.CurrentCulture.Name];
}
public static implicit operator LocalizableSetting<T>(T value)
{
var setting = new LocalizableSetting<T>();
setting[CultureInfo.CurrentCulture.Name] = value;
return setting;
}
}
Here LocalizableSetting stores localized values in an internal dictionary, which is really nothing special, however I added a feature that allows it to be used like normal properties as well, the implicit conversion operators.
This does take some tricks to use though, in order to properly use it in a class, you cannot use auto-properties, since you have to merge the two on a set, not overwrite it, so here is an example of how to use it in a class:
public class SomeLocalizableClass
{
//Explicitly declare the backing field for the property!
private LocalizableSetting<int> _intSetting = new LocalizableSetting<int>();
public LocalizableSetting<int> IntSetting
{
get { return _intSetting; }
set
{
//Merge, don't overwrite
foreach (var kvp in value)
_intSetting[kvp.Key] = kvp.Value;
}
}
}
Notice that in the set method, it iterates through the values and either overwrites the current one or adds a new one (with the help of the indexer).
So, this allows you to do something like this:
public class SomeConsumerClass
{
public void SomeMethod()
{
SomeLocalizableClass c = new SomeLocalizableClass();
c.IntSetting["fr-FR"] = 4; //Sets the french setting
c.IntSetting = 10; //Sets the current culture setting
int multipleSetting = c.IntSetting * c.IntSetting;
}
}
Where multipleSetting will be the multiple of the current culture values for that property due to the implicit conversion from LocalizableSetting<int> to int. The c.IntSetting = 10 causes an implicit conversion from the source type (int) to a LocalizableSetting<int> and then assigns it to the property, this is why a merge is needed instead of an overwrite.
There are a couple (big) holes that I left here, namely that the property should return some default value if the value for that culture is not found (currently it will throw an exception). But it shows one method of solving this issue.
I have used dictionary named _settingsRepositoty to store settings, but it might be anything which use to store setting based on the application type.
public class Settings
{
private Dictionary<string, object> _settingsRepository = new Dictionary<string, object>();
private LanguageSpecificPropertyFactory _factory;
public Settings()
{
_factory = new LanguageSpecificPropertyFactory(this);
}
public LanguageSpecificProperty<bool> IsContentDownloaded
{
get
{
return _factory.GetLanguageProperty("IsContentDownloaded", false);
}
}
private void Set<T>(string propertyName, string lang, T val)
{
string fullPropertyName = string.Format("{0}_{1}", propertyName, lang);
_settingsRepository[fullPropertyName] = val;
}
private T Get<T>(string propertyName, string lang, T defaultValue)
{
string fullPropertyName = string.Format("{0}_{1}", propertyName, lang);
if (!_settingsRepository.ContainsKey(fullPropertyName))
{
_settingsRepository[fullPropertyName] = defaultValue;
}
return (T)_settingsRepository[fullPropertyName];
}
public class LanguageSpecificProperty<T>
{
private string _properyName;
private T _defaultValue;
private Settings _settings;
internal LanguageSpecificProperty(Settings settings, string propertyName, T defaultValue)
{
_properyName = propertyName;
_defaultValue = defaultValue;
}
public T this[string lang]
{
get
{
return _settings.Get<T>(_properyName, lang, _defaultValue);
}
set
{
_settings.Set<T>(_properyName, lang, value);
}
}
}
public class LanguageSpecificPropertyFactory
{
private Dictionary<string, object> _properties = new Dictionary<string, object>();
private Settings _settings;
public LanguageSpecificPropertyFactory(Settings settings)
{
_settings = settings;
}
internal LanguageSpecificProperty<T> GetLanguageProperty<T>(string propertyName, T defaultValue)
{
if (!_properties.ContainsKey(propertyName))
{
_properties.Add(propertyName, new LanguageSpecificProperty<T>(_settings, propertyName, defaultValue));
}
return (LanguageSpecificProperty<T>)_properties[propertyName];
}
}
}

WPF Dependency Property Error

I am trying to define a dependency property like this:
public static readonly DependencyProperty DependencyPropertyName= DependencyProperty.Register("DepName", typeof(EnumName), typeof(MyWindow1), new FrameworkPropertyMetadata("FrameWorkProperty", FrameworkPropertyMetadataOptions.AffectsRender, Target));
private static void Target(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
//some logic here
}
public EnumName DepName
{
get { return (EnumName)GetValue(DependencyPropertyName); }
set { SetValue(DependencyPropertyName, value); }
}
And i get this error, and dont understand why:
{"Default value type does not match type of property 'DepName'."}
The default value type (String) of your Dependency Property does not match the Type of your property DepName (EnumName).
Change the default type in your dependency property and it should work.
public static readonly DependencyProperty DependencyPropertyName= DependencyProperty.Register(
"DepName",
typeof(EnumName),
typeof(MyWindow1),
new FrameworkPropertyMetadata(
EnumName.SomeValue, // this is the defalt value
FrameworkPropertyMetadataOptions.AffectsRender,
Target));

Is it wrong/bad to use INPC on a DependencyObject to support built-in conversion behavior?

We have a DependencyObject which defines a Value property as a DP. It also defines a Presets collection representing friendly names for some pre-defined values.
The way our UI should work is when we bind to the Value property, if the value matches a preset, we show the friendly name, otherwise we just show the value directly.
Using a converter is out since there's no reliable way to both pass in the Presets (which are defined per-item, they aren't shared) and also do two-way binding, so our thought is to expose a FriendlyValue property on the object and use that for binding in the UI, letting it handle the conversion internally.
Since FriendlyValue depends on the already-existing Value DependencyProperty, we figured we'd just wrap the conversion logic in CLR getters/setters, but that means when the actual Value DP changes, it needs to notify the UI that FriendlyValue has been updated too, and since FriendlyValue is a CLR property, we need to support INPC for that specific property.
My question is, is that the correct/suggested way to handle this, or should I go with a second DP, monitoring its change handlers and setting the other property accordingly, adding state variables to stop one from setting the other, which then sets the first, which then again updates the other, etc.
Here's the code for the object's properties...
public static readonly DependencyProperty PresetsProperty = DependencyProperty.Register(
"Presets",
typeof(List<Preset>),
typeof(MyObject),
new UIPropertyMetadata(null));
public List<Preset> Presets
{
get { return (List<Preset>)GetValue(PresetsProperty); }
set { SetValue(PresetsProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value",
typeof(string),
typeof(MyObject),
new UIPropertyMetadata(null, (s,e) => {
var myObject = (MyObject)s;
myObject.OnPropertyChanged("FriendlyValue");
}));
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public string FriendlyValue
{
get
{
var foundPreset = Presets.FirstOrDefault(preset => preset.Value == this.Value);
return (foundPreset != null)
? foundPreset.FriendlyName
: this.Value;
}
set
{
var foundPreset = Presets.FirstOrDefault(preset => preset.FriendlyName == value);
this.Value = (foundPreset != null)
? foundPreset.Value
: value;
// Note: We don't raise INPC notification here. It's raised in the Value's change handler
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
So is this considered good practice for built-in converter behavior?
Why not make both Value and FriendlyValue dependency properties? I see no reasons to use two techniques at the same time.
Consider:
using Preset = Tuple<string, string>;
public class MyObject : DependencyObject
{
private readonly IList<Tuple<string, string>> _presets = new List<Preset> {
new Preset("1", "good"),
new Preset("2", "bad"),
};
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(string), typeof(MyObject),
new PropertyMetadata(null,
(o, e) => ((MyObject)o).ValuePropertyChanged((string)e.NewValue)));
private static readonly DependencyProperty FriendlyValueProperty = DependencyProperty.Register(
"FriendlyValue", typeof(string), typeof(MyObject),
new PropertyMetadata(null,
(o, e) => ((MyObject)o).FriendlyValuePropertyChanged((string)e.NewValue)));
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public string FriendlyValue
{
get { return (string)GetValue(FriendlyValueProperty); }
set { SetValue(FriendlyValueProperty, value); }
}
private void ValuePropertyChanged (string newValue)
{
var preset = _presets.FirstOrDefault(p => p.Item1 == newValue);
FriendlyValue = preset != null ? preset.Item2 : newValue;
}
private void FriendlyValuePropertyChanged (string newValue)
{
var preset = _presets.FirstOrDefault(p => p.Item2 == newValue);
Value = preset != null ? preset.Item1 : newValue;
}
}
Notes:
Code for presets simplified for brevity.
This will not cause stack overflow, because change callback are not called if value is not changed.
I hope I understood your logic correctly. There's one issue: if you change FriendlyValue to one of the friendly values from the presets, this will change Value to the value from the found preset and in turn change FriendlyValue to the name of the preset. I don't know if that behavior is expected.

PropertyMetadata to register a DependencyProperty of Type "System.Windows.Point"?

Here is my code :
public class ExoticPoint : DependencyObject
{
public Point PointValue
{
get { return (Point)GetValue(PointValueProperty); }
set { SetValue(PointValueProperty, value); }
}
public static readonly DependencyProperty PointValueProperty =
DependencyProperty.Register("PointValue", typeof(Point), typeof(ExoticPoint), new PropertyMetadata(0));
public string Description
{
get { return (string)GetValue(DescriptionProperty); }
set { SetValue(DescriptionProperty, value); }
}
public static readonly DependencyProperty DescriptionProperty =
DependencyProperty.Register("Description", typeof(string), typeof(ExoticPoint), new UIPropertyMetadata(0));
public ExoticPoint()
{
}
public ExoticPoint (string objectName)
: base(objectName)
{
}
}
It compiles but when I want to CreateInstance of my type it crashes with the following error :
{"Default value type does not match type of property 'PointValue'."}
So Im kinda sure the problem is :
new PropertyMetadata(0)
but as far as I understand PropertyMetadata it should work as there is a Point constructor that takes an int as parameter : http://msdn.microsoft.com/en-us/library/bf1b4f2b.aspx
So... what is wrong ?
Yes you are right the problem is with the object passed into PropertyMetada.The parameter will be the default value for your property so it has to match with the type of your dependency property.
In your case PointValue type is Point so you should write new PropertyMetadata(new Point(0)).
Also your Description property which is string: new UIPropertyMetadata("0") or new UIPropertyMetadata("") depending on your needs.

Categories

Resources