File System-like TreeView using HierarchicalDataTemplate in WPF/Silverlight - wpf

My ViewModel looks like this:
public class DirectoryViewModel : ViewModelBase
{
public ObservableCollection<DirectoryViewModel> SubDirectoryList { get; set; }
public ObservableCollection<FileViewModel> FileList { get; set; }
public string Name { get; set; }
}
Under each directory, there may be it's own files as well as sub-directories. How can I make both of it's sub-directories and files display on a same level of a TreeView?

Change your class like this:
public class DirectoryViewModel : ViewModelBase
{
public ObservableCollection<ViewModelBase> ItemsInDirectory { get; set; }
public string Name { get; set; }
}
ViewModelBase has to be the base class of DirectoryViewModel and FileViewModel. Put all your files and directories into the ItemsInDirectory collection.
Then create 2 HierarchicalDataTemplates one for class DirectoryViewModel and one for FileViewModel

One option would be to have both DirectoryViewModel and FileViewModel derive from the same TreeViewItemBase class. Then use have one collection rather than two, and let each derived member deal with its own particularities (like how to, if at all, get child members. What icon to display, etc)

Related

using statement in codebehind

When editing the c# programs I have the top that includes namespaces with the using keyword. Such as using System;.
I have some classes that are redundantly implemented across my WPF application. I would like to create a single reference point to use the methods within the whole application.
for instance when I perform data binding for ComboBoxes I have a class that includes this...
public class ComboBoxItemSource : ViewModelBase
{
public ObservableCollection<Item> Source { get; set; }
public Item Selected { get; set; }
}
I would like to have this in one place and include it in a reference rather than create it in each ViewModel that will need a combobox binding.
I'd recommend to just put the class in a separate file and add it to your project.
Or even simpler:
Right click on your project in the Solution Explorer -> "Add new Item" -> "Class".
Copy/Paste your class into the file
Adjust the namespace
Add the missing usings to the file (especially the using for the "View Model Base")
The class including the namespace in the file will now look similar to this:
namespace MyNamespace
{
public class ComboBoxItemSource : ViewModelBase
{
public ObservableCollection<Item> Source { get; set; }
public Item Selected { get; set; }
}
}
You could do something like this.
Create an IComboBox interface:
public interface IComboBox
{
ObservableCollection<Item> Source { get; set; }
Item Selected { get; set; }
}
then you could create a Class that inherits from your ViewModelBase and implements your IComboBox:
public class ComboBoxVM :ViewModelBase, IComboBox
{
public ObservableCollection<Item> Source
{
get
{
// do stuff
return _source;
}
set { _source = value; }
}
public Item Selected
{
get
{
// do stuff
return _selected;
}
set { _selected = value; }
}
}
then in your ComboBoxItemSource, inherit from ComboBoxVM:
public class ComboBoxItemSource : ComboBoxVM
{
}
Hopefully this helps.

WPF DataGrid build from List<SomeInterface> using AutoGenerateColumns

I'm trying to load data to DataGrid from a generic list.
the relevant code:
XAML:
<Grid>
<DataGrid DataContext="{Binding Lines}"
ItemsSource="{Binding}"
AutoGenerateColumns="True">
</DataGrid>
</Grid>
C#:
public IList<IReportLine> Lines { get; set; }
public interface IReportLine {}
public class ReportLine : IReportLine
{
public string A { get; set; }
public string B { get; set; }
}
It seems that the columns are taken from the type IReportLine - so I'm getting an empty DataGrid.
Of course, if I'm changing IReportLine definition to:
public interface IReportLine
{
string A { get; set; }
string B { get; set; }
}
it works perfectly, but i can't do that because every class that implement IReportLine has different Properties.
What can I do in order to make the columns be generated from the dynamic type of IReportLine?
Or have any other idea to solve my problem?
Thanks!
EDIT:
The interface holding the Lines property and the class implementing the interface(one of many):
interface IReport
{
string Header { get; set; }
IList<IReportLine> Lines { get; set; }
}
public class Report : IReport
{
public string Header
{
get;
set;
}
public IList<IReportLine> Lines
{
get;
set;
}
}
The DataContext of the DataGrid is IReport object.
So I can't Change
public IList<IReportLine> Lines { get; set; }
to
public IList<ReportLine> Lines { get; set; }
Instead of defining members in interface, make the list to be more verbose. You gotta tell dataGrid at least some specific type so that it can look for properties in it.
Change
public IList<IReportLine> Lines { get; set; }
to
public IList<ReportLine> Lines { get; set; }
UPDATE
Like I mentioned above, if you want columns to be auto generated, you gotta supply some specific type.
Consider scenario where you have another class say AnotherReportLine implementing IReportLine:
public class AnotherReportLine : IReportLine
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
Now, you can add both class instances in Lines collection like this:
Lines = new List<IReportLine>();
Lines.Add(new ReportLine() { A = "A1", B = "B1" });
Lines.Add(new AnotherReportLine() { A = "A1", B = "B1", C = "C1" });
What should be the columns list now?
A | B OR A | B | C.
WPF engine cannot infer that without your help.
That brings you down to three possible ways:
Move properties to interface.
Make the list of more specific type.
Last set AutoGenerateColumns to False and provide your own list of columns you want to show.

Which one is a better data design or object model?

Overview
I am designing a mechanism for generating dynamic controls in an ASP.NET MVC application that uses ADO.NET Entity Framework. However, my question has nothing to do with MVC and a little to do with the Entity Framework. It is about comparing two object models.
Problem Statement
In my app, a user must have the ability to interact with Web page A to specify that he wants to add such and such HTML controls to Web Page B.
When he browses Web Page B next, he must see those controls and be able to use them.
What Is Not The Challenge
I have written the code to generate the controls. That was the easy part. I used the Tag Builder, Partial Views, HtmlHelper extensions and Display & Editor templates.
The Challenge
The challenge is in arriving at a database design and an object model generated by Entity Framework to hold the metadata about the controls that need to be generated.
I have come up with a database design as shown below:
You may ignore the User and Permissions tables. They are not relevant to our discussion.
Entity Framework generates the following entities based on the above database design.
Let's call my database design as Design Option A.
I would have wanted a design that looked more like this:
Let's call this second design as Design Option B.
The code (stripped down version) for this second option would look like this:
namespace DynamicControls
{
public class DynamicControlGroup
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Controller { get; set; }
public IEnumerable<string> Actions { get; set; }
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; }
public User CreatedByUser { get; set; }
public DateTime CreationDateTime { get; set; }
public User LastModifiedBy { get; set; }
public DateTime ModificationDateTime { get; set; }
// Navigational
public ICollection<DynamicControl<T>> DynamicControls { get; set; }
}
public class DynamicControl<T>
{
public long Id { get; set; } //db Id
public string HtmlId { get; set; }
public bool ValueRequired { get; set; }
public virtual ControlType ControlType { get; protected set; }
// Every control is capable of having a default value but of a different
// type. Most controls have default values of type text (string). The
// multi-select ones (checkboxes, multi-select lists, etc.) have a default
// value of type IEnumerable<string>. So, I want to leave this generic.
// But I am not that hung-up on this. I am fine if I am required to move
// this property DefaultValue from the base class and make it a concrete
// (not generic) property for each individual child class.
// Mostly I just want the heirarchy. And before that, I want to know
// if it is a good idea to model this heirarchy. Or is it better to just
// work with what my Entity Framework produced for my db?
// Should I change my db? I can because I thought-up the design for
// those tables.
public virtual T DefaultValue { get; set; }
// Navigational
public DynamicControlGroup DynamicControlGroup { get; set; }
}
public class TextBox : DynamicControl<string>
{
public override ControlType ControlType
{
get
{
return DynamicControls.ControlType.TextBox;
}
}
public string Label { get; set; }
public int MaxLength { get; set; }
}
public class PasswordControl : TextBox
{
public override ControlType ControlType
{
get
{
return DynamicControls.ControlType.Password;
}
}
}
public class TextArea : TextBox
{
public override ControlType ControlType
{
get
{
return DynamicControls.ControlType.TextArea;
}
}
public int Rows { get; set; }
}
public class DropDownList: DynamicControl<string>
{
public override ControlType ControlType
{
get
{
return ControlType.DropDownList;
}
}
// I want something like this. That I should be able to say
//
// myDropDownListObject.Options...
//
// You'll notice that given my current database design, I have
// no direct way of accessing the options of a, say, drop down list.
// To do that, I have to make a round-about Linq query.
public ICollection<DynamicControlOption> Options { get; set; }
}
public class DynamicControlOption
{
public long Id { get; set; } // db Id
public string OptionHtmlId { get; set; }
public string OptionValue { get; set; }
public string OptionText { get; set; }
// Navigational property
public DynamicControl<IEnumerable<string>> TheControlWhoseOptionIAm { get; set; }
}
public class User
{
}
public class Permission
{
}
public enum ControlType
{
TextBox,
TextArea,
Password,
RadioButton,
Checkbox,
DropDownList,
MultiSelectList,
DatePicker,
TimePicker,
DateTimePicker
}
}
My Question
1) I feel that I'd like Design Option B better. Am I feeling right?
2) I know I can work with Design Option A just as fine but it'll involve a little round-about way to do some things. For example, to get all the options for a drop down list, there's not navigational property on the DropDownList class in Design Option A. I'll have to write a round-about Linq query to do that.
3) Is it possible to have Entity Framework come close to generating Design Option B? How? What changes will I need to make to my database design to achieve that?
Now we are working on a Project like this at our company...
If I got your meaning correctly and If I were you...I implemented inherited structure as my database design like below.
Now you Classes are inheritance but your database design is not.
I have removed Id in TextBox and I have put ControlId as PK and FK in the same time. (not just FK).
in fact,ControlId is both PK for TextBox and FK from DynamicControl
and also this way for PasswordControl and TextArea
and Now ControlId in TextBox is not Identity. It gets it's ControlId from DynamicControl
I also accept Design Option B .I'm always more comfortable than using Design Option A.in my idea It's true and main structure

How to return hierarchical graph with RIA services

I would like a DomainService as follows:
[EnableClientAccess]
public class FamilyService : DomainService
{
public IQueryable<Person> GetPeople() // for the time being fake out a set of people
{
var people = new[]{ new Person(), ... };
return people.AsQueryable();
}
}
The Person class should be simple enough:
public class Person
{
[Key]
public Guid Id { get; set; }
public Person Parent { get; set; }
public String Name { get; set; }
public Person[] Children { get; set; }
}
In the Silverlight client, the Person class that is generated does not include the Parent or Children properties. What am I missing?
(Perhaps I should point out that while this is obviously a mock example, I am planning on using a loosely coupled approach, that this mimics. In fact most of my data doesn't reside in a database at all A significant majority of the RIA samples use an end-to-end parity of model from the database to the UI, which is not an option in my case.)
Try adding the [Include] attribute to the Parent & Children properties.
public class Person
{
[Key]
public Guid Id { get; set; }
[Include]
public Person Parent { get; set; }
public String Name { get; set; }
[Include]
public Person[] Children { get; set; }
}
If the Person class is coming out of the DB (in your real world app) and you are using EF, then you need to force them to be loaded eagerly, using the .Include() method.

EF 4.1 Codefirst WPF Eager Loading Data Binding

I am having problems databinding to EF code first. I need to be using Eager Loading, but I am running into some issues with databinding. I have the following classes:
public class Context : DbContext
{
DbSet<A> As;
DbSet<B> Bs;
DbSet<C> Cs;
}
public class A
{
public ICollection<B> Bs { get; set; }
public string Name { get; set; }
}
public class B
{
public ICollection<C> Cs { get; set; }
public string Name { get; set; }
}
public class C
{
public string Name { get; set; }
}
I am data binding Context.As to a Treeview, using the below code:
Context.As.Load();
tvItems.ItemsSource = Context.As.Local;
This works as expected, however, it does not automatically load the child properties, Bs, and subsequently, Cs. So, I found that lazy loading can help with this, like so:
Context.As.Load();
tvItems.ItemsSource = Context.As.Include(u=>u.Bs);
From my reading, this should automatically load at least the first level of child properties. However, this will not data bind, as I did not use .Local
.Include() returns IQueryable, which does not support .Local. I can use .ToList(), but this will not automatically update when I add items.
So, how the hell am I supposed to be doing this?
You could try this:
Context.As.Include(a => a.Bs).Load();
tvItems.ItemsSource = Context.As.Local;

Resources