?
--
I've been out of the .NET game for a few years now [pre 2005] and
starting a little project using the Entity Framework and WPF. My
understanding is that the MVVM pattern is the way to go nowadays, but
I've got a few questions.
This is a purely made up example, so forgive any UI design quirks, and
I'm leaving out a bunch of code just as the INotifyPropertyChanged
stuff.
1. Let's say I've got a heavy-ish model class called Report. I'd like
to create a Report browser type of viewer. I'd like the browser to
have a combobox / listbox / treeview / something where the user can
select the report to view, and a Report User Control that displays the
currently selected report. In all the examples I've seen, the
ReportBrowserViewModel would collection of Reports or ReportViewModels
which is bound to the combobox/listbox/treeview. Something like this:
ReportViewModel
{
ObervableCollection<Report> Reports;
}
The Report User Control's DataContext is a ReportViewModel which is
bound to the current ReportViewModel as set by the
ObservableCollections CurrentItem [I can't figure out how to get this
in code, just in the XAML].
I'd like to not have to bring all the Reports into memory [they're
heavy], so I'd like to just bring in a ReportHeader, which is a subset
of the Report data. In doing so, my ReportBrowserViewModel would look
something like this:
ReportBrowserViewModel
{
ObservableCollection<ReportHeader> ReportHeaders;
ReportViewModel CurrentReport;
}
I'd like the combobox/listbox/treeview to be bound to the
ReportHeaders, and when the ReportHeader's CurrentItem changes, I'd
like to set the CurrentReport to the appropriate Report [in doing so,
updating the bound ReportUserControl]
Is this how it's supposed to be done? If so, this leads to question 2.
2. In the above scenario, the ReportBrowserViewModel would need to get
a Report to fill the ReportViewModel. Is it appropriate for the
ReportBrowserViewModel to access the DAL to get the Report? If not,
how should the Report be obtained?
2a. In general, how is data supposed to be loaded into the ViewModel?
Something has to put the Model objects into the ViewModel. In my
example, should I load the ReportHeader via the Window, or have them
passed in?
3. Commands. Are Model modifying commands supposed to be placed in
the ViewModel? Things like adding a line item to a report? So I'd have
a Command:
AddLineItemToReportCommand : ICommand
{
public AddLineItemToReportCommand(Report report);
....
}
and the ReportViewModel would have a property:
AddLineItemToReportCommand addLineItem;
AddLineItemToReportCommand AddLineItem
{
get{
addLineItem = addLineItem ?? new
AddLineItemToReportCommand(this.Model);
addLineItem = addLineItem.Model == this.Model
? addLineItem
: new
AddLineItemToReportCommand(this.Model);
return addLineItem;
}
}
This would be creating a new Command instance every time the Model in
the ReportViewModel changes? This seems like a lot.
4. A more general generics question. If I have a generic class:
B<T> : INotifyPropertyChanged
{
T item;
T Item{
get{return item;}
set{
if(item==value)return; // Note, this doesn't work
item=value;
OnPropertyChanged("Item");
}
}
}
What's the appropriate method in the setter for checking if the new
value is equal to the old value? == doesn't work unless there's a
class constraint on T, and item.Equals(value) will throw an exception
in item or value are null. My current method is:
if(item == null && value == null)return;
if(item==null || value==null || !item.Equals(value))
{
item=value;...
}
But this seems excessive. There must be a better way.
starting a little project using the Entity Framework and WPF. My
understanding is that the MVVM pattern is the way to go nowadays, but
I've got a few questions.
This is a purely made up example, so forgive any UI design quirks, and
I'm leaving out a bunch of code just as the INotifyPropertyChanged
stuff.
1. Let's say I've got a heavy-ish model class called Report. I'd like
to create a Report browser type of viewer. I'd like the browser to
have a combobox / listbox / treeview / something where the user can
select the report to view, and a Report User Control that displays the
currently selected report. In all the examples I've seen, the
ReportBrowserViewModel would collection of Reports or ReportViewModels
which is bound to the combobox/listbox/treeview. Something like this:
ReportViewModel
{
ObervableCollection<Report> Reports;
}
The Report User Control's DataContext is a ReportViewModel which is
bound to the current ReportViewModel as set by the
ObservableCollections CurrentItem [I can't figure out how to get this
in code, just in the XAML].
I'd like to not have to bring all the Reports into memory [they're
heavy], so I'd like to just bring in a ReportHeader, which is a subset
of the Report data. In doing so, my ReportBrowserViewModel would look
something like this:
ReportBrowserViewModel
{
ObservableCollection<ReportHeader> ReportHeaders;
ReportViewModel CurrentReport;
}
I'd like the combobox/listbox/treeview to be bound to the
ReportHeaders, and when the ReportHeader's CurrentItem changes, I'd
like to set the CurrentReport to the appropriate Report [in doing so,
updating the bound ReportUserControl]
Is this how it's supposed to be done? If so, this leads to question 2.
2. In the above scenario, the ReportBrowserViewModel would need to get
a Report to fill the ReportViewModel. Is it appropriate for the
ReportBrowserViewModel to access the DAL to get the Report? If not,
how should the Report be obtained?
2a. In general, how is data supposed to be loaded into the ViewModel?
Something has to put the Model objects into the ViewModel. In my
example, should I load the ReportHeader via the Window, or have them
passed in?
3. Commands. Are Model modifying commands supposed to be placed in
the ViewModel? Things like adding a line item to a report? So I'd have
a Command:
AddLineItemToReportCommand : ICommand
{
public AddLineItemToReportCommand(Report report);
....
}
and the ReportViewModel would have a property:
AddLineItemToReportCommand addLineItem;
AddLineItemToReportCommand AddLineItem
{
get{
addLineItem = addLineItem ?? new
AddLineItemToReportCommand(this.Model);
addLineItem = addLineItem.Model == this.Model
? addLineItem
: new
AddLineItemToReportCommand(this.Model);
return addLineItem;
}
}
This would be creating a new Command instance every time the Model in
the ReportViewModel changes? This seems like a lot.
4. A more general generics question. If I have a generic class:
B<T> : INotifyPropertyChanged
{
T item;
T Item{
get{return item;}
set{
if(item==value)return; // Note, this doesn't work
item=value;
OnPropertyChanged("Item");
}
}
}
What's the appropriate method in the setter for checking if the new
value is equal to the old value? == doesn't work unless there's a
class constraint on T, and item.Equals(value) will throw an exception
in item or value are null. My current method is:
if(item == null && value == null)return;
if(item==null || value==null || !item.Equals(value))
{
item=value;...
}
But this seems excessive. There must be a better way.