Ok, so I am not sure this is even possible but I will ask the question here and hope to get an answer to it.
Suppose I have a list of a class, say Media items defined as follows
Enum MediaItemType{
Book,
CD,
VideoGame
}
public MediaItem{
public string Name { get; set; }
public MediaItemType { get; set; }
}
Now suppose I want to bind a list of MediaItems to a TreeView such that each MediaItem ends upp in a separate subtree depending on the media item type. Is that possible to do and if so, how do I do that?
In my Xaml-code I assume that I have defined the list as a property named MediaItems in the context.
<Grid>
<TreeView ItemsSource="{Binding Path=MediaItems}">
</Grid>
The tree view should be something like this
Book
- In to the wild
- Code Complete
CD
- Foo Fighters
- Bach
DVD
- X-men
- Casino Royale
Don't see any problem.
In model you have MediaItem, on model view you have to have MediaItemView type, something like this:
public class MediaItemView
{
public MediaItemType { get; set; }
public List<MediaItem> medialist;
}
Define bindings on that class, and define a Converter which will convert enum value to its string presentation.
I don't know about about a tree view, but you could achieve something similar to what you describe using a GroupDescription grouping on the MediaItemType property with a ListBox or ListView as described here
Related
Data Types
My MainWindow has a property called Project project which has a property ObservableCollection<Drawable> Drawables
public class Drawable {
public enum DrawableType { Top, Head, Feet };
public bool IsMale {get; set;}
public bool IsFemale {get; set;}
public DrawableType DrawableType {get; set;}
public string DisplayName {get; set;}
}
For all Data types and properties I properly implemented the INotifyPropertyChanged interface.
Current situation
The ObservableCollection is displayed in a ListView but as it contains up to about 500 items it is hard to use the application. I would like to display the items in a TreeView-like structure categorized by the gender (IsMale, IsFemale) and the DrawableType like this:
Male
Top (Drawables are display here if IsMale=true and DrawableType=DrawableType.Top)
Drawable 1
Drawable 2
Drawable 3
Head
Feet
Female
Top (Drawables are display here if IsFemale=true and DrawableType=DrawableType.Top)
Drawable 2
Head
Feet
In this example Drawable 2 has IsFemale=true, the others have false.
My problem
During research I found that ListView actually supports grouping but I don't think this is what I want as a single instance of Drawable can be a children of up to two nodes (as with Drawable 2 belongs both to Male->Top and Female->Top)
What I have tried
I tried using a TreeView which provides all the visuals I need for this task but I can not get it to categorize the Drawable instances. I tried subscribing to the PropertyChanged and CollectionChanged events to create an ObservableCollection in order to create a structure that I can directly bind the TreeView to:
public class DrawableListEntry : INotifyPropertyChanged {
public enum Sex {Male, Female}
public Drawable Drawable;
public DrawableType DrawableType = DrawableType.None;
public Sex Sex = Sex.None;
public string Label {
get {
if(Drawable != null) { return Drawable.DisplayName; }
if(DrawableType != null) { return DrawableType.ToString(); }
return Sex.ToString();
}
}
public ObservableCollection<DrawableListEntry> Children {get; set;}
}
My Question
Is it possible to directly bind to the ObservableCollection and let a TreeView do the categorization automatically?
Please keep in mind, that I'm currently not adhering to any patterns like MVVM but I try to keep my business logic apart from the UI.
During research I found that ListView actually supports grouping but I don't think this is what I want as a single instance of Drawable can be a children of up to two nodes (as with Drawable 2 belongs both to Male->Top and Female->Top)
Create a DrawableViewModel class with Gender, DrawableType and DisplayName properties and then add an instance of this class for each leaf entry that you want to display in the grouped ListView.
In this particular example you will then end up with a source collection of four items; Drawable 1, Drawable 2, Drawable 3 and another Drawable 2 (with the Gender property set to Female unlike the first one).
In other words, you should use the MVVM design pattern to basically transform your data model into something that works with the ListView control in the view.
I'm trying to populate a list on my current model with subitems from a different folder.
On my current model I want to define a field of type General Link in which I will select an item from Sitecore who has different subitems.
The "public virtual IEnumerable List" should be populated with the above subitems.
I have read different posts related to how you can make the following type of queries:
[SitecoreQuery("./*[##templatename='Testimonial']", IsRelative = true)]
public virtual IEnumerable Children { get; set; }
but this does not apply in my case because most probably I will have this template in different areas which I do not want to be included here.
Does anyone know if this is possible with Glass or should I just use a custom query to populate the list with an item subitems?
If you use a droplink or droptree field, rather than a General Link, you could do what you want by creating a generic Folder model.
namespace MySite.Models
{
[SitecoreType(AutoMap = true)]
public class Folder<T> : GlassBase
{
[SitecoreChildren]
public virtual IEnumerable<T> Children { get; set; }
}
}
And then use it from another model like so:
[SitecoreField("My Link Field")]
public virtual Folder<ChildModel> MyLinkField { get; set; }
I have a ListBox, and it's items consist of custom class objects (can be any class).
Then I set the DisplayMemberPath so the ListBox shows the right property of that custom class fine.
Now I need to enumerate the Items list of ListBox, and get the DisplayMember value of each item in the list, without knowing the type of the class in the list. Is there any way to get this DisplayMember value without Reflection?
In WPF, you don't need to implement an interface, or a base class for a container control to read the value of a property. In an ideal world, it would make sense to declare a base class or interface and have all of your custom classes extend, or implement these, but the benefit of that is really to keep your data type safe.
For example, in WPF, this is perfectly legal and will work just the same:
public class RadioButtonData
{
public string Label { get; set; }
public bool IsSelected { get; set; }
}
public class CustomData
{
public string Label { get; set; }
public string Value { get; set; }
}
...
private ObservableCollection<object> objects = new ObservableCollection<object>();
public ObservableCollection<object> Objects
{
get { return objects; }
set { objects = value; NotifyPropertyChanged("Objects"); }
}
...
Objects.Add(new RadioButtonData() { Label = "Some Value" });
Objects.Add(new CustomData() { Label = "Another Value" });
...
<ListBox ItemsSource="{Binding Objects}" DisplayMemberPath="Label" />
So as long as your various classes have the same name of property, then they will all be displayed in the same way, like above. They don't even have to be of the same type... just as long as the name matches that used in the ListBox.DisplayMemberPath property.
UPDATE >>>
Ah sorry, I misunderstood your question. In the case that you want to access these property values in code, then you have four basic options:
Define an Interface with a particular property and make your custom classes implement it.
Declare a base class with a particular property and make your custom classes extend it.
Create a (potentially long) section of if else statements that checks the type of each object and then accesses the relevant property.
Use reflection.
In my personal opinion, I would recommend options 1 or 2 first, then 4 and lastly 3. I'm really not sure what you have against reflection, but it's really not that bad, or slow... I'd certainly prefer to use it rather than having an else if statement for every possible type used.
I have a usercontrol with a Collection property. What I want to achieve is to be able to add/modify/remove items of some data types of that collection via VS designer (Property window/Collection editor).
I have a simple class:
public class Quantity
{
public string Name { get; set; }
public Type DataType { get; set; }
}
In my UserControl I have:
private ObservableCollection<Quantity> _quantities = new ObservableCollection<Quantity>();
public ObservableCollection<Quantity> Quantities
{
get { return _quantities; }
}
And the thing is that I am able to change the Name property via that VS Collection editor but I am unable to change DataType property that way.
So what do I have to do to make it work?
I don't believe this can be achieved through the properties editor. You can however produce the result in XAML. Here is what it would look like using your example:
<my:UserControl1>
<my:UserControl1.Quantites>
<my:Quantity Name="Hello World" DataType="{x:Type sys:Boolean}"/>
<my:Quantity Name="This is a double" DataType="{x:Type sys:Double}"/>
</my:UserControl1.Quantites>
</my:UserControl1>
If you need access to system types (like I used in my example) you can include the following xmlns:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Hope it helps :)
In C# itself, is there something like "attached property" used in WPF?
The short answer is no. The slightly longer answer is that this is a bit of an unfortunate story. We designed "extension properties" for C# 4 and got as far as implementing (but not testing) them when we realized, oh, wait, the thing we designed is not really compatible with WPF-style properties. Rather than redesign and reimplement the feature we ended up cutting it.
The even longer version is here:
http://blogs.msdn.com/b/ericlippert/archive/2009/10/05/why-no-extension-properties.aspx
AttachedProperties are part of the .NET Framework, not part of the C# language specification, and specifically part of the System.Activities.Presentation.Model namespace, which is WPF specific.
In WPF, an attached property allows you to do something like:
<TextBlock Grid.Row="2" Text="I know nothing about grids!" />
This would be like having a class in C# defined as:
public class TextBlock
{
public string Text { get; set; }
}
And being able to do this:
var tb = new TextBlock();
tb.Grid.Row = 2; // this line would not compile
In order to make this work, you'd need to pass a Grid object into your TextBlock class:
public class TextBlock
{
public string Text { get; set; }
public Grid Grid { get; set; }
public TextBlock(Grid grid)
{
Grid = grid;
}
}
But I don't think there's anything directly equivalent to the way attached properties work in WPF. You'd need to build it by hand.
What are you trying to accomplish?
You can use the ConditionalWeakTable<TKey, TValue> class to attach arbitrary state to an instance. You can combine it with extension methods to create a form of extension properties, but unfortunately without using the nice property syntax in C#.
I think you're thinking of getters and setters.
They are created like this:
public class Person
{
//default constructor
public Person()
{
}
private string _Name;
public string Name
{
//set the person name
set { this._Name = value; }
//get the person name
get { return this._Name; }
}
}
More on how they work here:
http://msdn.microsoft.com/en-us/library/aa287786(v=vs.71).aspx