I'm new to WPF and I'm trying to implement MVVM model into my WPF application. I have this scenario: a Customers model, a customer view, a CUstomersViewModel and a Dbcontext class.
Model Customers.cs
public partial class Customers
{
public int Id { get; set; }
public string Customer { get; set; }
}
MyDbContext.cs
public partial class MyDbContext: DbContext
{
public MyDbContext()
{
}
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
public virtual DbSet<Customers> Customers { get; set; }
public virtual DbSet<Users> Users{ get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
// ..............
}
}
CustomersViewModel.cs
class CustomersViewModel
{
public ObservableCollection<Customers> Customers { get; set; }
public CustomersViewModel()
{
using (MyDbContext db = new MyDbContext())
{
Customers = new ObservableCollection<Customers>(db.Customers.ToList());
}
}
}
In my view I'm binding the ViewModel to a combobox:
<Window.Resources>
<ViewModels:CustomersViewModel x:Key="CustomerViewModel"/>
</Window.Resources>
...
<ComboBox x:Name="cboCustomers" Grid.Row="2"
DataContext="{StaticResource CustomerViewModel}"
ItemsSource="{Binding Customers}"
DisplayMemberPath="Customer"/>
This works fine. However (this might be a silly question), if I want to add more queries, such as retrieve customers by Id, grouping customers by a certain column or update a customer, where would I need to add these?
Customers = new ObservableCollection<Customers>(db.Customers.Where(....))..
In the Viewmodel class? The constructor of the ViewModel, at the moment, gets all customers.
if I want to add more queries, such as retrieve customers by Id, grouping customers by a certain column or update a customer, where would I need to add these?
For example in a service that you inject the view model with, e.g.:
class CustomersViewModel
{
private readonly ICustomerService _customerService;
public ObservableCollection<Customers> Customers { get; set; }
public CustomersViewModel(ICustomerService customerService)
{
_customerService = customerService;
}
}
The view model can then invoke operations on the service based on user interactions such as for example button clicks.
The service implementation is responsible for connecting to the database, for example using Entity Framework through a data access layer.
Related
I have two datagrids in a single view but the collections which are ItemsSource of these datagrids are in different View Models. So is it possible to bind these two datagrids with the collections in two different View Models?
Go for a view model combining both:
public class ViewModelA {
public ObservableCollection<CustomClass> Items { get; set; }
/* properties, etc. */
}
public class ViewModelB {
/* properties, etc. */
}
public class CombiningViewModel {
public ViewModelA A { get; set; }
public ViewModelB B { get; set; }
}
Binding can be done like
<DataGrid ItemsSource="{Binding A.Items}">
<!-- Sample, not complete -->
</DataGrid>
No, not directly. You do have options though:
You could set the DataCOntext of the view to itself, then expose each viewmodel through a separate property and bind to those properties:
public class MyView : Window
{
public MyView()
{
this.DataContext = this;
}
public ViewModel1 FirstViewModel { get; set; }
public ViewModel2 SecondViewModel { get; set; }
}
Or you could make a wrapper viewmodel which either extends (inherits from) one of the viewmodels, or wraps them both and surfaces the appropriate properties:
public class MyCompositeViewModel
{
public ViewModel1 FirstViewModel { get; set; }
public ViewModel2 SecondViewModel { get; set; }
}
You can set the DataContext for each DataGrid rather than for the container view.
<Grid>
<DataGrid ... DataContext="..." />
<DataGrid ... DataContext="..." />
</Grid>
Or don't use a DataContext and Bind to the models directly
<DataGrid ItemsSource="{Binding Source={StaticResource ...}}" />
I am using the MVVM pattern in my project;
In my project I have a CheckedComboBoxEdit then bind to a Person List;
Public Class Person
{
Public Int Id { get; set; }
Public string Name { get; set; }
}
When User select some Items in CheckedComboBoxEdit, how can I get CheckedComboBoxEdit SelectedItems in my ViewModel?
You need a property on your ViewModel that binds to the CheckedComboBoxEdit SelectedItems property. You should probably look at related DevExpress posts.
<CheckedComboBoxEdit x:Name="cbPeople" SelectedItems="{Binding SelectedPeople}" ... />
Ok I'll make this very simple! Here are viewmodels :
public class ObjectsModel
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private string _objectName;
public string ObjectName
{
get
{
return _objectName;
}
set
{
if (value != _objectName)
{
_objectName = value;
PropertyChanged(this, new PropertyChangedEventArgs("ObjectName"));
}
}
}
public IEnumerable<Object> Objects {get;set;}
public ICommand AddCommand { get; private set; }
public ICommand SaveChangesCommand { get; private set; }
myDomainContext context = new myDomainContext();
public ObjectsModel()
{
objects = context.Objects;
context.Load(context.GetObjectsQuery());
}
}
public class InventoryModel
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public IEnumerable<Inventory> Inventories {get;set;}
public ICommand AddCommand { get; private set; }
public ICommand SaveChangesCommand { get; private set; }
myDomainContext context = new myDomainContext();
public ObjectsModel()
{
objects = context.Objects;
context.Load(context.GetObjectsQuery());
}
}
So what I'm trying to do is in my second form where I want to add an inventory for an object, I have to select the object in a combobox. The question is, how do I fill my combobox? Create another instance of the "ObjectsModel" in the InventoryModel? or use another "context" where I would query the other table? Or is there an easier Xaml approach? If I'm not clear, tell me I'll put more examples/code.
tx a lot!
You want to bind the contents of the combobox to a list of items provided by your ViewModel and bind the selected item to another property on the same ViewModel.
Please get into the habit of naming actual view models to end in "ViewModel", rather than "Model", so they do not clash with your other "real" models. It actually looks like you are binding directly to your business models instead of ViewModels (which is not good).
I have a simple example where I'm creating a View consisting of a list box, and the list box displays a bunch of items. I'm wondering if I'm going about the creation of the View Model and Model classes correctly here. Use whatever value of correctly works in this context, I understand it's a bit subjective, but my current solution doesn't feel right. Here's a simplified version.
The ViewModels and Models:
namespace Example
{
public class ParentViewModel
{
public ParentViewModel()
{
// ... Create/Consume ChildViewModel * n
}
public List<ChildViewModel> ChildViewModels { get; set; }
}
public class ChildViewModel
{
public ChildViewModel()
{
// ... Create/Consume ChildModel
}
public ChildModel Model { get; set; }
}
public class ParentModel
{
public List<ChildModel> ChildModels { get; set; }
public ParentModel()
{
// ... Create/Consume ChildModel * n;
}
}
public class ChildModel
{
public ChildModel()
{
// ... Contains actual data.
}
public string Data { get; set; }
}
}
The View:
<Window x:Class="Example.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Example="clr-namespace:Example" Title="View" Height="300" Width="300"
DataContext="{StaticResource TheViewModel}">
<Window.Resources>
<Example:ParentViewModel x:Key="TheViewModel" />
</Window.Resources>
<Grid>
<ListBox Height="261" HorizontalAlignment="Left" Name="listBox1" VerticalAlignment="Top" Width="278" ItemsSource="{Binding ChildViewModels}"/>
</Grid>
In the proper code, the listbox will use a data template to display the child view models. But as you can see I'm not sure how the to instantiate the child related objects. It feels like the ParentViewModel will have a reference to the ParentModel and create ChildViewModel objects based on the ParentModel's ChildModel objects. Now I've said that it doesn't sound so daft, but I'd be interested in your thoughts.
You are on the right track.
The parent model would naturally contain a list of child models, e.g. a customer having multiple orders.
When ParentViewModel is created and loaded by a third-party, it is passed a ParentModel. Then the ParentViewModel will:
Assign the ParentModel to a local variable
Create a ChildViewModel for each ChildModel by passing the
ChildModel to the ChildViewModel constructor
Add each of those ChildViewModels to a list
By the way, you want
public List<ChildViewModel> ChildViewModels { get; set; }
to be
public ObservableCollection<ChildViewModel> ChildViewModels { get; set; }
I have a WPF combobox that I would like to bind to an observable collection of Teams on my ViewModel class e.g.
class Team
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
}
class ViewModel
{
public ObservableCollection<Team> Teams { get; set; }
public IDictionary<int, Image> CountryFlags { get; set; }
}
I'd like to have the combobox display the flag and name of each team, what is the best way to do this?
I don't want to add the image directly to the team object if I can avoid it and would be happy to move the CountryFlags lookup to another class if need be.
You'll need to make a custom IValueConverter for this. Basically, you'll want to have the converter convert from Team -> Image, and have it do the lookup within the Dictionary based on the CountryId in the Team.