I get the exception:
AmbiguousMatchException: ambiguous match found
when opening my Window and the XAML gets parsed. I have a base ViewModel class. It has a property for the SelectedItem property of a DataGrid
public class BaseViewModel<T> : ViewModel, INotifyPropertyChanged where T : MyClass
{
protected T _selectedItem;
public T SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnPropertyChanged();
}
}
}
In my inherited ViewModel I override that property which produces the exception
public new MyInheritedClass SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnPropertyChanged();
//Do other stuff
}
}
So how to use the overrided property and not get an exception?
Why are you redefining the property in the derived class? The type argument of the derived class should specify the type of the property:
public class MyInheritedClass : BaseViewModel<MyClass>
{
//no need to define a new SelectedItem property...
}
In the above sample code MyInheritedClass already has a SelectedItem property of type MyClass. It is already defined in the base class. You don't need to create a new one.
If the property needs to do something special in the derived class, you should define the property as virtual in the base class:
public virtual T SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnPropertyChanged();
}
}
...and override it in the derived class:
public override MyClass SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnPropertyChanged();
//Do other stuff
}
}
This happens, if you define a Property (or the accessor of a Dependency property) which already exists in the base class. Because then you make it ambigious. Either you have to override (Topic: virtual) or new (hide) it. Otherwise the reflection happenings in WPF will deal with ambiguity.
Example:
public partial class My : UserControl
{
// this will make the ambiguity with the existing trigges-DP legacy accessor
public int Triggers {get;set;}
// this will not make ambiguities, because it hides the original.
// however it may cause other problems
public new object Background {get;set; }
// also OK, but needs justification as well.
public override object ExistingVirtualProperty {get;set; }
...
Related
So, I need to go through my code base and remove all the public setters and change them to private for immutable properties.
I know this will make it harder for me to set the values an I can do that through a constructor. Are there any other ways for me to set the value besides through a constructor?
The point is to limit the access on changing the value.
private string _value;
public SetValue(string value)
{
_value = value;
}
or
ctrl+. on property to encapsulate field
There are several methods that I use to create immutable properties in C#, when I also need to set that property outside of the constructor.
The first scenario is to throw an exception if the object is modified after being set
private object _myProperty;
public object MyProperty
{
public get { return _myProperty; }
public set
{
if(_myProperty == null) { _myProperty = value; }
else { throw new InvalidOperationException("MyProperty can't be changed onece set"); }
}
}
This method doesn't prevent errors before runtime but it can help you catch yourself when you're doing silly things.
Another method is to hide setters using an interface. By explicitly implementing an interface you can hide a property or method from a user unless they cast your class to that specific interface. This doesn't actually make your property immutable, but it helps protect properties from unintentional modification.
public interface MyInterface
{
object MyProperty { get; }
}
public interface MyInterfaceProtected
{
object MyProperty { set; }
}
public class MyClass : MyInterFace, MyInterfaceProtected
{
private object _myProperty;
public object MyProperty { get {return _myProperty;} }
object MyInterfaceProtected.MyProperty
{
set { _myProperty = value; }
}
}
It seems you are talking about C# 6 { get; }. Those properties are settable only from the constructor.
If you will define your property as { get; private set; } you will be able to set it from this class or in derived classes.
My Custom Sitecore control inherits from Sitecore.Web.UI.HtmlControls.Control. This Class defines the Property Value as follows:
public virtual string Value {
get {
return this.GetViewStateString("Value");
}
set {
if (!(value != this.Value))
return;
this.SetViewStateString("Value", value);
}
}
My custom class is defined as follows:
public class ClientProfileSelector : Sitecore.Web.UI.HtmlControls.Control, IContentField {
...
public override string Value {
get {
return this.MyOwnValue;
}
set {
if (!(value != this.MyOwnValue))
return;
this.MyOwnValue = value;
}
}
...
}
The code of the entire class is available here.
My class is automatically instantiated by Sitecore, but I know it is running because I can step into other methods defined therein. For example the method GetValue() in my custom class calls the field Value like so:
public string GetValue() {
return string.IsNullOrEmpty(CalculatedValue) ? CalculatedValue : Value;
}
but when I step over it after adding breakpoints in both my definition and the base class' one, the execution stops in the base class.
What am I doing wrong?
I have a project called Common along with several other projects. Inside the Common project, I have a class named ItemBase. Inside that class, I have a virtual getter called CachedReference, it looks like so:
public virtual ItemData CachedReference
{
get
{
return new ItemData();
}
}
Now, I'm returning an empty ItemData object because I want the classes that inherit from ItemBase to override this getter so it will refer to the overriden getter and not the default one (I would make it an abstract class, but I can't because the Common project initializes instances of this class).
In my other projects I have a class named Item which inherits from the ItemBase class and overrides the getter. It looks like so:
public override ItemData CachedReference
{
get
{
return LoginServer.Instance.ItemDataProvider[this.MapleId];
}
}
The constructor of the ItemBaseclass uses the CachedReference property to set it's data. However, when I initialize a new instance of the Itemclass that uses the default constructor of ItemBase, it refers to the default getter rather than the overriden one.
Why's that happening? I want to refer the overriden getter only, not the default one so each project can return it's own CachedReference.
EDIT: I've been asked to show how I use CachedReference, so here:
public ItemBase(int mapleId, short quantity = 1)
{
this.MapleId = mapleId;
this.Quantity = quantity;
this.WeaponAttack = this.CachedReference.WeaponAttack;
...
}
This code works as you expect. Can you provide a compilable code of your's that demonstrates your problem?
public static void Main()
{
var derived = new Derived();
}
public class Base
{
protected string _p = "Base";
public virtual string P
{
get { Console.WriteLine("Base get"); return _p; }
set { Console.WriteLine("Base set"); _p = value; }
}
public Base()
{
P = "Base constructor";
}
}
public class Derived : Base
{
public override string P
{
get { Console.WriteLine("Derived get"); return _p; }
set { Console.WriteLine("Derived set"); _p = value; }
}
public Derived()
{
Console.WriteLine(P);
}
}
Output:
Derived set
Derived get
Base constructor
I recently wrote two classes and an interface as a way to implement the answer to this question of mine.
The first class is the Notifier generic class:
public interface INotifier { }
public class Notifier<T> : Observable,INotifier where T:new()
{
public Notifier()
{
V = new T();
}
private T _ValueBacker;
public T V
{
get { return _ValueBacker; }
set
{
_ValueBacker = value;
OnPropertyChanged(() => V);
}
}
}
The Observable base class here is just a class that implements INotifyPropertyChanged and defines an OnPropertyChanged method.
Thanks to that class, I can now define a Silverlight/WPF ViewModel like this:
public class Person : ViewModelBase
{
Notifier<string> Name {get;set;}
Notifier<string> Surname {get;set;}
Notifier<int> Age {get;set;}
}
instead of:
public class Person : Observable
{
private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
_Name=value;
OnPropertyChanger(()=>Name);
}
}
privaate string _Surname;
public string Surname
{
get
{
return _Surname;
}
set
{
_Surname=value;
OnPropertyChanger(()=>Surname);
}
}
private int _Age;
public int Age
{
get
{
return _Age;
}
set
{
_Age=value;
OnPropertyChanger(()=>Age);
}
}
}
As you can see, the new code is much more concise and much less coding-error (or typo) prone. All I have to do in my XAML is to bind to "MyPerson.V" instead of "MyPerson". However, since there aren't any ways to implement initializers for autoproperties, I had to initialize every property in the constructor. In some cases, I skipped the initializers and that led to some runtime errors. So, to take care of that, in the constructor of the ViewModelBase class, I added this loop:
public ViewModelBase()
{
foreach(var notifierProperty in this.GetType().GetProperties().Where(c=>c.PropertyType.GetInterfaces().Any(d=>d==typeof(INotifier))))
{
notifierProperty.SetValue(this, notifierProperty.PropertyType.GetConstructor(System.Type.EmptyTypes).Invoke(null), null);
}
}
What this does is, whenever you instantiate a ViewModelBase derived class, the constructor loops through the properties, and invokes the constructor for each Notifier type property.
Is this evil? Will using reflection this way come back to haunt me in the future? Are there any performance hits I should be aware of?
I think that's fine. I have some bits of information to add:
You can create types with trivial constructors by calling Activator.Create(myType), which means you don't have to fetch a constructor.
I believe at least for Silverlight, all properties initialized with your hack need to be public.
There is a library called ReactiveProperty, that defines a class ReactiveProperty<T> very similar to your Notifier<T>.
You will bind against it's Value property:
public class ReactiveProperty<T> : IObservable<T>, IDisposable, INotifyPropertyChanged, IReactiveProperty, INotifyDataErrorInfo
{
public T Value
{
get { return latestValue; }
set { anotherTrigger.OnNext(value); }
}
// ...
}
The call in the setter eventually leads to the respective call to INotifyPropertyChanged.PropertyChanged.
ReactiveProperty<T> also is an observable in the sense of reactive extensions, on which the library depends. Other than that, the author basically does what you do, but without the initialization hack in the constructor.
Say I have a class
class Object
{
Vector2 positon;
}
This position is editable in the propert grid, how would I be able to set this as not browasable / read only in a class that inherits from object. I know the [Browsable(false)] and [ReadOnly(true)] tags but this will set the it for all Objects, which I do not desire.
Declare position property as virtual and override it on derived types.
public class Class1
{
public virtual string Lol { get; set; }
}
class Class1Impl1 : Class1
{
[Browsable(false)]
[ReadOnly(false)]
public override string Lol
{
get
{
return base.Lol;
}
set
{
base.Lol = value;
}
}
}
class Class1Impl2 : Class1
{
[Browsable(true)]
[ReadOnly(true)]
public override string Lol
{
get
{
return base.Lol;
}
set
{
base.Lol = value;
}
}
}
Doing it at runtime is a different question, IsBrowsable and IsReadOnly are readonly properties. You should google to know if there is posible to change the instances of this attributes at runtime, which I think is not.
I don't think it's possible to change the browseable attribute at runtime (and I don't understand the point of doing that), but you can have a method check your conditions and allow/disallow writing of the property. If that's good enough, I'll be glad to mock something up if you want.
EDIT:
class SomeClass
{
private Object _foo;
private Object _bar;
public Object Foo
{
get
{
return _foo;
}
set
{
if (_bar != _foo) // replace with your test
{
_foo = value;
}
}
}
}