Thanks Tim! You are explaining everything so clear. You are a great teacher! I saw that you use Automapper and I would like to give you my opinion after years of experience with it and why I stopped using it. I don't like Automapper because it hides references and increases in most cases the code reading time. I think most people believe that Automapper saves development time, but its actually the opposite. When I refactor code or implement new functionalities and I don't have the references which would tell me where all those properties are in use, I would have to constantly look through the AutoMapper mapping profiles from each type which is involved and try to figure out what is going where and what might break if I change a property, because the compiler wont tell me due to the fact that Automapper is doing everything during runtime with reflection, but during development time I don't get any help. That costs much more time than the time you maybe saving when writing the code. And I haven't even mentioned other problems which Automapper is causing like misleading of static analysis. If you want to shrink writing time, then look rather into the Visual Studio extension MappingGenerator on GitHub ;)
Im impressed Tim, i wish I would have preset the things 'the way you are explaining, great.' , also you're a kind person who responded to all the comments below the video. Appreciated .
Hi Tim, thank you again. I enjoyed the video and it is nice to learn about AutoMapper. You also gave me a good laugh at the bugs you created by copy/pasting. The nice thing is you preach not t do it, but you do it over and over again and it turns out wrong over and over again ... I think you demonstrated your point now ....
Yeah, I would love to say I do it to show off how not to do it but the truth is that I'm trying to hurry so you don't watch repetitive stuff, which leads to problems.
Hi Tim, When we add all the products from stock to the cart, both the 'AddToCart' and 'RemoveFromCart' buttons becomes disabled (rendering the item to be stuck). I believe we might need to change the logic in CanRemoveFromCart from SelectedCartItem?.Product.QuantityInStock > 0 to SelectedCartItem?.QuantityInCart >= 0 (greater than or equal to 0) Also, since we removed the DisplayText from the Model, it means that there is redundant code in the View right ? Additionally, we are removing out the functionality to show the DisplayText but not bringing it back in with the new Display Model
Hi Tim, thanks for the series, it is really helpful. One question: In your SalesViewModel CanRemoveFromCart should the second test not test QuantityInCart rather than QuantityInStock? If I added 10 skillets I cannot remove one. Thanks again.
@@IAmTimCorey Hi Tim, while checking this out, check this situation: add the entire quantity of a product, remove one piece and see if your Add to Cart button reactivates. In my case it doesn't until I select another item from the Product List then re-select the previous item. As always, thanks for the uploads.
When adding the event and event handler to the Display Models, instead of duplicating the Invoke and the event, it seems to work fine implementing an abstract class to hold those things, that is then inherited by the Display Models.
When removing an item from the cart and increasing the SelectedCartItem.Product.QuantityInStock by 1, I was a little confused how it was increasing the amount in the Product list, given these are 2 different lists. But this seems to work because it references the same object in memory, and I did some object Equal checking in the debugger watch to confirm that suspicion. Is this correct?
Is there a reason for not having try catch blocks in the ViewModel methods, like you have in the end points? Is this something that will be added later or is the code design is robust enough with null checks etc? Secondly, thank you so much for the work you are doing here, this is a fantastic playlist, the way you have chunked the work in the videos is great for building knowledge and skills. I now pause the video before you start a task and asttempt it myself before watching, it helps build a better understanding of what the code is doing, and I get to learn from my own mistakes as well as yours. Again, I wanted to acknowledge the fine work that you have done here, I know its a vocation but its clear that you care about the service you are providing.
I don't typically fill my demo code with try/catch but I also don't go crazy adding them even in production. It adds overhead to do that check and often, if something unexpected happens I want the application to crash rather than continue on. I'm glad you are enjoying the content.
Awesome videos! Thanks so much for your invaluable lessons & support to the C# enthusiasts. I have followed through all the videos until this one. One question, though: when you remove items from the cart, the quantity is always 1, even if the Quantity is set to be > 1. I guess the logic can be slightly improved here. All the very best, Neculai
I don't know if it has been said, but it probably has been. The WPF top bar would have told you (other than red line around the box) that you had an Exception happening, whenever you clicked the box.
Great video Tim. Quick question: I have a scenario that I have a source class (call it Foo) that has a public static property: public class FooStatus { public static readonly FooStatus Applied = new FooStatus(1, "Applied"); public static readonly FooStatus Applied = new FooStatus(2, "Open"); public static readonly JobApplicationStatus[] AllStatuses = { Applied, Closed }; public int Id { get; } public string StatusDescription { get; } } When mapping this class to a DTO object I want to exclude these static properties. How would you do it using the Fluent approach with AutoMapper? If you cant with the Fluent approach, how would you do it with the Attribute Matching approach? I am using AutoMapper.Collection nuget v.7.0.1 and AutoMapper.Extensions.Microsoft.DependencyInjection nuget 8.1.1
Does this work also on datagrid that needs to update when the source changes? Like implement iNotifyPropertyChange on the class we use for our datasource
Hello, at 24:00 the qty in Item box not updating when adding to cart, I have no Errors... any idea? I traced though the code all the values seem to be updating properly, just not the display. I found this info do you think it could be the issue? AutoMapper no longer creates maps automatically (CreateMissingTypeMaps and conventions) You will need to explicitly configure maps, manually or using reflection. Also consider attribute mapping.
That doesn't sound like the issue. If all of the values are being updated properly then the issue is probably that the NotifyOfPropertyChanged event isn't firing for that property.
I am also getting the same issue. Cart and Products lists are not being updated on Display though values are updated properly. How to resolve this? Is there a AutoMapper version problem? I have referred AutoMapper version 10.0.
Hi Tim, maybe I overlooked, but I don't get why we cannot use Caliburn.Micro's NotifyOfPropertyChange in TRMDesktopUI.Models. This project has already Caliburn.Micro nuget package installed, so why not to use it here, too? I suppose this is in connection with Automapper: The models in TRMDesktopUI.Library does not have this nuget package and this might mean a kind of constraint. Right? Thank you.
@@IAmTimCorey Yes, I understand that we do not want to refer our library to the UI. But it is weird to me, if in the UI project we map a library model into a UI model (with Caliburn.Micro) it "brings our UI-specific code down into our class library". Black magic. This is what not clear to me.
The Automapper kind of threw me off, but i was able to enable it for my UI (Xamarin forms), thankfully, unlike autoFac, it supports .NET Core. Thanks Tim, this right here is a blessing.
Autofac supports .NET Core as well: autofaccn.readthedocs.io/en/latest/integration/netcore.html I'm glad you were able to get Automapper to work for your situation.
Your channel should be a part of MS documentation. There is just so much stuff to learn here. I have to ask, dont you get tired of responding to all of these 'you're great thank you' comments? Its hard to not leave one, when you discover some minor fix to a thing that has been driving you nuts for a while. For instance, lauching api and wpf app at the same time, i used to open visual studio in two windows, and start api in one, desktop in the other. Its annoying as it gets.
This is just for my curiosity. The fact that you are using BindingList for the Products and Cart brings in the already existing ResetBindings() method. Before you posted this video I played around with this method and got the same result as creating the two DisplayModels and mapping them to the already existing models. I understand that the way I did it forces me to call this ResetBindings() in every method that updates the Products and Cart and it might get repetitive, but I didn't bring any new classes to the project and used the already existing ones. The way you did it updates the information every time something triggers the PropertyChanged. Is this way faster as the project grows, as in the products list grows or the product details grow or is just meant to be more maintainable code over time? Thanks again. Have a great day!
Not sure I'm visualizing what you are doing but adding in the notification on property change allows us to see what is getting notified and it bubbles those changes up to Caliburn Micro.
@@IAmTimCorey Thank you for clearing that up :). Before creating the UI display models (ProductDisplayModel and CartItemDisplayModel), in the AddToCart() and RemoveFromCart() methods, I called Cart.ResetBindins() and Products.ResetBindings() to update the quantities from the Cart and the Quantity left in stock.
I Agree with you completely, you could even write a function called NotifyCartItemChanged() so you can have the same 'workflow' as using the NotifyOfPropertyChanged. You can even make sure it only updates the specific Item by using Cart.ResetItem(), so it only updates the specific item on screen, and ofcourse have anoter for NotifyProductChanged(). The advantage of working this way is that the item on screen doesn't get updated every time a single property changes and only if you're done with updating the whole item yourself.. The advantage ofcourse of using the way Tim showed is you don't have to keep any single change in mind of you update the item.. But in this case I think using the whole AutoMapper is overkill compared to just calling the ResetBindings/ResetItem..
On the explanation for why the display models should be in the WPF UI project. Think about if you had different interfaces for different people, Mobile with Android, iPhone, MVC Web App, Console App. Each would have different ways of presenting things
Hi, this is a great video. I am wondering why the SelectedCartItem?.Product.QuantityInStock > 0 was checked instead of SelectedCartItem.QuantityInCart >0? I think even the QuanityInStock == 0, we can still remove the item from the cart. I didn't see the cause.
We do the SelectedCartItem?... because we are doing a null check on SelectedCartItem. If nothing is selected, we would get an exception otherwise. You cannot access a property on a null object.
Hi Tim, thanks for this video, it was really helpful. I would like to ask you, though, if is there any chance you can extend your Getting Started with .NET Core course, or create an in-depth one to explain the authorization part of .Net Core and how we can make use of roles, policies and claims. Thanks again for your efforts.
Hi Tim, thanks a lot for your videos and for this course in particular. Just downloaded the project via github to another machine and getting 400 response when trying to log in. all packages are installed as I can see. in another machine where the project has been written all works good.
Did you create the user on that other machine? Remember that the database gets created on every machine you are on unless you created a centralized database for your authentication.
Hi Tim, thank you for this video. One question/suggestion: CanRemoveFromCart(), isn't it redundant to add "?" after SelectedCartItem? If the first condition is not true (SelectedCartItem is null) the second one will never be checked (because you use "&&" operator). Going forward I suggest that we can simplify entire method to one condition: SelectedCartItem?.Product.QuantityInStock > 0. In case when "?" operator catches null entire if will be false.
I wonder if you found yourself setting up that called event a lot if it would make a case for having models inherit from a base class that is abstract. It might be overkill now, but later..... if the software got really large maybe.
I'm a couple of years behind this, but when I was trying to get the Items and Cart boxes to update, I just went Products.ResetBindings(); Cart.ResetBindings(); All good. No need to create separate models or do AutoMapper! is this the wrong way to do it?!
The issue here is that ResetBindings will refresh the list and move your selection. So if you had a record selected, now it will be unselected. I wanted to avoid that and do it right.
@@IAmTimCorey Ahhh, OK I see what you mean. Yes, it does lose the focus, so you would have to reselect if you wanted to remove more of the same item. I have two points, one is a suggestion and the other a query. The first is that I control how many are removed from the cart by using the item quantity box. So if I have 5 in the cart and I want to remove 3, I place that number in the quantity box and it will remove 3 items. To help control this further, the Add button is highlighted when you select an item in the Item ListBox and the Remove button when you select an item in the Cart ListBox. Both buttons can't be active at the same time. The query is, with this in place, if you add 5 of the 10" Frying Pans and then remove 3 of them (here the Add button is now unhighlighted and the Remove button is highlighted). If you then try to select Frying Pan again to Add from the item ListBox, nothing changes. You need to select another item for the NotifyOfPropertyChange to take effect and the Add button to highlight. The ListBoxes seem to keep a 'soft focus', so even if you move from one to the other (selecting the last selected item again), nothing changes. Thanks for all that you do. Because of you, I am getting the bug for this programming stuff and the days fly by.
There is one more suggestion I have. What is your opinion on using interfaces for the models since many are repeated. I saw many videos that showed that interfaces should be used for nearly everything.
I don't use user interfaces for models because there is no need (typically). We use interfaces so that we can replace one type with another. That is helpful for unit testing or changing how a system acts. Data is just data. It doesn't need to be swapped out for a different class that also holds the same type of data (99% of the time).
If you need it, yes. AutoMapper is performant, so the only real "issue" is that you are creating multiple objects but that cannot be helped at that point.
So question about the CanRemoveFromCart. If you are checking QuantityInStock that's the amount that should be showing on the left right? So if you have no stock left, and want to remove and put it back you'll be blocked? Am I misreading that?
Thanks for the great videos Tim. In the display models, you invoke events, but you never added a listener for those events in the view model. Why does this work?
It works based upon convention (one of the things Caliburn Micro makes easier). So if I have a button named AddToCart, it will look for the AddToCart method in my ViewModel and match the click event to that method.
I have one question from the video. When I saw you enter the information for a full property, i noticed that after you typed in one text, it did the other automatically. How was that done? because everytime with a standard snippet, i was forced to enter twice. once with the _ and lower case and the other with uppercase. I hope that resharper is not required. Is there a way to make it work like that without paying for resharper?
I had copied the name from the auto-property and pasted it in for the full property name. No, you don't need to pay for Resharper if you don't want to. I don't use it (mostly because I try not to use paid products for my videos).
I have a question. In the beginning of the video, you mentioned a special where if you donate 10 dollars a month via patreon, then you get a pdf with ideas for apps. I paid the 10 dollars but did not see any pdf file on the site.
The way Patreon works is that it will send out the PDF to you when the promotion closes. I did get your email but I'm just now recovering from vacation. I'll respond more fully there in a bit.
@@IAmTimCorey Thanks for letting me know. I will really be looking forward to it. Because I just finished redoing my game package and was going to redo again when .net core 3 hits in september. Until then, I don't have much to do.
I've been trying to find my bug... I'm not sure what has caused it, or how to fix it, but I can put break points in my code to view the _quantityInStock, and it will decrease relative to the cart quantity, but when I try to run my program the inventory stock on the sales view page wont lower when I add something to the cart...
also now when I removed the hack I can only add 1 item to the cart... I am assuming I don't have something wired up properly and I should just revert back to my last push and start the video again from scratch.... I had some issues when renaming the ProductModel and CartItemModel to the DisplayModels respectively and accidentally renamed everything in my whole solution, I managed to go back and put the ProductModel and CartItemModel back in and I am pretty sure I renamed everything I need to, but I think I screwed something else up in another script somewhere
I just reverted back in github, and re-started from the beginning of the video, I either screwed up with the mass rename across the solution, or I chose the exact same version of AutoMapper that was shown in the video instead of v10 or something, and when I restarted I picked the absolute newest version of AutoMapper, I think the issue was the rename though.
Overdue but might help someone else. My issue was on the CallPropertyChanged methods, I had new PropertyChangedEventArgs(nameof(propertyName)) whilst passing in the QuantityInStock like so: CallPropertyChanged(nameof(QuantityInStock));. So I ended up using nameof twice. No error so could be an easy miss. So when we're calling Invoke, it should be new PropertyChangedEventArgs(propertyName) not new PropertyChangedEventArgs(nameof(propertyName)). Well it depends what you want to pass in I suppose but if you're following along, it'll cause an issue :)
U can use [CallerMemberNameAttribute] in CallPropertyChanged public void CallPropertyChanged([CallerMemberName] propertyName = "") { ... } Then u don't have to use name of property when call/invoke CallPropertyChanged
@@IAmTimCorey When you change this though, make sure you STILL pass in the nameof(DisplayText) in the "QuanityInCart" Property in CartItemDisplayModel as you're calling the propertyChanged twice there. CallPropertyChanged(); CallPropertyChanged(nameof(DisplayText)); public void CallPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Hi Tim, I need your help concerning Models, i am making a web application with 3 tire Architecture, and i am confused about Models. I have models in my Dal and my business layer and Mvc both uses the models from dal. I have only view models in my Mvc. Should i make separate library for models and use them all over the projects or should i make a new sets of models in my Mvc and Map them with models from dal using AutoMapper in my Mvc ?
It depends if you need different models or if you can get away with reusing the same models as your DAL. It also depends on the size of your project and what you intend to add to it.
Hi Tim, I'm having trouble getting the data bindings to work (as you showcase at 23:50). My quantity stays at 10 after i press "Add to cart". I have tried undoing everything and starting over from the beginning of this video to make sure I wrote the same code as you did. Do you have any idea how i could debug this?
Well, breakpoint the AddToCart method to see what is happening. Maybe you are actually doing the work but the display is not getting updated. Or, maybe the work is not getting done properly. That is a good place to start.
@@IAmTimCorey Thank you so much for your quick answer, I really appreciate your outstanding work with this course! I have now debugged the AddToCart method and I can clearly see that the QuantityInStock property of the SelectedProduct is reduced to 9 from 10 however the quantity wont update in the UI. I've also added tried debugging with tracing: xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase" But from what i can understand from this trace output message is that the binding is initializing properly: System.Windows.Data Warning: 56 : Created BindingExpression (hash=15674164) for Binding (hash=43691456) System.Windows.Data Warning: 58 : Path: 'QuantityInStock' System.Windows.Data Warning: 60 : BindingExpression (hash=15674164): Default mode resolved to OneWay System.Windows.Data Warning: 61 : BindingExpression (hash=15674164): Default update trigger resolved to PropertyChanged System.Windows.Data Warning: 62 : BindingExpression (hash=15674164): Attach to System.Windows.Controls.TextBlock.Text (hash=16654654) System.Windows.Data Warning: 67 : BindingExpression (hash=15674164): Resolving source System.Windows.Data Warning: 70 : BindingExpression (hash=15674164): Found data context element: TextBlock (hash=16654654) (OK) System.Windows.Data Warning: 78 : BindingExpression (hash=15674164): Activate with root item ProductDisplayModel (hash=1503503) System.Windows.Data Warning: 108 : BindingExpression (hash=15674164): At level 0 - for ProductDisplayModel.QuantityInStock found accessor RuntimePropertyInfo(QuantityInStock) System.Windows.Data Warning: 104 : BindingExpression (hash=15674164): Replace item at level 0 with ProductDisplayModel (hash=1503503), using accessor RuntimePropertyInfo(QuantityInStock) System.Windows.Data Warning: 101 : BindingExpression (hash=15674164): GetValue at level 0 from ProductDisplayModel (hash=1503503) using RuntimePropertyInfo(QuantityInStock): '10' System.Windows.Data Warning: 80 : BindingExpression (hash=15674164): TransferValue - got raw value '10' System.Windows.Data Warning: 84 : BindingExpression (hash=15674164): TransferValue - implicit converter produced '10' System.Windows.Data Warning: 89 : BindingExpression (hash=15674164): TransferValue - using final value '10' Lastly i tried adding "NotifyOfPropertyChange(() => SelectedProduct);" at the end of the AddToCart method but no luck... Where should I look next?
@@IAmTimCorey After some more testing I tried, in the SalesView, to put the "quantity in stock" textblock ( ) outside the stackpanels to see if, maybe, the binding was not able reach out from so many panels (made sense in my head when i came up with the idea haha). And to my surprise, the binding now worked! But i was even more surprised when I put the textblock back, inside the stackpanels, because it was working there as well. So now i'm sitting here, 2 days later, with the same code that wasn't working before but is now working perfectly. And according to the history and comparing feature of the team explorer the code is the same. How weird isn't that??
Alright, finally I tracked down why my bindings weren't working. I had accidentally added a extra "nameof" in the CallPropertyChanged Method I had done this: public void CallPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(propertyName))); } instead of this: public void CallPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
@@antoneriksson208 Oh Kernigan and Ritchie. I had the exact same problem. Then traced it to this. Thank you for posting that. I don't think I would have noticed that it didn't have nameof
I post a message on Patreon each week that there is a TimCo video released, so if you want old video code, you will need to go back and find it. No guarantee that it will be there, but it should be.
CartItemDisplayModel and ProductDisplayModel, both have same event and method calling that event. So I created a new class for that event and method, called PropertyChangedBase, and inherited CartItemDisplayModel and ProductDisplayModel from that class. Maybe I can have another displayModel class in the future, and I can then inherit again from that base class
@@IAmTimCorey But then again, you're using the ProductDisplayModel/CartItemDisplayModel purely for displaying items AND the need for PropertyChanged Event, so it does make sense to use a base for it, but I'd rather would call it DisplayModelBase so more functionalities/properties that might be common to the needs of a ....DisplayModel class..
Hi Tim, thank you for your incredible tutorials! I have a problem fetching data between 2 laptops. I decided to fetch code of all 21 tutorials via github to my second laptop, and this is where some problems start. I can't login because of WPF's "internal server error". I decided that I need first to register with the postman, but It returns a post 500 internal server error (.mdf file is missed and also a bunch of sql server exceptions ). I would appreciate any help. Thank You.
I go over this later on in the series (how to put everything on a new machine). You will need to publish your SQL database and update your connection string (potentially). There are some other tweaks you will probably need to do as well.
As tim said in his comment, caliburn micro adds some extra features and you can see this by pressing F12 on INotifyOfPropertyChanged and see that it inherits from INotifyPropertyChanged.
I think a more normal behavior for removing from cart is to remove the item completely instead of lowering the quantity one by one. If the user cannot change the quantity in the chart directly it is easier for him just to add the item again with the right quantity. That makes the logic much simpler too by doing: SelectedCartItem.Product.QuantityInStock += SelectedCartItem.QuantityInCart; Cart.Remove(SelectedCartItem); Best regards
i have no idea why, but for Products listbox I can use SelectedItem="SelectedProduct" (where caliburn takes care of the binding), yet for Cart listbox I had to use SelectedItem="{Binding SelectedCartItem}, as SelectedItem="SelectedCartItem" did not work no matter what, even with everything else being exactly the same not really a problem, I just like to use caliburn's bindings (where it is possible)
@@IAmTimCorey I was just googling for something completely different ( but still wpf related) and the article I stumbled upon included, among others, the usage of caliburn and on the very first page, there was an example showing how caliburn binds the selected item of a listbox and apparently, it uses the following naming pattern: - it checks the xaml element (listbox) name - if the name is plural (ends in "s") it makes it singular - binds to a property named "Selected[singular_form_of_element_name]" it's nice when things work out by themselves
CanRemoveFromCart should really just check if the item is selected, because if there isn't any quantityInCart, you should still be able to remove it from the cart, RemoveFromCart should check if it should increase Product.QuantityInStock.
That situation should never happen. By not covering this possibility, you would be "approving" a bad state and pretending it was an OK state. That's not a wise choice. You would be allowing something to go through that another method had to properly handle or you would introduce a bug. A bug that shouldn't show up but when it did, it would be hard to track down.
@@IAmTimCorey Except now if someone would call RemoveFromCart in another spot, it might go all wrong, because now you are assuming that everything has been set up properly before RemoveFromCart is being called (hell we even assume SelectedCartItem is not null). In reality it shouldn't even matter if the remove or add button is disabled at all, as long as the RemoveFromCart en AddToCart would handle it correctly.. You might for instance add a keyboard shortcut to remove the item from the cart or another extra button.. Again, now you handled a protection from outside the RemoveFromCart, while RemoveFromCart would be the one that actually does all the checking if it should increase the QuantityInStock or decrease the QuantityInCart or remove it all together. Apart from checking is there actually is a CartItem selected, the only check to make it 'foolproof' is to check if we are allowed to increase the QuantityInStock (which you only should do if QuantityInCart > 0)..
First, we don't assume SelectedCartItem is not null, we check for that first. Second, we have a method for removing items from the cart. Why would we do the same action somewhere else a different way? If we are going to remove the item from the cart using a keyboard shortcut, that shortcut is going to utilize the CanRemoveFromCart and RemoveFromCart methods.
Also, i had a suggestion. It would be easy to create a simple class that has the basics for INotifyPropertyChanged so you can inherit and not have to copy/paste so much code.
I haven't checked to see if there are any breaking changes. I would recommend getting it to work with the version we used and then updating the version to see if it still works.
Hi mate , i got one question , i dont really have idea how to exactly achieve it , im working on a project where in certain time some of checks(bool) should get changed either it have any traffic active or not , would be nice if you can give any clue Much Appreciated.
i mean what if i want to send a notification to user at specific time , their must be something running 24/7 and checking if its time to send notification and when it is it will send ...
If you are doing it locally, look into Windows Services (I did a video on them). That can send messages or do other work based upon time. If you can run things in the cloud, check out Azure Functions. They are free for low to moderate usage and you can use a time-based function to kick off a task or job.
It depends on what you mean. When you sell something, you modify the inventory. When you accept something into inventory, you record it. Those all go through a UI of some type.
Why exactly? That's the entire purpose of the tool. It has been optimized and honed to do one thing well and that's what we are using it for. I don't reinvent the wheel when I don't need to.
@@IAmTimCorey I know, don't take it personally. But the use of reflection (automapper) in a big project is something that the people have take into consideration.
I covered that in the video. Yes, it uses reflection but at startup, not throughout your project. That means you take a minor performance hit on startup but that is it. That is, in my estimation, a perfectly acceptable trade-off to creating custom mapping methods for each method you need to map. Even if you do it by hand, it probably won't be as performant as what Automapper will do. My thing is that you shouldn't hide from reflection. You should just know the downsides and you should weigh them against the alternatives. In this case, a small performance hit that none of my customers will see is totally worth it.
@@IAmTimCorey I agree. By he way, Caliburn.Micro (and other MVVM solutions) reliess heavily on reflection. I think trying to do it only once is a good strategy.
@@IAmTimCorey Except it does require the automapper (which takes up space/memory) and the more items you're gonna map, the longer it takes to start the application and the larger the memory footprint. Maybe there is something wrong with the design if you are using it a lot in your application...
Thanks Tim! You are explaining everything so clear. You are a great teacher! I saw that you use Automapper and I would like to give you my opinion after years of experience with it and why I stopped using it. I don't like Automapper because it hides references and increases in most cases the code reading time. I think most people believe that Automapper saves development time, but its actually the opposite. When I refactor code or implement new functionalities and I don't have the references which would tell me where all those properties are in use, I would have to constantly look through the AutoMapper mapping profiles from each type which is involved and try to figure out what is going where and what might break if I change a property, because the compiler wont tell me due to the fact that Automapper is doing everything during runtime with reflection, but during development time I don't get any help. That costs much more time than the time you maybe saving when writing the code. And I haven't even mentioned other problems which Automapper is causing like misleading of static analysis. If you want to shrink writing time, then look rather into the Visual Studio extension MappingGenerator on GitHub ;)
You're an incredible teacher, thank you so much.
You are welcome.
Im impressed Tim, i wish I would have preset the things 'the way you are explaining, great.' , also you're a kind person who responded to all the comments below the video. Appreciated .
Hi Tim, thank you again. I enjoyed the video and it is nice to learn about AutoMapper. You also gave me a good laugh at the bugs you created by copy/pasting. The nice thing is you preach not t do it, but you do it over and over again and it turns out wrong over and over again ... I think you demonstrated your point now ....
Yeah, I would love to say I do it to show off how not to do it but the truth is that I'm trying to hurry so you don't watch repetitive stuff, which leads to problems.
Does anybody else get proud of themselves when they find the bug before Tim does? at 38:35 I saw what we missed.
Well done!
Hi Tim,
When we add all the products from stock to the cart, both the 'AddToCart' and 'RemoveFromCart' buttons becomes disabled (rendering the item to be stuck). I believe we might need to change the logic in CanRemoveFromCart from
SelectedCartItem?.Product.QuantityInStock > 0
to
SelectedCartItem?.QuantityInCart >= 0
(greater than or equal to 0)
Also, since we removed the DisplayText from the Model, it means that there is redundant code in the View right ? Additionally, we are removing out the functionality to show the DisplayText but not bringing it back in with the new Display Model
You know its Monday when Tim video drops 😊
I'm glad it adds a smile to your day.
@@IAmTimCorey It's the only thing that cheers my mondays up... though I don't get around to the video until later, I know it's there :)
Hi Tim, thanks for the series, it is really helpful. One question: In your SalesViewModel CanRemoveFromCart should the second test not test QuantityInCart rather than QuantityInStock? If I added 10 skillets I cannot remove one.
Thanks again.
Whoops, good catch. I'll add that to my list of things to fix. Thanks for pointing it out.
@@IAmTimCorey Hi Tim, while checking this out, check this situation: add the entire quantity of a product, remove one piece and see if your Add to Cart button reactivates. In my case it doesn't until I select another item from the Product List then re-select the previous item.
As always, thanks for the uploads.
@@tinumurymury38 Add NotifyOfPropertyChange(() => CanAddToCart); to RemoveFromCart method.
@@skeleton04-r5g Thank you. Just got the chance to work on it and got to the same solution :).
When adding the event and event handler to the Display Models, instead of duplicating the Invoke and the event, it seems to work fine implementing an abstract class to hold those things, that is then inherited by the Display Models.
Yep, that would work.
@@IAmTimCorey Cool. Didn't know if there was a hidden trap there. Thanks for your work!
When removing an item from the cart and increasing the SelectedCartItem.Product.QuantityInStock by 1, I was a little confused how it was increasing the amount in the Product list, given these are 2 different lists. But this seems to work because it references the same object in memory, and I did some object Equal checking in the debugger watch to confirm that suspicion. Is this correct?
You are the man Tim, doing an amazing job! Keep it up, just a minor suggestion - increase the font size.
I've tweaked it a bit (up to 18pt from 16pt) but that's about as far as I can go. Otherwise, it is too hard to show things on screen.
@@IAmTimCorey WOW and I thought it was too big at 16pt. You can't win can you Tim :)
Is there a reason for not having try catch blocks in the ViewModel methods, like you have in the end points? Is this something that will be added later or is the code design is robust enough with null checks etc?
Secondly, thank you so much for the work you are doing here, this is a fantastic playlist, the way you have chunked the work in the videos is great for building knowledge and skills. I now pause the video before you start a task and asttempt it myself before watching, it helps build a better understanding of what the code is doing, and I get to learn from my own mistakes as well as yours.
Again, I wanted to acknowledge the fine work that you have done here, I know its a vocation but its clear that you care about the service you are providing.
I don't typically fill my demo code with try/catch but I also don't go crazy adding them even in production. It adds overhead to do that check and often, if something unexpected happens I want the application to crash rather than continue on.
I'm glad you are enjoying the content.
Awesome videos! Thanks so much for your invaluable lessons & support to the C# enthusiasts. I have followed through all the videos until this one. One question, though: when you remove items from the cart, the quantity is always 1, even if the Quantity is set to be > 1. I guess the logic can be slightly improved here. All the very best, Neculai
I don't know if it has been said, but it probably has been.
The WPF top bar would have told you (other than red line around the box) that you had an Exception happening, whenever you clicked the box.
Yep, the one time I could have benefited from it. OK, it isn't that bad. It just annoys me.
Tim, do you have the git repo available ? - do you mind !
Great video Tim. Quick question: I have a scenario that I have a source class (call it Foo) that has a public static property:
public class FooStatus
{
public static readonly FooStatus Applied = new FooStatus(1, "Applied");
public static readonly FooStatus Applied = new FooStatus(2, "Open");
public static readonly JobApplicationStatus[] AllStatuses = { Applied, Closed };
public int Id { get; }
public string StatusDescription { get; }
}
When mapping this class to a DTO object I want to exclude these static properties. How would you do it using the Fluent approach with AutoMapper? If you cant with the Fluent approach, how would you do it with the Attribute Matching approach?
I am using AutoMapper.Collection nuget v.7.0.1 and AutoMapper.Extensions.Microsoft.DependencyInjection nuget 8.1.1
Does this work also on datagrid that needs to update when the source changes? Like implement iNotifyPropertyChange on the class we use for our datasource
Hello,
at 24:00 the qty in Item box not updating when adding to cart, I have no Errors... any idea? I traced though the code all the values seem to be updating properly, just not the display. I found this info do you think it could be the issue?
AutoMapper no longer creates maps automatically (CreateMissingTypeMaps and conventions) You will need to explicitly configure maps, manually or using reflection. Also consider attribute mapping.
That doesn't sound like the issue. If all of the values are being updated properly then the issue is probably that the NotifyOfPropertyChanged event isn't firing for that property.
I am also getting the same issue. Cart and Products lists are not being updated on Display though values are updated properly.
How to resolve this?
Is there a AutoMapper version problem? I have referred AutoMapper version 10.0.
Hi Tim, maybe I overlooked, but I don't get why we cannot use Caliburn.Micro's NotifyOfPropertyChange in TRMDesktopUI.Models. This project has already Caliburn.Micro nuget package installed, so why not to use it here, too?
I suppose this is in connection with Automapper: The models in TRMDesktopUI.Library does not have this nuget package and this might mean a kind of constraint. Right? Thank you.
Right. We don't want to bring our UI-specific code down into our class library.
@@IAmTimCorey Yes, I understand that we do not want to refer our library to the UI. But it is weird to me, if in the UI project we map a library model into a UI model (with Caliburn.Micro) it "brings our UI-specific code down into our class library". Black magic. This is what not clear to me.
The Automapper kind of threw me off, but i was able to enable it for my UI (Xamarin forms), thankfully, unlike autoFac, it supports .NET Core. Thanks Tim, this right here is a blessing.
Autofac supports .NET Core as well: autofaccn.readthedocs.io/en/latest/integration/netcore.html
I'm glad you were able to get Automapper to work for your situation.
Your channel should be a part of MS documentation. There is just so much stuff to learn here.
I have to ask, dont you get tired of responding to all of these 'you're great thank you' comments? Its hard to not leave one, when you discover some minor fix to a thing that has been driving you nuts for a while. For instance, lauching api and wpf app at the same time, i used to open visual studio in two windows, and start api in one, desktop in the other. Its annoying as it gets.
Not at all. In fact it really helps my UA-cam ratings! Keep it up! Thanks for your note.
This is just for my curiosity.
The fact that you are using BindingList for the Products and Cart brings in the already existing ResetBindings() method.
Before you posted this video I played around with this method and got the same result as creating the two DisplayModels and mapping them to the already existing models.
I understand that the way I did it forces me to call this ResetBindings() in every method that updates the Products and Cart and it might get repetitive, but I didn't bring any new classes to the project and used the already existing ones.
The way you did it updates the information every time something triggers the PropertyChanged.
Is this way faster as the project grows, as in the products list grows or the product details grow or is just meant to be more maintainable code over time?
Thanks again. Have a great day!
Not sure I'm visualizing what you are doing but adding in the notification on property change allows us to see what is getting notified and it bubbles those changes up to Caliburn Micro.
@@IAmTimCorey Thank you for clearing that up :).
Before creating the UI display models (ProductDisplayModel and CartItemDisplayModel), in the AddToCart() and RemoveFromCart() methods, I called Cart.ResetBindins() and Products.ResetBindings() to update the quantities from the Cart and the Quantity left in stock.
I Agree with you completely, you could even write a function called NotifyCartItemChanged() so you can have the same 'workflow' as using the NotifyOfPropertyChanged.
You can even make sure it only updates the specific Item by using Cart.ResetItem(), so it only updates the specific item on screen, and ofcourse have anoter for NotifyProductChanged(). The advantage of working this way is that the item on screen doesn't get updated every time a single property changes and only if you're done with updating the whole item yourself..
The advantage ofcourse of using the way Tim showed is you don't have to keep any single change in mind of you update the item..
But in this case I think using the whole AutoMapper is overkill compared to just calling the ResetBindings/ResetItem..
On the explanation for why the display models should be in the WPF UI project. Think about if you had different interfaces for different people, Mobile with Android, iPhone, MVC Web App, Console App. Each would have different ways of presenting things
Correct, which is why each UI should probably have its own models for display.
Hi, this is a great video. I am wondering why the SelectedCartItem?.Product.QuantityInStock > 0 was checked instead of SelectedCartItem.QuantityInCart >0? I think even the QuanityInStock == 0, we can still remove the item from the cart. I didn't see the cause.
We do the SelectedCartItem?... because we are doing a null check on SelectedCartItem. If nothing is selected, we would get an exception otherwise. You cannot access a property on a null object.
@@IAmTimCorey I found you fixed the issues at the beginning of next video. Thanks
Hi Tim, thanks for this video, it was really helpful. I would like to ask you, though, if is there any chance you can extend your Getting Started with .NET Core course, or create an in-depth one to explain the authorization part of .Net Core and how we can make use of roles, policies and claims.
Thanks again for your efforts.
I am designing and building a .NET Core Start to Finish course that will build a web-based app. I'm hoping to have the course out this fall.
Hi Tim, thanks a lot for your videos and for this course in particular. Just downloaded the project via github to another machine and getting 400 response when trying to log in. all packages are installed as I can see. in another machine where the project has been written all works good.
Did you create the user on that other machine? Remember that the database gets created on every machine you are on unless you created a centralized database for your authentication.
@@IAmTimCorey thank you so much! I think this is the problem, just didn't think about it.
Hi Tim, thank you for this video. One question/suggestion:
CanRemoveFromCart(), isn't it redundant to add "?" after SelectedCartItem? If the first condition is not true (SelectedCartItem is null) the second one will never be checked (because you use "&&" operator). Going forward I suggest that we can simplify entire method to one condition: SelectedCartItem?.Product.QuantityInStock > 0. In case when "?" operator catches null entire if will be false.
Yep, I just forgot to remove that first statement. We don't need it.
I wonder if you found yourself setting up that called event a lot if it would make a case for having models inherit from a base class that is abstract. It might be overkill now, but later..... if the software got really large maybe.
I'm generally cautious about inheriting from a base class for general code sharing. This might be the case for a snippet though.
I'm a couple of years behind this, but when I was trying to get the Items and Cart boxes to update, I just went
Products.ResetBindings();
Cart.ResetBindings();
All good. No need to create separate models or do AutoMapper! is this the wrong way to do it?!
The issue here is that ResetBindings will refresh the list and move your selection. So if you had a record selected, now it will be unselected. I wanted to avoid that and do it right.
@@IAmTimCorey Ahhh, OK I see what you mean. Yes, it does lose the focus, so you would have to reselect if you wanted to remove more of the same item. I have two points, one is a suggestion and the other a query. The first is that I control how many are removed from the cart by using the item quantity box. So if I have 5 in the cart and I want to remove 3, I place that number in the quantity box and it will remove 3 items. To help control this further, the Add button is highlighted when you select an item in the Item ListBox and the Remove button when you select an item in the Cart ListBox. Both buttons can't be active at the same time. The query is, with this in place, if you add 5 of the 10" Frying Pans and then remove 3 of them (here the Add button is now unhighlighted and the Remove button is highlighted). If you then try to select Frying Pan again to Add from the item ListBox, nothing changes. You need to select another item for the NotifyOfPropertyChange to take effect and the Add button to highlight. The ListBoxes seem to keep a 'soft focus', so even if you move from one to the other (selecting the last selected item again), nothing changes. Thanks for all that you do. Because of you, I am getting the bug for this programming stuff and the days fly by.
There is one more suggestion I have. What is your opinion on using interfaces for the models since many are repeated. I saw many videos that showed that interfaces should be used for nearly everything.
I don't use user interfaces for models because there is no need (typically). We use interfaces so that we can replace one type with another. That is helpful for unit testing or changing how a system acts. Data is just data. It doesn't need to be swapped out for a different class that also holds the same type of data (99% of the time).
Hi Tim, put a search box above items.
That’s on the suggestion list.
Great Idea!
One more thing..please deo a gud use of how to use dictionary/List as a candidate to use when implementing search,,food for thought..
Hi Tim, do you recommend using AutoMapper on the Web API side? For mapping DTO to your Data Models and vice versa? Are there performance issue?
If you need it, yes. AutoMapper is performant, so the only real "issue" is that you are creating multiple objects but that cannot be helped at that point.
You should try fody wearer, it will allow you to remove all NotifyPropertyChange. It become a get set prop
I will add it to the list. Thanks for the suggestion.
Fody Weaver
So question about the CanRemoveFromCart. If you are checking QuantityInStock that's the amount that should be showing on the left right? So if you have no stock left, and want to remove and put it back you'll be blocked? Am I misreading that?
(nvm looks like someone else caught it first.)
Yep, that was caught.
Hi Tim can we replace this UI with any front end framework
Yep.
Thanks for the great videos Tim. In the display models, you invoke events, but you never added a listener for those events in the view model. Why does this work?
It works based upon convention (one of the things Caliburn Micro makes easier). So if I have a button named AddToCart, it will look for the AddToCart method in my ViewModel and match the click event to that method.
I have one question from the video. When I saw you enter the information for a full property, i noticed that after you typed in one text, it did the other automatically. How was that done? because everytime with a standard snippet, i was forced to enter twice. once with the _ and lower case and the other with uppercase. I hope that resharper is not required. Is there a way to make it work like that without paying for resharper?
I had copied the name from the auto-property and pasted it in for the full property name. No, you don't need to pay for Resharper if you don't want to. I don't use it (mostly because I try not to use paid products for my videos).
I have a question. In the beginning of the video, you mentioned a special where if you donate 10 dollars a month via patreon, then you get a pdf with ideas for apps. I paid the 10 dollars but did not see any pdf file on the site.
The way Patreon works is that it will send out the PDF to you when the promotion closes. I did get your email but I'm just now recovering from vacation. I'll respond more fully there in a bit.
@@IAmTimCorey Thanks for letting me know. I will really be looking forward to it. Because I just finished redoing my game package and was going to redo again when .net core 3 hits in september. Until then, I don't have much to do.
I've been trying to find my bug... I'm not sure what has caused it, or how to fix it, but I can put break points in my code to view the _quantityInStock, and it will decrease relative to the cart quantity, but when I try to run my program the inventory stock on the sales view page wont lower when I add something to the cart...
also now when I removed the hack I can only add 1 item to the cart... I am assuming I don't have something wired up properly and I should just revert back to my last push and start the video again from scratch.... I had some issues when renaming the ProductModel and CartItemModel to the DisplayModels respectively and accidentally renamed everything in my whole solution, I managed to go back and put the ProductModel and CartItemModel back in and I am pretty sure I renamed everything I need to, but I think I screwed something else up in another script somewhere
I just reverted back in github, and re-started from the beginning of the video, I either screwed up with the mass rename across the solution, or I chose the exact same version of AutoMapper that was shown in the video instead of v10 or something, and when I restarted I picked the absolute newest version of AutoMapper, I think the issue was the rename though.
I am glad you got it working.
Overdue but might help someone else. My issue was on the CallPropertyChanged methods, I had new PropertyChangedEventArgs(nameof(propertyName)) whilst passing in the QuantityInStock like so: CallPropertyChanged(nameof(QuantityInStock));.
So I ended up using nameof twice. No error so could be an easy miss.
So when we're calling Invoke, it should be
new PropertyChangedEventArgs(propertyName)
not
new PropertyChangedEventArgs(nameof(propertyName)).
Well it depends what you want to pass in I suppose but if you're following along, it'll cause an issue :)
@@MrGwarpy I was having the same problem and going nuts. Thank you for calling it out!
U can use [CallerMemberNameAttribute] in CallPropertyChanged
public void CallPropertyChanged([CallerMemberName] propertyName = "") { ... }
Then u don't have to use name of property when call/invoke CallPropertyChanged
Thanks for the suggestion. I don't think I've ever tried that.
@@IAmTimCorey When you change this though, make sure you STILL pass in the nameof(DisplayText) in the "QuanityInCart" Property in CartItemDisplayModel as you're calling the propertyChanged twice there.
CallPropertyChanged();
CallPropertyChanged(nameof(DisplayText));
public void CallPropertyChanged([CallerMemberName] string propertyName = "")
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Hi Tim, I need your help concerning Models, i am making a web application with 3 tire Architecture, and i am confused about Models. I have models in my Dal and my business layer and Mvc both uses the models from dal. I have only view models in my Mvc. Should i make separate library for models and use them all over the projects or should i make a new sets of models in my Mvc and Map them with models from dal using AutoMapper in my Mvc ?
It depends if you need different models or if you can get away with reusing the same models as your DAL. It also depends on the size of your project and what you intend to add to it.
Hi Tim, I'm having trouble getting the data bindings to work (as you showcase at 23:50). My quantity stays at 10 after i press "Add to cart". I have tried undoing everything and starting over from the beginning of this video to make sure I wrote the same code as you did. Do you have any idea how i could debug this?
Well, breakpoint the AddToCart method to see what is happening. Maybe you are actually doing the work but the display is not getting updated. Or, maybe the work is not getting done properly. That is a good place to start.
@@IAmTimCorey Thank you so much for your quick answer, I really appreciate your outstanding work with this course!
I have now debugged the AddToCart method and I can clearly see that the QuantityInStock property of the SelectedProduct is reduced to 9 from 10 however the quantity wont update in the UI.
I've also added tried debugging with tracing:
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"
But from what i can understand from this trace output message is that the binding is initializing properly:
System.Windows.Data Warning: 56 : Created BindingExpression (hash=15674164) for Binding (hash=43691456)
System.Windows.Data Warning: 58 : Path: 'QuantityInStock'
System.Windows.Data Warning: 60 : BindingExpression (hash=15674164): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=15674164): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=15674164): Attach to System.Windows.Controls.TextBlock.Text (hash=16654654)
System.Windows.Data Warning: 67 : BindingExpression (hash=15674164): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=15674164): Found data context element: TextBlock (hash=16654654) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=15674164): Activate with root item ProductDisplayModel (hash=1503503)
System.Windows.Data Warning: 108 : BindingExpression (hash=15674164): At level 0 - for ProductDisplayModel.QuantityInStock found accessor RuntimePropertyInfo(QuantityInStock)
System.Windows.Data Warning: 104 : BindingExpression (hash=15674164): Replace item at level 0 with ProductDisplayModel (hash=1503503), using accessor RuntimePropertyInfo(QuantityInStock)
System.Windows.Data Warning: 101 : BindingExpression (hash=15674164): GetValue at level 0 from ProductDisplayModel (hash=1503503) using RuntimePropertyInfo(QuantityInStock): '10'
System.Windows.Data Warning: 80 : BindingExpression (hash=15674164): TransferValue - got raw value '10'
System.Windows.Data Warning: 84 : BindingExpression (hash=15674164): TransferValue - implicit converter produced '10'
System.Windows.Data Warning: 89 : BindingExpression (hash=15674164): TransferValue - using final value '10'
Lastly i tried adding
"NotifyOfPropertyChange(() => SelectedProduct);" at the end of the AddToCart method but no luck...
Where should I look next?
@@IAmTimCorey After some more testing I tried, in the SalesView, to put the "quantity in stock" textblock (
) outside the stackpanels to see if, maybe, the binding was not able reach out from so many panels (made sense in my head when i came up with the idea haha). And to my surprise, the binding now worked! But i was even more surprised when I put the textblock back, inside the stackpanels, because it was working there as well. So now i'm sitting here, 2 days later, with the same code that wasn't working before but is now working perfectly. And according to the history and comparing feature of the team explorer the code is the same. How weird isn't that??
Alright, finally I tracked down why my bindings weren't working. I had accidentally added a extra "nameof" in the CallPropertyChanged Method
I had done this:
public void CallPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(propertyName)));
}
instead of this:
public void CallPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
@@antoneriksson208 Oh Kernigan and Ritchie. I had the exact same problem. Then traced it to this. Thank you for posting that. I don't think I would have noticed that it didn't have nameof
Visual studio can convert auto-properties to full ones with "Ctrl+.".
Yep, that's a nice feature.
Спасибо вам, привет из России)) Thank you, greetings from Russia))
Greetings from Texas! ... um, I mean United States. :-)
@@tomthelestaff-iamtimcorey7597 Ok)))
I'm a Patron Member, but I can not get to the sample code??
I post a message on Patreon each week that there is a TimCo video released, so if you want old video code, you will need to go back and find it. No guarantee that it will be there, but it should be.
CartItemDisplayModel and ProductDisplayModel, both have same event and method calling that event. So I created a new class for that event and method, called PropertyChangedBase, and inherited CartItemDisplayModel and ProductDisplayModel from that class. Maybe I can have another displayModel class in the future, and I can then inherit again from that base class
Inheritance shouldn't be used as a code-sharing mechanism. I don't see enough of a relationship here to justify the base class.
@@IAmTimCorey But then again, you're using the ProductDisplayModel/CartItemDisplayModel purely for displaying items AND the need for PropertyChanged Event, so it does make sense to use a base for it, but I'd rather would call it DisplayModelBase so more functionalities/properties that might be common to the needs of a ....DisplayModel class..
Hi Tim, thank you for your incredible tutorials! I have a problem fetching data between 2 laptops. I decided to fetch code of all 21 tutorials via github to my second laptop, and this is where some problems start. I can't login because of WPF's "internal server error". I decided that I need first to register with the postman, but It returns a post 500 internal server error (.mdf file is missed and also a bunch of sql server exceptions ). I would appreciate any help. Thank You.
I go over this later on in the series (how to put everything on a new machine). You will need to publish your SQL database and update your connection string (potentially). There are some other tweaks you will probably need to do as well.
Thank you Tim, I appreciate that! And I'm looking forward to the upcoming tutorials.
Hi Tim, could you be so kind and explain difference between INotifyPropertyChanged and INotifyPropertyChanged?
NotifyOfPropertyChange is something specific to Caliburn Micro that adds some extra features but it is really close to INotifyPropertyChanged.
As tim said in his comment, caliburn micro adds some extra features and you can see this by pressing F12 on INotifyOfPropertyChanged and see that it inherits from INotifyPropertyChanged.
A Touchscreen-focused UI for the Sales page would be cool, turn a Surface or something like that into a portable PoS machine
Something like that is coming.
I think a more normal behavior for removing from cart is to remove the item completely instead of lowering the quantity one by one. If the user cannot change the quantity in the chart directly it is easier for him just to add the item again with the right quantity. That makes the logic much simpler too by doing:
SelectedCartItem.Product.QuantityInStock += SelectedCartItem.QuantityInCart;
Cart.Remove(SelectedCartItem);
Best regards
Thanks for the thoughts.
Could you please explain me Team Explorer with GIT
I will add it to the list. Thanks for the suggestion.
Thank you .more power!
You are welcome.
i have no idea why, but
for Products listbox I can use SelectedItem="SelectedProduct" (where caliburn takes care of the binding),
yet for Cart listbox I had to use SelectedItem="{Binding SelectedCartItem}, as SelectedItem="SelectedCartItem" did not work no matter what, even with everything else being exactly the same
not really a problem, I just like to use caliburn's bindings (where it is possible)
I don't have the code in front of me but I believe it has to do with using the name in more than one spot.
@@IAmTimCorey I was just googling for something completely different ( but still wpf related) and the article I stumbled upon included, among others, the usage of caliburn and on the very first page, there was an example showing how caliburn binds the selected item of a listbox
and apparently, it uses the following naming pattern:
- it checks the xaml element (listbox) name
- if the name is plural (ends in "s") it makes it singular
- binds to a property named "Selected[singular_form_of_element_name]"
it's nice when things work out by themselves
so we dont need the CartItemModel in the UI Library.
Correct. We create CartItemDisplayModel for the UI so we can have UI-specific stuff in it.
CanRemoveFromCart should really just check if the item is selected, because if there isn't any quantityInCart, you should still be able to remove it from the cart, RemoveFromCart should check if it should increase Product.QuantityInStock.
That situation should never happen. By not covering this possibility, you would be "approving" a bad state and pretending it was an OK state. That's not a wise choice. You would be allowing something to go through that another method had to properly handle or you would introduce a bug. A bug that shouldn't show up but when it did, it would be hard to track down.
@@IAmTimCorey Except now if someone would call RemoveFromCart in another spot, it might go all wrong, because now you are assuming that everything has been set up properly before RemoveFromCart is being called (hell we even assume SelectedCartItem is not null). In reality it shouldn't even matter if the remove or add button is disabled at all, as long as the RemoveFromCart en AddToCart would handle it correctly.. You might for instance add a keyboard shortcut to remove the item from the cart or another extra button..
Again, now you handled a protection from outside the RemoveFromCart, while RemoveFromCart would be the one that actually does all the checking if it should increase the QuantityInStock or decrease the QuantityInCart or remove it all together. Apart from checking is there actually is a CartItem selected, the only check to make it 'foolproof' is to check if we are allowed to increase the QuantityInStock (which you only should do if QuantityInCart > 0)..
First, we don't assume SelectedCartItem is not null, we check for that first. Second, we have a method for removing items from the cart. Why would we do the same action somewhere else a different way? If we are going to remove the item from the cart using a keyboard shortcut, that shortcut is going to utilize the CanRemoveFromCart and RemoveFromCart methods.
Also, i had a suggestion. It would be easy to create a simple class that has the basics for INotifyPropertyChanged so you can inherit and not have to copy/paste so much code.
This is actually what the mvvm frameworks do. You could inherit from Screen, as well, think.
You could, but that means that every class needs to be related. Inheritance isn't just a code-sharing mechanism.
Cool
Thanks!
Is this still valid for v9?
I haven't checked to see if there are any breaking changes. I would recommend getting it to work with the version we used and then updating the version to see if it still works.
@@IAmTimCorey Thank you for your answer, I will try that way
Fody PropertyChanged , I'll just leave this package for anyone who likes automation
Thanks for the suggestion!
I love Fody PropertyChanged, it saves so much boilerplate code :-)
Hi mate , i got one question , i dont really have idea how to exactly achieve it , im working on a project where in certain time some of checks(bool) should get changed either it have any traffic active or not , would be nice if you can give any clue Much Appreciated.
I'm not sure what you are asking. Can you clarify?
i mean what if i want to send a notification to user at specific time , their must be something running 24/7 and checking if its time to send notification and when it is it will send ...
If you are doing it locally, look into Windows Services (I did a video on them). That can send messages or do other work based upon time. If you can run things in the cloud, check out Azure Functions. They are free for low to moderate usage and you can use a time-based function to kick off a task or job.
@@IAmTimCorey i just needed a hint i will surely research on them now , Thank you very much Appreciate it.
Modifying on-hand inventory in the client is not something that would fly anywhere I've worked.
It depends on what you mean. When you sell something, you modify the inventory. When you accept something into inventory, you record it. Those all go through a UI of some type.
Please increase your volume
My volume is auto-leveled at a high level. I'm not sure I can increase it.
automapper? SHAME!
Why exactly? That's the entire purpose of the tool. It has been optimized and honed to do one thing well and that's what we are using it for. I don't reinvent the wheel when I don't need to.
@@IAmTimCorey I know, don't take it personally. But the use of reflection (automapper) in a big project is something that the people have take into consideration.
I covered that in the video. Yes, it uses reflection but at startup, not throughout your project. That means you take a minor performance hit on startup but that is it. That is, in my estimation, a perfectly acceptable trade-off to creating custom mapping methods for each method you need to map. Even if you do it by hand, it probably won't be as performant as what Automapper will do. My thing is that you shouldn't hide from reflection. You should just know the downsides and you should weigh them against the alternatives. In this case, a small performance hit that none of my customers will see is totally worth it.
@@IAmTimCorey I agree. By he way, Caliburn.Micro (and other MVVM solutions) reliess heavily on reflection. I think trying to do it only once is a good strategy.
@@IAmTimCorey Except it does require the automapper (which takes up space/memory) and the more items you're gonna map, the longer it takes to start the application and the larger the memory footprint. Maybe there is something wrong with the design if you are using it a lot in your application...