HierarchicalDataTemplate Link By Parent - silverlight

I want bind my treeview. There are a lot of samples binding treeview by object, which contains children collection. I've got domain having just Parent pointer.
public class Service : BaseDomain
{
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual Service Parent { get; set; }
}
Can I bind collection of this objects to my treeView. Thanks

It's not possible with HierarchicalDataTemplate, but you could create custom convertedr for ItemsSource binding. In general case converting such structure to tree might be resource intensive task (particularly it requires that treeview grabs all your data before displaying tree root).

Related

How to bind WinForms' DataGridView to EF navigation property (collection) in master-detail scenario?

I have a databinding problem in Windows Forms.
Here's the part of the EF model that is relevant for the story:
namespace Model
{
class Person
{
[Key]
public int Id { get; set; }
public String Name { get; set; }
public virtual ICollection<Receipt> Receipts { get; set; }
}
class Receipt
{
[Key]
public int Id { get; set; }
public DateTime Timestamp { get; set; }
public double Value { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
}
There is a BindingSource called peopleBindingSource that is set to class Model.Person. In code behind, I do this:
db.People.Include(p => p.Receipts).Load();
peopleBindingSource.DataSource = db.People.Local.ToBindingList();
Textbox has its DataBindings set to peopleBindingSource as DataSource and Name as the property.
When I run the application, the binding navigator works correctly, showing different people as I click previous and next buttons. The textbox with the person's name is also populated correctly.
Now, here comes the problem:
On the same form, there is a DataGridView. I want to show a row for each of the Receipt of currently selected Person.
I've tried to bind dataGridView's DataSource to Receipts navigation property of peopleBindingSource.
I have expected that the gridview will update its DataSource to the appropriate collection of receipts just as the textbox updates its Text property on navigation change. The setup is basicly the same.
The thing is, no error is thrown, and the grid remains empty (it doesn't even create the columns header).
Why doesn't this binding work and can this be done from within the designer? How to correctly set up binding (without programatically handling change event on peopleBindingSource and setting grid's DataSource manually from peopleBindingSource.Current)?
I have found the solution to the problem.
The thing is that DataGridView can't bind to ICollection<Receipt> so the solution was to change the navigation property to BindingList<Receipt>. Then the designer showed the property correctly.

WPF Listbox Items

I have a ListBox control that contains the names of files inside a directory.
How would I iterate though the controls and get those names? I've tried:
for (int i = 0; i < listboxFileGroups.Items.Count; i++)
{
// I don't want to use properties that start with Selected
// Here is what I was looking for
string textItem = listboxFileGroups.Items[i].ToString();
}
Any suggestions?
You may want to explore an MVVM approach.
In one of your view model classes, you can have an ObservableCollection<string>:
public ObservableCollection<string> StuffForListBox { get; set; }
Populate that ObservableCollection with what you want to get displayed in the ListBox.
In the code-behind of the UserControl or Window in which you have the ListBox, set the DataContext to an instance of the class containing StuffForListBox seen above.
this.DataContext = new MyClass();
Alternatively you could also create a datatemplate for the usercontrol / window which will automagically wire up the datacontext with your view model.
Since you only mentioned that you want to display the files in a directory (not including sub-directories), you just need to bind the ItemsSource to StuffForListBox.
<ListBox ItemsSource="{Binding StuffForListBox}" ... >
To iterate through the strings displayed in the ListBox you just need to iterate through the ObservableCollection.
If you don't want to bother with MVVM or if that is some third party listbox, you can try grabbing the ItemsSource in the codebehind and loop through that but I'd certainly recommend MVVM. It'll make your life easier.
Now, if you wanted to get a little crazier and display things like subfolders then an ObservableCollection<string> won't cut it. You would need to create a class that contains children to model how a folder has files and subfolders.
public class DemoItem
{
public string Name { get; set; }
public DemoItem Parent { get; set; }
public ObservableCollection<DemoItem> Children { get; set; }
public bool IsSelected { get; set; }
}
...and then base your observable collection thats bound to the listbox on the above class.
If and when you do that, your listbox won't display the items properly until you create a DataTemplate But I suppose that't outside of the scope of the question :p

Creating the Model part of MVVM

I am working on an app where I am trying to use MVVM for the first time. After reading some things, I think I might have misunderstood what goes in the Model.
All my app does right now is make a request to get some data, display it, allow the user to edit it, and save it if changes were made.
Here is an example of my current setup. I read some Employee data, which returns groups of employees ("Managers", "VPs", etc.). Each group contains a list of people. I created an interface to represent the groups:
public interface IEmployeeGroup : INotifyPropertyChanged
{
bool IsDirty { get; set; }
string GroupName { get; set; }
ObservableCollection<IPerson> People { get; set; }
}
public interface IPerson : INotifyPropertyChanged
{
bool IsDirty { get; set; }
string PersonName { get; set; }
int Id { get; set; }
}
I then create concrete EmployeeGroup and Person classes implementing those interfaces. And thats all they do, expose the specified properties.
That is all I have for my model.
My view model implements the below interface:
public interface IEmployeeGroupsViewModel
{
ICommand AddEntryCommand { get; }
ICommand SaveCommand { get; }
ObservableCollection<IEmployeeGroup> EmployeeGroups { get; set; }
ObservableCollection<IPerson> People { get; set; }
}
The view model makes the call to get the actual data, creates the EmployeeGroup and Person objects, and then returns them in properties for the view to bind to. When the user wants to save his changes, the view model makes the call to persist the changes.
Am I putting too much in my view model, which should be in the model instead? Right now my model does nothing, they are just the classes that represent the objects.
If I am off track here, can someone give me some advice? How would I change my above scenario for example?
Thank you.
There's nothing wrong with your approach. You are free to either expose mapped model properties from your view model if they require formatting, or you can expose your model directly from your view model if no changes need to be made.
MVVM is about testability, not pattern purity. As long as what you are doing works, you can always refactor later.
That looks right to me.
I could be wrong, but I don't really see a benefit from making your view model interfaces derive from INotifyPropertyChanged. That seems like unnecessarily coupling together two things that don't really have any intrinsic relationship to one another. I'd just declare the PersonViewModel class (for instance) as:
public class PersonViewModel : IPerson, INotifyPropertyChanged

Entity Framework CTP5 Code First, WPF - MVVM modeling

I have my model all setup for my WPF application and working with entity framework ctp5 code first, here's a sample model class:
public class Task
{
public int ID { get; set; }
public int Index { get; set; }
public string Content { get; set; }
public int Indentation { get; set; }
public DateTime Start { get; set; }
public decimal Effort { get; set; }
public decimal CompletedEffort { get; set; }
public decimal Cost { get; set; }
}
What would be the recommended way to build my view model? My view models will implement INotifyPropertyChanged, I do not want the model classes to have any UI specific code - so that they can be easily reused in other apps.
Should I make all of the model properties virtual then override them in the view model? (seems like a lot of unnecessary coding...) Would EF code first play nice with this type of format?
Edit
This is a somewhat similar question In MVVM should the ViewModel or Model implement INotifyPropertyChanged? however, the only solutions appear to be adding in what I consider to be UI logic into the model. Perhaps I can add some sort of delegate to the model and hook into that from the viewmodel, which will in turn use INotifyPropertyChanged... something like this?
public class Task
{
public delegate void HandleChange(string propertyName);
public HandleChange ChangeHandler;
public int ID
{
get
{
return ID;
}
set
{
if(ID != value)
{
ID = value;
ChangeHandler("ID");
}
}
}
...
What I am doing is to make an instance of my model class to a property in the ViewModel and then implement INotifyPropertyChanged directly on the Model for the Model properties and on the ViewModel only for the Model instance, like so:
public class Task : INotifyPropertyChanged
{
// Implementation of INotifyPropertyChanged
// Raising the PropertyChanged event in the Setters of all properties
}
public class TaskViewModel : INotifyPropertyChanged
{
private Task _task;
public Task Task
{
get
{
return _task;
}
set
{
if (_task != value)
{
_task = value;
RaisePropertyChanged("Task");
}
}
}
// INotifyPropertyChanged implementation
}
Then in XAML I bind directly to Model properties, for instance:
<TextBox Text="{Binding Task.Content}" />
(TaskViewModel would be here the DataContext for the View.)
I do this mainly to avoid this "lot of unnecessary coding" that you mention, and I could not find a drawback. (I make my model persistent with EF Code-First too.)
I know this is an old thread, but I was googling about this very topic and stumbled upon this blogs.msdn.com article: http://bit.ly/iE3KHI
In short, starting with CTP 4 of EF CodeFirst there is a new property of the CodeFirst dbSet object .Local. .Local is an ObservableCollection that implements INotifyPropertyChanged. So if you have a code first dbcontext that exposes a DbSet(Of Task) called Tasks you can set your forms data context to Tasks.Local.

Using a BindingSource in a UserControl

I have a UserControl with multiple fields that I would like to have bound to a BindingSource. I would also like the UserControl to expose some BindingSource property so that it can be dropped on a Form and be bound to the BindingSource on the form. Is there an easy way to do this? I realize that I can rebind all of the controls of the UserControl in its BindSource setter. But this seems wrong. Is there some BindingSource Proxy that will let me link the BindingSource in the user control to the BindingSource in the form?
As per your question, I can hardly get what you intend to do. Thus I will try my best to provide you with, I hope, interesting information on that matter.
First, let's consider the following UserControl in a Customer management software project.
public partial class CustomerManagementUserControl : UserControl {
public CustomerManagementUserControl() {
InitializeComponent();
_customerBindingSource = new BindingSource();
}
public IList<ICustomer> DataSource {
set {
_customerBindingSource.DataSource = value;
}
}
private BindingSource _customerBindingSource;
}
Second, let's consider the following Form which should be your Customer management form.
public partial class CustomerManagementForm : Form {
public CustomerManagementForm() {
InitializeComponent();
_customerUserControl = new CustomerManagementUserControl();
_customerUserControl.Name = #"customerUserControl";
}
private void CustomerManagementForm_Load(object sender, EventArgs e) {
// CustomersFacade is simply a static class providing customer management features and requirements.
// Indeed, the GetCustomers() method shall return an IList<ICustomer>.
// The IList type and typed IList<T> are both intended to be bindable as a DataSource for DataBinding.
_customerUserControl.DataSource = CustomersFacade.GetCustomers();
this.Controls.Add(_customerUserControl);
}
private CustomerManagementUserControl _customerUserControl;
}
If you're expecting to use CustomerManagementUserControl.DataSource property from within the Property window, please consider adding the following on top of your property definition.
[System.ComponentModel.DesignTimeVisible(true), System.ComponentModel.DesignerCategory("CustomerUserControl"), System.ComponentModel.Description("Sets the CustomerUserControl DataSource property")]
This is one way of doing what I guess you might want to do. On the other hand, if what you wish to do is to get the as most abstract as possible by setting a different type of object as your UserControl.BindingSource.DataSource property, then you will have to write a method which could detect the type of the object passed, then binding the properties accordingly. A nice way you could go, perhaps, is by Reflection, if you're comfortable working with it. In any possible way you may imagine working with such polymorphism features, you will have to write yourself an interface that all of your bindable objects will have to implement. This way, you will avoid unknown property names, and when will come the time to bind your UserControl's controls, you will be able to bind the correct property to the correct control and so forth.
Let's try the following:
public interface IEntity {
double Id { get; set; }
string Number { get; set; }
string Firstname { get; set; }
string Surname { get; set; }
long PhoneNumber { get; set; }
}
public interface ICustomer : IEntity {
}
public interface ISupplier : IEntity {
string Term { get; set; }
}
public sealed Customer : ICustomer {
public Customer() {
}
public double Id { get; set; }
public string Number { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
public long PhoneNumber { get; set; }
}
public sealed Supplier : ISupplier {
public Supplier() {
}
public double Id { get; set; }
public string Number { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
public long PhoneNumber { get; set; }
public string Term { get; set; }
}
Considering the above code, you could use the DataSource property of your UserControl to bind with an IEntity, so your property could like like this.
[System.ComponentModel.DesignTimeVisible(true), System.ComponentModel.DesignerCategory("CustomerUserControl"), System.ComponentModel.Description("Sets the CustomerUserControl DataSource property")]
public IList<IEntity> DataSource {
set {
_customerBindingSource.DataSource = value;
}
}
That said, if you wish to push even further, you could just expose your UserControl's controls DataBindings properties in order to set them on design-time. Considering this, you will want to expose your BindingSource as a public property either so that you may set it on design-time too, then choose your DataMember from this BindinSource.
I hope this helps you both a little or at least, give you some tracks for further searchings.
I know it's a late answer; however, it might be useful to someone else reading this post.
I have controls on a UserControl that are data-bound. I need to have a BindingSource on the UserControl in order to be able to bind the controls at design time. The "real" BindingSource, however, sits on the Form. In other words, the controls on the UserControl should behave as if they were sitting directly on the form (or on a ContainerControl on the form).
The idea behind this solution is to watch for the DataSourceChanged event of the "real" BindingSource and to assign its DataSource to the local BindingSource when it changes. In order to find the "real" BindingSource I let the Form (or Control) containing it implement the following interface:
public interface IDataBound
{
BindingSource BindingSource { get; }
}
We can watch for the ParentChanged event of a control in order to know when it has been added to a Form or a ContainerControl. The problem here is that this ContainerControl itself might not have been added to the Form (or another ContainerControl) yet at this time. In this case we subscribe to the ParentChanged event of the last parent we find in the parents chain and wait until this last parent has been added, an so on, until we find a Control or Form implementing IDataBound. When a IDataBound has been found, we subscribe to the DataSourceChanged event of its BindingSource.
public partial class MyUserControl : UserControl
{
private IDataBound _dataBoundControl;
private Control _parent;
public MyUserControl()
{
InitializeComponent();
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime) {
_parent = this;
SearchBindingSource();
}
}
private void SearchBindingSource()
{
if (_parent != null && _dataBoundControl == null) {
while (_parent.Parent != null) {
_parent = _parent.Parent;
_dataBoundControl = _parent as IDataBound;
if (_dataBoundControl != null) {
if (_dataBoundControl.BindingSource != null) {
_dataBoundControl.BindingSource.DataSourceChanged +=
new EventHandler(DataBoundControl_DataSourceChanged);
}
return;
}
}
// This control or one of its parents has not yet been added to a
// container. Watch for its ParentChanged event.
_parent.ParentChanged += new EventHandler(Parent_ParentChanged);
}
}
void Parent_ParentChanged(object sender, EventArgs e)
{
SearchBindingSource();
}
void DataBoundControl_DataSourceChanged(object sender, EventArgs e)
{
localBindingSource.DataSource = _dataBoundControl.BindingSource.DataSource;
}
}
If you wanted to do this all automatically you could look for the binding source from the parent form in the load event of your user control or something like that...
Dim components As Reflection.FieldInfo = typ.GetField("components", Reflection.BindingFlags.DeclaredOnly Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
Dim lstBindingSources As New List(Of BindingSource)
For Each obj As Object In components.Components
Dim bindSource As BindingSource = TryCast(obj, BindingSource)
If bindSource IsNot Nothing Then
lstBindingSources.Add(bindSource)
End If
Next
If lstBindingSources.Count = 1 Then
MyBindingSource.DataSource = lstBindingSources(0).DataSource
End If
If you assign the same object reference as the datasource on two bindingsources, the controls will not be updated consistently on the second bindingsource. Possibly, a compromise to the choices above is the following:
Temporarily add a bindingsource to the usercontrol and use the VS designer to set the bindings to the controls.
bring the designer.vb up in the code editor. Search for all the "DataBindings.Add" lines that were created by the designer. Copy them all to notepad.
delete the bindingsource from the designer and add a bindingsource reference in code. Add a property for the bindingsource with the same name as was used in the designer. In the setter for the property, paste all the lines from notepad above in step 2.
In the Load event of the form, assign the bindingsource of the form to the property on the user control. If the user control is embedded in another user control, you can use the handlecreated event of the parent control to do the same.
There is less typing and less typos because the VS designer is creating all those literal text property names.

Resources