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.
Related
I am working on a WPF application that follows an MVVM pattern. Inspite of moving the validation into services, I am ending up with a fat viewmodels that runs for several lines of code(in my case close to 1000 lines).
I have added the interface for the viewmodel here. I got a few collections exposed as combo and based on the combo selection, I have to perform validation/invoke service/apply filtering to other combos
public interface ISampleViewModel {
ObservableCollection<InstrumentDto> Collection1 { get; set; }
ObservableCollection<TenderViewConfigDetailViewModel> Collection2 { get; set; }
ObservableCollection<TenderViewConfigDetailViewModel> Collection3 { get; set; }
ObservableCollection<TenderViewConfigDetailViewModel> Collection4 { get; set; }
ObservableCollection<TenderViewConfigDetailViewModel> Collection5 { get; set; }
TenderViewConfigDetailViewModel SelectedViewConfigDetail { get; set; }
int SelectedTenderViewIndex { get; set; }
int SelectedInstrumentsViewIndex { get; set; }
SortableCollection<TenderViewToInstrumentViewModel> CurrentInstruments { get; set; }
TenderViewToInstrumentViewModel SelectedInstrumentForTenderView { get; set; }
InstrumentDto SelectedInstrument { get; set; }
bool IsAllInstrumentsFocused { get; set; }
ICommand ApplyChangesCommand { get; }
ICommand AddTenderPanelViewCommand { get; }
ICommand DeleteTenderPanelViewCommand { get; }
ICommand ModifyTenderViewVisiblityCommand { get; }
ICommand AddInstrumentsToPanelViewCommand { get; }
ICommand DeleteInstrumentsFromPanelViewCommand { get; }
ICommand MoveUpTenderListViewCommand { get; }
ICommand MoveDownTenderListViewCommand { get; }
ICommand MoveUpInstrumentsCommand { get; }
ICommand MoveDownInstrumentsCommand { get; }
bool IsValidModel { get; }
void PublishTenderViewConfigChanges(TenderViewConfigDetailViewModel viewModel,EventActionType actionType);
}
The above set of functionality make my viewmodel bulkier. How can I avoid avoid it? I cant think of breaking the functionality into smaller controls as they are dependent? Am I missing something here?
If you have stored in the ViewModel properties that can be isolated in separate classes, it is best to move them to a separate Model. Large number of properties pretty loads ViewModel, for each type of properties you should create your Model. Although on this occasion there is some debate, I believe there is nothing wrong if in the ViewModel will be links to several Models. On this subject you can see this answers:
In MVVM, is every ViewModel coupled to just one Model?
Example of using separate models:
Model
public class MainMenuModel : NotificationObject // Here also implemented INotifyPropertyChanged interface
{
private bool _buttonIsEnabled = true;
public bool ButtonIsEnabled
{
get
{
return _buttonIsEnabled;
}
set
{
_buttonIsEnabled = value;
NotifyPropertyChanged("ButtonIsEnabled");
}
}
}
ViewModel
public class MainMenuViewModel
{
private MainMenuModel _mainMenuModel = null;
public MainMenuModel MainMenuModel
{
get
{
return _mainMenuModel;
}
set
{
_mainMenuModel = value;
}
}
...
public MainMenuViewModel()
{
MainMenuModel = new MainMenuModel();
}
}
View
<Button IsEnabled="{Binding Path=MainMenuModel.ButtonIsEnabled}" ... />
The only thing that can be left on the side of the ViewModel, it Commands and IDataErrorInfo interface implementation, although implementation of IDataErrorInfo can also be moved to the side of the Model.
Also, if the implementation of Command takes a lot of space, you can create separate function / procedure that can be called such Helper and place in suitable class. Next, in Command did not write the whole implementation, it's necessary refer to this method.
For example:
private ICommand _findCommand = null;
public ICommand FindCommand
{
get
{
if (_findCommand == null)
{
_findCommand = new RelayCommand(param => this.Find(), null);
}
return _findCommand;
}
}
private void Find()
{
// Here instead of writing large code,
// moving find logic to separate static class
SomeHelper.FindPerson(MainModel.SearchName);
}
Therefore Command in this case is a wrapper for a call method in ViewModel.
This is one of the class definitions within a DLL I use in my WCF service.
[DataContract]
public class ScenarioXML
{
[DataMember(Order = 1)]
public long? TNRScenario { get; set; }
[DataMember(Order = 2)]
public long? TNRProject { get; set; }
[DataMember(Order = 3)]
public int? Priority { get; set; }
// ...
[DataMember(Order = 19)]
public List<ScenarioAssetXML> ScenarioAssets { get; set; }
[DataMember(Order = 20)]
public List<CalendarXML> Calendars { get; set; }
[DataMember(Order = 21)]
public ScenarioTriggerCollectionXML ScenarioTriggerCollection { get; set; }
}
I'm using DataContract instead of ProtoContract, so I can expose this class to a Silverlight project through a WSDL, and still use Protobuf-net for serialization.
Now, when I use the following code in my WCF service, the original "scenario" and the "restoredModel" are identical.
MemoryStream msTestString = new MemoryStream();
Serializer.Serialize<ScenarioXML>(msTestString, scenario);
string memento = Convert.ToBase64String(msTestString.ToArray());
byte[] byteAfter64 = Convert.FromBase64String(memento);
MemoryStream afterStream = new MemoryStream(byteAfter64);
ScenarioXML restoredModel = Serializer.Deserialize<ScenarioXML>(afterStream);
However, when I use the same code in Silverlight, the TNRScenario value is null.
Similarly, the TNRScenarioAsset property of the objects in the ScenarioAssets list are null.
[DataContract]
public class ScenarioAssetXML
{
[DataMember(Order = 1)]
public long? TNRScenarioAsset { get; set; }
[DataMember(Order = 2)]
public long? TNRScenario { get; set; }
[DataMember(Order = 3)]
public string Asset { get; set; }
[DataMember(Order = 4)]
public string Action { get; set; }
}
When I make the first property a string, it completely vanishes after (de)serialization. When I put a dummy bool as a first property, the bool is there, but the second property, in this case ScenarioAssets, is still null. There's something weird going on here...
Am I doing somethign wrong, or is this a bug?
Edit:
You're right Marc! The orders get messed up in the WSDL-generated code.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="ScenarioXML", Namespace="http://schemas.datacontract.org/2004/07/DataCollectionDLL")]
public partial class ScenarioXML : object, System.ComponentModel.INotifyPropertyChanged {
private System.Nullable<long> TNRScenarioField;
private System.Nullable<long> TNRProjectField;
private System.Nullable<int> PriorityField;
//...
[System.Runtime.Serialization.DataMemberAttribute()]
public System.Nullable<long> TNRScenario {
get {
return this.TNRScenarioField;
}
set {
if ((this.TNRScenarioField.Equals(value) != true)) {
this.TNRScenarioField = value;
this.RaisePropertyChanged("TNRScenario");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(Order=1)]
public System.Nullable<long> TNRProject {
get {
return this.TNRProjectField;
}
set {
if ((this.TNRProjectField.Equals(value) != true)) {
this.TNRProjectField = value;
this.RaisePropertyChanged("TNRProject");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(Order=2)]
public System.Nullable<int> Priority {
get {
return this.PriorityField;
}
set {
if ((this.PriorityField.Equals(value) != true)) {
this.PriorityField = value;
this.RaisePropertyChanged("Priority");
}
}
}
//...
However, I'm not sure how to correctly implement that partial class? I created it in the WCF service, but that seems to confuse the compiler. Getting the following errors:
Error 6 'DataCollectionDLL.ScenarioXML' does not contain a definition for 'TNRScenario' and no extension method 'TNRScenario' accepting a first argument of type 'DataCollectionDLL.ScenarioXML' could be found (are you missing a using directive or an assembly reference?)
Error 2 Cannot convert type 'DataCollectionDLL.ScenarioXML [c:\Projects\Flowcontrol 1.7.1.1\flowcontrolFC.Web\Libraries\DataCollectionDLL.dll]' to 'DataCollectionDLL.ScenarioXML [C:\Projects\Flowcontrol 1.7.1.1\flowcontrolFC.Web\DAL\DataCollectionClasses\ScenarioXML.cs(31)]'
Then tried it in the Silverlight project, which compiles fine but that doesn't solve the problem. Results are the same.
The partial class I created:
namespace DataCollectionDLL
{
[ProtoContract]
[ProtoPartialMember(1, "TNRScenario")]
[ProtoPartialMember(2, "TNRProject")]
[ProtoPartialMember(3, "Priority")]
//...
[ProtoPartialMember(21, "ScenarioTriggerCollection")]
partial class ScenarioXML
{
}
}
It sounds like you used WSDL-generated proxies; that can confuse things a little bit, because protobuf-net really really cares what the numbers are, and WSDL can sometimes play fast and loose with those. It would really help if I could see the WSDL-generated proxy classes (in the .designer.cs), but I'm going to assume this is the problem. Fortunately, most code-generators use partial class, so you can add your own partial class in a separate file to add extra information into the same type, in particular: more attributes. For example:
namespace The.Same.Namespace
{
[ProtoContract]
[ProtoPartialMember(1, "TNRScenario")]
[ProtoPartialMember(2, "TNRProject")]
// ...
[ProtoPartialMember(21, "ScenarioTriggerCollection")]
partial class ScenarioXML { }
}
This will get merged by the compiler into the ScenarioXML class, and should allow protobuf-net to use the correct numeric identifiers for each property.
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
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)
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;