I am trying to bind Font property of System.Windows.Forms.Label to a property of my class (via forms designer).
This is the exception I am seeing "Cannot bind to the property or column HeaderText on the DataSource"
I tried making my class static and make it expose static properties - it didn't help.
The generated code looks like this:
this.WindowTitle.DataBindings.Add(new System.Windows.Forms.Binding("Font", this.fontManagerBindingSource, "HeaderText", true));
//
// fontManagerBindingSource
//
this.fontManagerBindingSource.DataSource = typeof(FontDefinitions.FontManager);
Here is the font manager class:
public class FontManager
{
/// <summary>
/// Gets or sets HeaderText.
/// </summary>
public static Font HeaderText
{
get { return new Font("Tahoma", 42); }
}
}
What am I doing wrong? Under what circumstances a property can not be bound?
Why do you want the property to be static? Its working if you make it non-static.
Related
I've been getting an error (but my code still runs with it so I've been ignoring it until now) saying that my BindableListView is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter.
I'm guessing this is the cause of another crash I'm getting: System.ObjectDisposedException: Cannot access a disposed object. Object name: 'Xamarin.Forms.Platform.Android.FormsTextView'
because I've seen suggestions online saying that most of the time, this issue is related to the ListView, and that I should set the CachingStrategy to RecycleElement.
So I decided to finally take a look at the BindableListView and add in the CachingStrategy = "RecycleElement"
Now there was already some code implemented that seemed to try and add the CachingStrategy already:
BindableListView.cs:
namespace MyApp.Core.Controls
{
[PropertyChanged.DoNotNotify]
public class BindableListView : ListView
{
public static BindableProperty ItemClickedProperty = BindableProperty.Create(nameof(ItemClicked), typeof(ICommand), typeof(BindableListView));
public static BindableProperty ItemAppearsProperty = BindableProperty.Create(nameof(ItemAppears), typeof(ICommand), typeof(BindableListView));
public static BindableProperty AnimateScrollToSelectedItemProperty = BindableProperty.Create(nameof(AnimateScrollToSelectedItem), typeof(bool), typeof(BindableListView), true);
/// <summary>
/// Constructs a <see cref="BindableListView"/>
/// </summary>
/// <param name="cachingStrategy">Sets the caching strategy for the <see cref="ListView"/>.</param>
/// <example><![CDATA[
/// <controls:BindableListView>
/// <x:Arguments>
/// <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
/// </x:Arguments>
/// </controls:BindableListView>
/// ]]></example>
public BindableListView(ListViewCachingStrategy cachingStrategy)
: base(cachingStrategy)
{
ItemTapped += OnItemTapped;
ItemAppearing += OnItemAppearing;
ItemSelected += OnItemSelected;
...
Then in all the .xaml files that use this ListView:
<controls:BindableListView
...>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
Would this be the correct way to set CachingStrategy to Recycle Element? If so then how would I go about fixing my error(s)?
Or should I remove the parameter from the constructor in BindableListView.cs to make it parameterless, and then just add the one line CachingStrategy = "RecycleElement" ? I tried this and the error went away at least.. (app won't run now though, "missing default ctor") but I don't know if it's the right thing to do. If this is what I'm supposed to do, will this fix my second error as well?
Thanks!
The part of the error message that applies to your situation is:
... does not define a public parameterless constructor ...
Change this:
public BindableListView(ListViewCachingStrategy cachingStrategy)
: base(cachingStrategy)
{
ItemTapped += OnItemTapped;
ItemAppearing += OnItemAppearing;
ItemSelected += OnItemSelected;
...
}
To this:
public BindableListView(ListViewCachingStrategy cachingStrategy)
: base(cachingStrategy)
{
Init();
}
public BindableListView()
: base()
{
Init();
}
private void Init()
{
ItemTapped += OnItemTapped;
ItemAppearing += OnItemAppearing;
ItemSelected += OnItemSelected;
...
}
Note that you do want to keep your parameterized constructor (XAML needs that); so the solution is to add a second (parameterless) constructor.
Thus you will have both forms of constructor that are needed, and each of them will perform your initialization logic.
From your code, I think it is the correct way to set CachingStrategy to Recycle Element.
According to this document:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/performance
The solution to this issue is to specify a constructor on the subclassed ListView that accepts a ListViewCachingStrategy parameter and passes it into the base class:
public class CustomListView : ListView
{
public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
{
}
...
}
Then the ListViewCachingStrategy enumeration value can be specified from XAML by using the x:Arguments syntax
<local:CustomListView>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
I am creating a self composing UserControl in WPF.
I have an attribute I adorn the properties of my entity with that instructs my SelfComposingUserControl what to do.
If I want a property to be edited by a specific UI Control I pass this in my attribute.
In my attribute, I'm really not sure how to pass which property on the UI Control I would like bound to my entity property.
Can anybody help?
Here is a stripped down version of my UIEditableAttribute:
public class UIEditableAttribute : Attribute
{
/// <summary>
/// UIControl to edit the property
/// </summary>
public Type UIControl { get; set; }
/// <summary>
/// UIControl dependency property that binds to the property
/// </summary>
public DependencyProperty UIControlValueProperty { get; set; }
}
And here is an example of a property using the attribute
private int _numberOfRows;
[UIEditable(DisplayGroup = "B", UIControl = typeof(RadNumericUpDown), UIControlValueProperty = RadNumericUpDown.ValueProperty)]
public int NumberOfRows
{
get { return _numberOfRows; }
set { CheckPropertyChanged(ref _numberOfRows, value); }
}
In the SelfComposingUserControl, I have got around this by using a switch statement on the type of UIControl that binds the property to the correct dependency property. I would however like to specify at the property level.
Many thanks in advance.
The answer is to pass the UIControlValueProperty as a string i.e. "ValueProperty" in the attribute, then get this useful function;
Get Dependency Property By Name
to get the dependency property from the type or object.
How can I create a simple bool dependency property IsInput. This value can only be set to true or false when the class is created in code. Seems rather simple but ive searched around online and haven't found a clear example.
I've seen examples like this one below online but I'm not quite clear on what I would duplicate to create my own bool dependency property correctly.
public static readonly DependencyProperty AncestorProperty =
DependencyProperty.Register("Ancestor", typeof(FrameworkElement), typeof(MyItem),
new FrameworkPropertyMetadata(Ancestor_PropertyChanged));
/// <summary>
/// Event raised when 'Ancestor' property has changed.
/// </summary>
private static void Ancestor_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyItem c = (MyItem)d;
c.UpdateHotspot();
}
The second parameter of the Register method is the type of the property, i.e. bool, while the third parameter is the so-called owner type, which is the type that declares the property (MyControl in the example below).
For a complete dependency property declaration you also need to declare the "wrapper" property with a getter and a setter that call the dependency property's GetValue and SetValue methods.
public static readonly DependencyProperty IsInputProperty =
DependencyProperty.Register("IsInput", typeof(bool), typeof(MyControl),
new FrameworkPropertyMetadata(IsInputPropertyChanged));
/// <summary>
/// CLR wrapper for the 'IsInput' dependency property.
/// </summary>
public bool IsInput
{
get { return (bool)GetValue(IsInputProperty); }
set { SetValue(IsInputProperty, value); }
}
/// <summary>
/// Callback called when 'IsInput' property has changed.
/// </summary>
private static void IsInputPropertyChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
bool b = (bool)e.NewValue;
//TODO
}
I have a project in winrt environment where I am trying to extend the functionality of the standard GridView control by extending it. The goal is to change the SelectedItems behaviour of the GridView.
public class myGridView : GridView
{
/// <summary>
/// My replacement of SelectedItems
/// </summary>
public IObservableVector<object> appItems
{
get { return GetValue(AppSelectedItemsProperty) as IObservableVector<object>; }
set { SetValue(AppSelectedItemsProperty, value);
appItems.VectorChanged += AppSelectedItemsChanged;
}
}
/// <summary>
/// Identifies the AppSelectedItems dependency property.
/// </summary>
public static readonly DependencyProperty AppSelectedItemsProperty =
DependencyProperty.Register(
"appItems",
typeof(IObservableVector<object>),
typeof(AppGridView),
new PropertyMetadata(null, AppItemsPropertyCallback));
….
….
...
}
In my XAML file I have the following..
<xx
…….
<appControls:AppGridView appItems="{Binding ContactsListSelectedItems, Mode=TwoWay } }">
.…
…
</appControls:AppGridView >
…..
…….
/xx>
The final piece of code is my MVVM class that is bound to the Datacontext.
public class myModel: baseModel
{
……
……..
/// <summary>
/// Not Working
/// </summary>
private IObservableVector<Contact> _ContactsListSelectedItems;
public IObservableVector<Contact> ContactsListSelectedItems
{
get
{
return (IObservableVector<Contact>)_ContactsListSelectedItems;
}
set
{
SetProperty<IObservableVector<Contact>>(ref _ContactsListSelectedItems, value);
}
}
….
….
}
I found a implementation of IObservableVector here : https://gist.github.com/runceel/2437074
The data binding to ContactsListSelectedItems are not working giving the following Error:
Error: Cannot get 'ContactsListSelectedItems' value (type 'Object') from type 'Consius.ActiveWork.Pages.ContactPage.ContactPageViewModel, Consius.ActiveWork, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. BindingExpression: Path='ContactsListSelectedItems' DataItem='Consius.ActiveWork.Pages.ContactPage.ContactPageViewModel, Consius.ActiveWork, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'; target element is 'Consius.ActiveWork.Controls.AppGridView' (Name='ContactsList'); target property is 'appItems' (type 'IObservableVector`1<Object>').
If I change the type of ContactsListSelectedItems to:
IObservableVector<object>
It all works well.
This is not a acceptable solution for me, writing my MVVM class with using the class object.
Is there anyone out there that can give me a hint whats wrong?
Have you tried with ObservableCollection instead of IObservableVector and that custom implementation you found?
I am researching this same problem at the moment. There seem to be two problems.
One, if you move your type (contact) to a WinRT Component project, it gets rid of the exception that the type cannot be instantiated because it is not a legal WinRT type, but then there is a second problem that when the type is not object, the enumerator is used instead of a virtualization and the indexer. So far I cannot see a way around the problem other than using object...
I am tring to extend an existing microsoft control called the PivotViewer.
This control has an existing property that I want to expose to my ViewModel.
public ICollection<string> InScopeItemIds { get; }
I have created an inherited class called CustomPivotViewer and I want to create a Dependency Property that I can bind to that will expose the values held in InScopeItemIds in the base class.
I have spent a fair while reading up about DependencyPropertys and am becomming quite disheartened.
Is this even possible?
You only need a DependencyProperty is you want it to be bindable, meaning: if you want to have, for example, a MyBindableProperty property in your control, with which you want to be able to do:
MyBindableProperty={Binding SomeProperty}
if, however, you want other DependencyProperties to bind to it, any property (either a DependencyProperty or a normal one) can be used.
I'm not sure what you really need, maybe you can clarify more, but if it's the first scenario that you want to implement, you can do it as follows:
create a DependencyProperty, let's call it BindableInScopeItemIds, like so:
/// <summary>
/// BindableInScopeItemIds Dependency Property
/// </summary>
public static readonly DependencyProperty BindableInScopeItemIdsProperty =
DependencyProperty.Register("BindableInScopeItemIds", typeof(ICollection<string>), typeof(CustomPivotViewer),
new PropertyMetadata(null,
new PropertyChangedCallback(OnBindableInScopeItemIdsChanged)));
/// <summary>
/// Gets or sets the BindableInScopeItemIds property. This dependency property
/// indicates ....
/// </summary>
public ICollection<string> BindableInScopeItemIds
{
get { return (ICollection<string>)GetValue(BindableInScopeItemIdsProperty); }
set { SetValue(BindableInScopeItemIdsProperty, value); }
}
/// <summary>
/// Handles changes to the BindableInScopeItemIds property.
/// </summary>
private static void OnBindableInScopeItemIdsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = (CustomPivotViewer)d;
ICollection<string> oldBindableInScopeItemIds = (ICollection<string>)e.OldValue;
ICollection<string> newBindableInScopeItemIds = target.BindableInScopeItemIds;
target.OnBindableInScopeItemIdsChanged(oldBindableInScopeItemIds, newBindableInScopeItemIds);
}
/// <summary>
/// Provides derived classes an opportunity to handle changes to the BindableInScopeItemIds property.
/// </summary>
protected virtual void OnBindableInScopeItemIdsChanged(ICollection<string> oldBindableInScopeItemIds, ICollection<string> newBindableInScopeItemIds)
{
}
in the OnBindableInScopeItemIdsChanged, you can update the inner collection (InScopeItemIds)
remember that the property you want to expose is read-only (it has no "setter"), so you might need to update it as so:
protected virtual void OnBindableInScopeItemIdsChanged(ICollection<string> oldBindableInScopeItemIds, ICollection<string> newBindableInScopeItemIds)
{
InScopeItemIds.Clear();
foreach (var itemId in newBindableInScopeItemIds)
{
InScopeItemIds.Add(itemId);
}
}
Hope this helps :)
EDIT:
I realized misunderstandings and here is a new version (in the context of the original question):
So, you can use the property you need for the binding, with following circumstances having in mind:
as this property is read-only, you will not be able to use it for 2-way binding.
as far as the containing type does not implement INotifyPropertyChanged, your target control used to display the data will not be notified about the changes to the property value.
as far as the returned by this property value does not implement INotifyCollectionChanged (one example is ObservableCollection<T>), the changes to the collection will not be affected on the target control which is used to display it.