Execute RaiseCanExecuteChanged from 'subclass' - wpf

So I have the following setup:
PLANNING:
public class Planning : ViewModelBase
{
public Planning()
{
AddNewActivityCommand = new RelayCommand(AddActivity, CanAddActivity);
}
public ObservableCollection<PlanningItem> PlanningItems { get; set; }
public PlanningItem SelectedPlan { get; set; }
#region AddNewActivity
public RelayCommand AddNewActivityCommand { get; private set; }
private bool CanAddActivity()
{
if (!PlanningItems.Any())
{
return true;
}
if (string.IsNullOrEmpty(PlanningItems[PlanningItems.Count - 1].Activities) != true ||
PlanningItems[PlanningItems.Count - 1].DhpRepresentativeSelected != null)
{
return true;
}
return false;
}
private void AddActivity()
{
PlanningItems.Add(new PlanningItem());
AddNewActivityCommand.RaiseCanExecuteChanged();
}
#endregion
}
PLANNING ITEM:
public class PlanningItem : ViewModelBase
{
private string _activity;
public ObservableCollection<OutreachUser> DhpRepresentativeSource
{
get
{
var userSource = new ObservableCollection<OutreachUser>();
using (var context = new Outreach_Entities())
{
var query = from a in context.UserInfoes
join b in context.PersonalInfoes on a.UserIdentity equals b.PersonIdentity
join c in context.PersonalTitles on b.TitleLink equals c.TitleIdentity into cGroup
from c in cGroup.DefaultIfEmpty()
select new OutreachUser
{
PersonLink = a.UserIdentity,
Username = a.Username,
FirstName = b.FirstName,
MiddleInitial = b.MiddleInitial,
LastName = b.LastName
};
foreach (var result in query)
{
userSource.Add(result);
}
return userSource;
}
}
}
public OutreachUser DhpRepresentativeSelected { get; set; }
public DateTime PlanningDate { get; set; }
public TimeSpan PlanningStart { get; set; }
public TimeSpan PlanningEnd { get; set; }
public int PlanningTotalHours { get; set; }
public string Activities
{
get
{
return _activity;
}
set
{
_activity = value;
RaisePropertyChanged(nameof(Activities), "", _activity, true);
}
}
}
I have a ListBox bound to the PlanningItems Observable Collection.
I want to be able to add a new item to the list if the following criteria are met:
The Planning Items Collection is empty.
The last item in the Planning Items Collection has a DhpRepresentativeSelected that is not null.
The last item in the Planning Items Collection has some text in the Activities string.
The first item is easy enough because I call AddNewActivityCommand.RaiseCanExecuteChanged(); after I add a new item from an empty list.
Now I need to call the AddNewActivityCommand.RaiseCanExecuteChanged(); from within the PlanningItem ViewModel, but it does not have access rights to the command.

Clueless pointed me to the answer.
What I did was inside of my Planning ViewModel I created an internal Method that called the AddNewActivityCommand.RaiseCanExecuteChanged() method. I think called that method from within the PlanningItems ViewModel.

Related

How to return a string in the dataGrid.ItemsSource when it contains a ICollection<Continent>

When im displaying my database table it contains a few collections and those dont display in the datagrid. a column is generated but it stays blank. I do not know where to implement this either.
Maybe this will help also to explain what i want to display in the column instead of the ICollection
static void Main(string[] args)
{
using (var db = new Whataboutthisfish())
{
Vis vis = db.Vissen.Find(2);
if(vis != null)
{
if(vis.Continenten != null)
{
string s = "";
if(vis.Continenten.Count() > 1)
{
var continentenLijst = vis.Continenten;
s = continentenLijst.First().Naam;
foreach (Continent c in vis.Continenten)
{
s += ", "+c.Naam;
}
}
else
{
s = vis.Continenten.First().Naam;
}
Console.WriteLine(s);
}
}
}
}
I would like to return 1 string containing each continent's name using a seperator.
Like: "North-America" if there's only 1 continent in the collection
Or: "North-America, South-America" and so on for multiple.
Classes;
[Table("Continenten")]
public partial class Continent
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Continent()
{
Vissen = new HashSet<Vis>();
}
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Naam { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Vis> Vissen { get; set; }
}
}
[Table("Vissen")]
public partial class Vis
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Vis()
{
Continenten = new HashSet<Continent>();
Verbanden = new HashSet<Verband>();
Waterlagen = new HashSet<Waterlaag>();
}
public int Id { get; set; }
[StringLength(200)]
public string Naam { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Continent> Continenten { get; set; }
}
The Xaml for grid:
<DataGrid x:Name="dataGrid" HorizontalAlignment="Left" VerticalAlignment="Top" RenderTransformOrigin="0.833,0.846" Margin="10,10,10,10"/>
In code behind:
using (var db = new Catattafish.Whataboutthisfish())
{
dataGrid.ItemsSource = db.Vissen.ToList();
}

How to use an object as a data source c#

I'm trying to figure out how to make an object data source where I can select which columns to display in Visual Studio and all that. Here's what I have so far, but I'm not sure what else I'm supposed to do?
public class ItemData
{
public string ItemName { get; set; }
public string Description { get; set; }
public string Quantity { get; set; }
public string ManuPartNumber { get; set; }
public string ListID { get; set; }
public string VendorRef { get; set; }
public string VendorName { get; set; }
public string EditSequence { get; set; }
public string UPC { get; set; }
}
public class ItemDataSource : IEnumerable<ItemData>
{
private ICollection<ItemData> list;
public ItemDataSource()
{
try
{
list = QBCom.GetItemList();
}
catch (Exception e)
{
list = new List<ItemData>();
}
}
public ItemDataSource(IEnumerable<ItemData> data)
{
list = data.ToList();
}
public IEnumerator<ItemData> GetEnumerator()
{
foreach (var item in list)
{
yield return item;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((IEnumerable<ItemData>)this).GetEnumerator();
}
}
I am not talking about ASP.net, I'm talking about stuff like DataTables and so forth. Just a regular winforms program.
I assume you want to bind to a DataGridView if so I would inherit from BindingSource and set the list to the DataSource. You can then set the datagridview DataSource to the object to view the columns in the visual studio properties window.
public class ItemDataSource : BindingSource
{
private ICollection<ItemData> list;
public ItemDataSource()
{
try
{
list = QBCom.GetItemList();
}
catch (Exception e)
{
list = new List<ItemData>();
}
this.DataSource = list;
}
public ItemDataSource(IEnumerable<ItemData> data)
{
list = data.ToList();
this.DataSource = list;
}
}

MVVM and DBContext - how to put it together?

I'm trying to follow the MVVM pattern, however I spent some good time on this issue, googled a lot and checked stackoverflow as well... No working example found so far.
Basically, I've a simple application and want to retrieve and write data to SQL server. Here's my code:
//Model
public class Visitor
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
//ViewModel
public class VisitorViewModel : ViewModelBase
{
public ObservableCollection<Visitor> _visitorDataCollection = new ObservableCollection<Visitor>();
public ObservableCollection<Visitor> VisitorDataCollection
{
get { return _visitorDataCollection; }
set { _visitorDataCollection = value; }
}
private string _firstName = "";
private string _lastName = "";
public string FirstName
{
get { return _firstName; }
set
{
if (value != _firstName)
{
_firstName = value;
OnPropertyChanged("FirstName");
}
}
}
public string LastName
{
get { return _lastName; }
set
{
if (value != _lastName)
{
_lastName = value;
OnPropertyChanged("LastName");
}
}
}
public VisitorViewModel()
{
}
}
}
//VisitorContext class that represents a database context
public partial class VisitorContext : DbContext
{
public VisitorContext()
: base()
{
}
public DbSet<VISITOR> Visitors { get; set; }
}
}
Nothing really fancy. However, I cannot put it "together". How to complete that to retrieve all visitors and add a new one?
Could someone point me to the right direction?
Just a simple example how make it all to life.
Add some commands to VM:
public ICommand Add {get; private set;}
In constructor:
public VisitorViewModel()
{
using(var context = new VisitorContext())
{
//fill collection with initial data from DbContext
context.Visitors.ToList().ForEach(_visitorDataCollection.Add);
}
//setup add command, here I'm using MVVM Light like you
Add = new RelayCommand(()=> {
using(var context = new VisitorContext())
{
_visitorDataCollection.Add(context.Visitors.Add(new Visitor {
FirstName = this.FirstName,
LastName = this.LastName //read values from model properties
});
}
});
}
That's it, all you need to do is bind this ViewModel to appropriate View.

MVC Persist Collection ViewModel (Update, Delete, Insert)

In order to create a more elegant solution I'm curios to know your suggestion about a solution to persist a collection.
I've a collection stored on DB.
This collection go to a webpage in a viewmodel.
When the go back from the webpage to the controller I need to persist the modified collection to the same DB.
The simple solution is to delete the stored collection and recreate all rows.
I need a more elegant solution to mix the collections and delete not present record, update similar records ad insert new rows.
this is my Models and ViewModels.
public class CustomerModel
{
public virtual string Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<PreferredAirportModel> PreferedAirports { get; set; }
}
public class AirportModel
{
public virtual string Id { get; set; }
public virtual string AirportName { get; set; }
}
public class PreferredAirportModel
{
public virtual AirportModel Airport { get; set; }
public virtual int CheckInMinutes { get; set; }
}
// ViewModels
public class CustomerViewModel
{
[Required]
public virtual string Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<PreferredAirporViewtModel> PreferedAirports { get; set; }
}
public class PreferredAirporViewtModel
{
[Required]
public virtual string AirportId { get; set; }
[Required]
public virtual int CheckInMinutes { get; set; }
}
And this is the controller with not elegant solution.
public class CustomerController
{
public ActionResult Save(string id, CustomerViewModel viewModel)
{
var session = SessionFactory.CurrentSession;
var customer = session.Query<CustomerModel>().SingleOrDefault(el => el.Id == id);
customer.Name = viewModel.Name;
// How can I Merge collections handling delete, update and inserts ?
var modifiedPreferedAirports = new List<PreferredAirportModel>();
var modifiedPreferedAirportsVm = new List<PreferredAirporViewtModel>();
// Update every common Airport
foreach (var airport in viewModel.PreferedAirports)
{
foreach (var custPa in customer.PreferedAirports)
{
if (custPa.Airport.Id == airport.AirportId)
{
modifiedPreferedAirports.Add(custPa);
modifiedPreferedAirportsVm.Add(airport);
custPa.CheckInMinutes = airport.CheckInMinutes;
}
}
}
// Remove common airports from ViewModel
modifiedPreferedAirportsVm.ForEach(el => viewModel.PreferedAirports.Remove(el));
// Remove deleted airports from model
var toDelete = customer.PreferedAirports.Except(modifiedPreferedAirports);
toDelete.ForEach(el => customer.PreferedAirports.Remove(el));
// Add new Airports
var toAdd = viewModel.PreferedAirports.Select(el => new PreferredAirportModel
{
Airport =
session.Query<AirportModel>().
SingleOrDefault(a => a.Id == el.AirportId),
CheckInMinutes = el.CheckInMinutes
});
toAdd.ForEach(el => customer.PreferedAirports.Add(el));
session.Save(customer);
return View();
}
}
My environment is ASP.NET MVC 4, nHibernate, Automapper, SQL Server.
Well, if "elegant" is just "don't clear and recreate all" (untested) :
var airports = customer.PreferedAirports;
var viewModelAirports = viewModel.PreferredAirports;
foreach (var airport in airports) {
//modify common airports
var viewModelAirport = viewModelAirports.FirstOrDefault(m => m.AirportId == airport.AirportId);
if (viewModelAirport != null) {
airport.X = viewModelAirport.X;
airport.Z = viewModelAirport.Z;
//remove commonAirports from List
viewModelAirports.Remove(viewModelAirport);
continue;
}
//delete airports not present in ViewModel
customer.PreferedAirports.Remove(airport);
}
//add new airports
foreach (var viewModelAirport in viewModelAirports) {
customer.PreferedAirports.Add(new PreferredAirportModel {
Airport = session.Query<AirportModel>().SingleOrDefault(a => a.Id == el.AirportId),
CheckInMinutes = el.CheckInMinutes
});
}
session.Save(customer);

Ria Service: Navigation Property is null

For example I have two entities
Class A
{
public Guid Id {get;set;}
public Guid BId {get;set;}
public B InstanceB {get;set;}
}
Class B
{
public Guid Id {get;set}
}
B is related to A, on my silver light application I am creating a new instance of A, and also a new instance of B. The new instance of B does not exist yet. But I need the instance of B on my service.
Can I do this without Entity or Association with Ria Service?
Edit:
My Class A :
public partial class lSync{
// Metadata classes are not meant to be instantiated.
private lSync() {
}
public string ConflictMessage { get; set; }
public DateTime DateInserted { get; set; }
public Guid vValuesId { get; set; }
public Guid ID { get; set; }
public bool IsConflict { get; set; }
public bool IsReadyToSync { get; set; }
public Guid SyncSet { get; set; }
public vValues vValues { get; set; }
}
My Ria Service:
[Invoke]
public lSync[] SynchvValuesFromClient(lSync[] syncs) {
bool noConflict = true;
foreach (lSync sync in syncs) {
var servervValue = GetvValuesByID(sync.vValuesId).FirstOrDefault();
var queuevValues = sync.vValues; //sync.vValues here is null, but my sync.vValuesId is not
if (servervValue== null) {
InsertvValues(queueValue);
}
else {
if (servervValue.IsServerConflict(queueValue)) {
sync.IsConflict = true;
sync.ConflictMessage = "Conflict";
noConflict = false;
break;
}
if (!servervValue.AreValuesEqual(queueValue)) {
UpdatevValues(queueValue);
}
}
}
if (noConflict) {
this.ObjectContext.SaveChanges();
}
return syncs;
}
public IQueryable<vValues> GetvValuesByID(Guid ID) {
return ObjectContext.vValues.Where(t => t.ID == ID);
}
public void InsertvValues(vValues model) {
model.ServerDate = DateTime.UtcNow;
if ((model.EntityState != EntityState.Detached)) {
this.ObjectContext.ObjectStateManager.ChangeObjectState(model, EntityState.Added);
}
else {
this.ObjectContext.vValues.AddObject(model);
}
}
public void UpdatevValues(vValuesmodel) {
model.ServerDate = DateTime.UtcNow;
this.ObjectContext.vValues.AttachAsModified(model, this.ChangeSet.GetOriginal(model));
}
:(
Edit
The order is wrong of your method :)
Make an instance of the service before creating instances of the Entities.
It should be:
public void SyncToServer() {
ContextService service = new ContextService();
var instanceA = new A();
instanceA.InstanceB = new B();
service.SubmitChanges(); //service.SaveChanges() for LinqToEntities
}
Are you reloading after a submit because only adding the [Include] attribute in the DomainService MetaData won't work. You need to do this in the DomainService for LinqToSql
public A GetA()
{
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<A>(a => a.InstanceB);
this.DataContext.LoadOptions = dlo;
return this.DataContext.APlural.FirstOrDefault( ); //don't know the plural of A.
}
LinqToEntities:
public A GetA()
{
return this.MyEntitiesContext.APlural.Include( "instanceB" ).FirstOrDefault( ); //don't know the plural of A.
}
var a = new A(){
B = new B(); //or (B)selectedItem
}
now a.Id and a.BId is 0 until you SaveChanged and return saved A

Resources