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.
Related
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'm trying to create a lazy property with Catel framework. Is there a way to do it?
When I'm creating a property in ViewModel like this:
#region Photos property
/// <summary>
/// Gets or sets the Photos value.
/// </summary>
public FastObservableCollection<Photo> Photos
{
get
{
var temp = GetValue<FastObservableCollection<Photo>>(PhotosProperty);
if (temp == null)
Photos = SelectedPatient.GetPhotos();
return GetValue<FastObservableCollection<Photo>>(PhotosProperty);
}
set { SetValue(PhotosProperty, value); }
}
/// <summary>
/// Photos property data.
/// </summary>
public static readonly PropertyData PhotosProperty = RegisterProperty("Photos", typeof (FastObservableCollection<Photo>));
#endregion
the get function is called even without binding, so my lazy property initializes while ViewModel is initializing.
Is there a way to do it?
There is only 1 way to implement "lazy properties", and that is by using the Lazy<> class. The reason for this is that for some mappings (such as view model to model, etc), Catel uses SetValue directly instead of the property wrapper (compare Catel properties with dependency properties).
Basically I've got a KeyedCollection<string, CustomNode>, and I want to be able to sort the collection by the key (or preferably with a custom comparer).
If this isn't possible, can someone recommend another class where the key is embedded in the value that I can sort?
Upon further information (see comments on answer above), a requirement is to keep the "set" sorted by a element's property after the property is edited.
In this case, you might take a look at BindableLinq (there are other similar frameworks too) and use the OrderBy statement implemented in there.
KeyedCollection<string, CustomNode> collection = /* from whereever */
collection.Items.AsBindable().OrderBy(c => c.PropertyOnCustomNode);
As long as your edited property raises a PropertyChanged event then it'll apply the re-ordering immediately. If you wish to change your collection, then ensure that the source collection implements INotifyCollectionChanged.
Came this question while trying to solve a similar problem. If it is still relevant, I was able to implement Sort using the example here:
http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/56adc0f9-aa1b-4acf-8546-082bb01058f2/
Basically involves sorting the underlying List of the collection. Worked like a charm for me.
Cheers!
KeyCollection<T> inherits from Collection<T> which implements IEnumerable so you should be able to use IEnumerable.OrderBy(). IEnumerable.OrderBy() also has an overload that allows you to supply a custom comparer.
This is based on the link provided in the answer by Dan:
http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/56adc0f9-aa1b-4acf-8546-082bb01058f2/
public class RequestTemplate : IComparable<RequestTemplate>
{
// This is the primary key for the object
private Guid _guidNumber;
// This is what a collection of these objects should be sorted by
private string _buttonCaption = "";
public Guid GuidNumber
{
get { return _guidNumber; }
set { _guidNumber = value; } // Setter only provided for deserialization usage
}
public string ButtonCaption
{
get { return _buttonCaption; }
set { _buttonCaption = value; }
}
/// <summary>
/// Method needed to allow sorting a collection of these objects.
/// </summary>
public int CompareTo(RequestTemplate other)
{
return string.Compare(this.ButtonCaption, other.ButtonCaption,
StringComparison.CurrentCultureIgnoreCase);
}
}
public class RequestTemplateKeyedCollection : KeyedCollection<Guid, RequestTemplate>
{
/// <summary>
/// Sort the collection by sorting the underlying collection, accessed by casting the Items
/// property from IList to List.
/// </summary>
public void Sort()
{
List<RequestTemplate> castList = base.Items as List<RequestTemplate>;
if (castList != null)
castList.Sort(); // Uses default Sort() for collection items (RequestTemplate)
}
/// <summary>
/// Method needed by KeyedCollection.
/// </summary>
protected override Guid GetKeyForItem(RequestTemplate requestTemplate)
{
return requestTemplate.GuidNumber;
}
}
Haven't tested it extensively yet, but it seems to work OK.
You might look at the SortedDictionary collection... But that'll come with added expense for item retrieval O(log N) as opposed to a KeyedCollection with O(1) retrieval.
I'm using Generics with a ListView control whose initial class definition looks like this:
namespace BaseControlLibrary
{
public partial class CustomListView<T> : System.Windows.Forms.ListView
{
// Custom fields, properties, methods go here
public CustomListView(List<T> data)
{
_columnInfo = new Dictionary<int, string>();
_columnIndex = 0;
_lvwItemComparer = new ListViewItemComparer();
this.ListViewItemSorter = _lvwItemComparer;
InitializeColumnNames();
BindDataToListView(data);
this.Invalidate();
}
}
}
Here is my designer file:
partial class CustomListView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
//protected override void Dispose(bool disposing)
//{
// if (disposing && (components != null))
// {
// components.Dispose();
// }
// base.Dispose(disposing);
//}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
// this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
}
#endregion
}
What I want to do is to create a Windows Control Library and I have successfully done so, but the problem occurs when I can't add the DLL to the toolbox. I'm not exactly sure why I can't do this. I thought all Windows Forms Controls implement the IComponent interface which is a requirement to add items to the tool box. Is it because there's type parameter as part of the class definition?
The designer hates:
generics
things with abstract base-classes
Even if it works at runtime, you're probably not going to get it to work in the IDE. Sorry. Perhaps consider a non-generic class with a Type property; that's about the best you'll do...
btw, CustomListView<T> and CustomListView are completely different classes. You have 2 classes, not one.
You cannot use generic controls (i.e. control specialized through generics) in the designer. [I seem to remember reading that it was a design decision by the VS team, but i can't find the reference.]
For ObjectListView I used a Adapter pattern to provide typed access to a ListView control.
public class TypedObjectListView<T> where T : class
{
/// <summary>
/// Create a typed wrapper around the given list.
/// </summary>
public TypedObjectListView(ObjectListView olv) {
this.olv = olv;
}
public void BindTo(IList<T> objects) {
// Manipulate the attached ListView here
}
// plus whatever other methods you want
}
and you would use it like this:
TypedObjectListView<Person> tlist =
new TypedObjectListView<Person>(this.listView1);
tlist.BindTo(myListofPeople);
Or, instead of writing everything yourself, you could just use ObjectListView :)
It is possible to get a half way house - I have a HierarchicalDataSource Control that is defined within a generic class and the way I get it to appear in the toolbox is by creating a concrete implementation albeit just a one liner with the Types defined. Compiling the project into a dll and then adding to toolbox from that DLL gives me the toolbox item.