|
Supersonic posted:I'm going to look into this tomorrow night. I had been using a task because my TUI was being blocked during audio playback. I put my play code inside Task.Run() and this stopped the blocking, but also caused the issue of letting me open and play multiple audio files at once. https://github.com/naudio/NAudio/blob/master/Docs/PlayAudioFileWinForms.md This approach should also work in a TUI, and seems to have all the niceties you want built in.
|
# ? Oct 28, 2020 19:18 |
|
|
# ? Jun 8, 2024 09:30 |
|
Trying to combine code-behind event handlers with WPF data binding is a great way to run into bizarre bugs that make you tear your hair out. It can work, but when it doesn’t, debugging it is awful. Just use a command - they’re pretty straightforward once you write yourself a RelayCommand (I’m phoneposting so just google that and follow one of the examples you find). You can either figure out the binding incantations to pass the clicked button’s data context as a command parameter and save whatever you need that way, or you can model the current section in the view model and have the command go get it itself.
|
# ? Oct 28, 2020 19:21 |
|
Okay I might as well play with relaying commands tonight as a starter for interaction. I tried to bind to the SelectedItem property in the ListView to an integer property in the code-behind, but it always just came back zero. That was with a click handler, not with a command and in integer property in a separate view model class. I am chalking it up to late night bad luck for now.
|
# ? Oct 28, 2020 19:46 |
|
Bruegels Fuckbooks posted:The way I do it is: Preach. This is what I would have posted, but you said it better than I would have. Bruegels Fuckbooks posted:c) Your viewmodel gets your model classes through a service, which does whatever CRUD operations on wherever the data source is and creates your model classes. Bonus points if you inject this service via IoC container. Which may not appear to make sense for small applications, but anything of substance will benefit from this pattern. Bruegels Fuckbooks posted:If you need to communicate events between multiple models/viewmodels, a common temptation is to have them subscribe to each other. That can work, but if it gets too complicated to deal with, use pub sub or the event aggegator pattern. When you say "communicate events" and "subscribe to each other" what specifically do you mean? Subscribe to INPC and look for the nameof(MyProp)? Or a different event?
|
# ? Oct 28, 2020 19:52 |
|
epalm posted:Preach. This is what I would have posted, but you said it better than I would have. So one time, I had to introduce a viewmodel property which depended on the status of several objects in my model. E.g. Say a checkbox is checked if object1's status is true, object2's status is true, object3's status is true... I had an advanced settings popup where you could toggle the status individually, but the viewmodel property was supposed to reflect the status of them all combined. So I had the big brained idea of "Hey, you know, maybe my viewmodel just subscribes to the INotifyPropertyChanged of each of the models and changes the state as they change" (I might not have been getting enough sleep at the time) I made the PropertyChanged event of the models public, wrote a method in my viewmodel to check the status of the models, and made it so when one of the models would change the property, the viewmodel would trigger an OnStatusChanged and toggle its status dependent on the model. Don't that. This is stupid because it couples your viewmodel with your model, and for many other reasons. With pub sub / an event aggregator though, you can just fire events like "order placed" or "status changed", and whatever is listening responds. If you're ever in the situations where you're like "jesus christ, there's all these classes within classes and models and such, how do I get them to talk to each other", that's how you solve that.
|
# ? Oct 28, 2020 21:30 |
|
Bruegels Fuckbooks posted:With pub sub / an event aggregator though, you can just fire events like "order placed" or "status changed", and whatever is listening responds. If you're ever in the situations where you're like "jesus christ, there's all these classes within classes and models and such, how do I get them to talk to each other", that's how you solve that. Any pubsub or event aggregators you've used that've worked well in WPF apps? When you say "you can just fire events like "order placed" or "status changed", and whatever is listening responds" to be honest this just sounds like normal events.
|
# ? Oct 28, 2020 21:38 |
|
epalm posted:Any pubsub or event aggregators you've used that've worked well in WPF apps? An event aggregator is pretty simple - I'd recommend this article: http://www.nichesoftware.co.nz/2015/08/16/wpf-event-aggregates.html which actually includes the full source. Microsoft has a similar article here https://social.technet.microsoft.com/wiki/contents/articles/23314.using-the-event-aggregator-pattern-to-communicate-between-view-models.aspx but it doesn't explain the problem as well. Some WPF UI frameworks like prism will include an event aggregator in the framework, and you can use that if it's present.
|
# ? Oct 28, 2020 21:58 |
|
epalm posted:Bonus points if you inject this service via IoC container. Which may not appear to make sense for small applications, but anything of substance will benefit from this pattern. How do you all implement DI in a WPF project? I find myself using the locator pattern, where there is a Locator class which has a ServiceProvider, registers all the services needed, and exposed properties like C# code:
C# code:
|
# ? Oct 29, 2020 00:23 |
|
The locator pattern is an anti-pattern because it's essentially a static god object that gets you everything everywhere and in doing so hides each and every dependency of a class behind a runtime error. Just imagine trying to instantiate a class that uses the locator pattern when starting from a blank slate (i.e. no services registered with the locator at all). With classic constructor injection you see every dependency right there and then before even compiling. You provide those dependencies and it will work. With locator you instantiate it and then only during runtime it will fail with the first missing service. Then you add that and it will fail again with the next one. Then after some trial and error it finally works until you call a method on that class that itself also uses the locator to load yet another missing dependency. Repeat ad-infinitum. E: Can't really answer the question what's good to use for DI in WPF in practice as I was successfully able to avoid having to use it so far, but I can't see why basic stuff like TinyIoC won't work in principle. SirViver fucked around with this message at 00:43 on Oct 29, 2020 |
# ? Oct 29, 2020 00:37 |
|
necrotic posted:https://github.com/naudio/NAudio/blob/master/Docs/PlayAudioFileWinForms.md Thanks for this! I've worked the ideas into my code and this approach is working great. No more Task.Run() or Mutex.
|
# ? Oct 29, 2020 00:46 |
|
LongSack posted:How do you all implement DI in a WPF project? I find myself using the locator pattern, where there is a Locator class which has a ServiceProvider, registers all the services needed, and exposed properties like I never had a problem just using microsoft unity for dependency injection - I've used like five different DI frameworks in .net and frankly I could not give a gently caress about the differences, they all worked. This article is pretty much how I did it last time. https://stackoverflow.com/questions/36631149/dependency-injection-with-unity-on-wpf-mvvm-application For service locator, the reason it's bad is that service locator is essentially a fancy way of making all your poo poo static, and it also doesn't really deal with teasing out which services depend on other services so it's a pain in the rear end. Constructor injection is nice because your startup does all the wiring, and you can figure out what all the dependencies of a class are just from looking at the constructor. Bruegels Fuckbooks fucked around with this message at 01:16 on Oct 29, 2020 |
# ? Oct 29, 2020 01:13 |
|
epalm posted:Bonus points if you inject this service via IoC container.
|
# ? Oct 29, 2020 01:17 |
|
adaz posted:The easiest way to accomplish this is to implement what's called a cancellation token. You would wire up your while loop to see if the cancellation token was called. Then you can abort it. Depending on how you want to do this, the easiest thing to do is setup a additional method on your IPlayer interface called Cancel() that just invokes the cancellation token and call that from whatever needs to cancel the audio file. On a sidenote, do you by any chance have recommendations for books or guides that deal with tasks and threading? I just want to make sure I don't run into any pitfalls (like Mutexes inside of Task.run) again going forward.
|
# ? Oct 29, 2020 02:01 |
|
Yeah I'm having uncomfortable amounts of success with a ViewModel. Setting a command for a button in the template is letting me run the callback against the button data it represents directly so I don't have to do any lookups or anything. Also, all of the buttons in my template were instantiated and displayed in the designer now. I'm trying to come to terms with how so much stuff just kind of worked. I'm guessing a lot of the stuff around data contexts have grown to assume you use view models of some sort. One big concern I have is RelayCommand. That isn't stock so I'm trying to figure out where to properly source it without a license issue. I'm not sure how well getting it from a NuGet package is going to work when I move this all to Unity3d and try to use it with NoesisGUI.
|
# ? Oct 29, 2020 08:08 |
|
Rocko Bonaparte posted:Yeah I'm having uncomfortable amounts of success with a ViewModel. Setting a command for a button in the template is letting me run the callback against the button data it represents directly so I don't have to do any lookups or anything. Also, all of the buttons in my template were instantiated and displayed in the designer now. I'm trying to come to terms with how so much stuff just kind of worked. I'm guessing a lot of the stuff around data contexts have grown to assume you use view models of some sort. The original article introducing the RelayCommand is here: https://docs.microsoft.com/en-us/archive/msdn-magazine/2009/february/patterns-wpf-apps-with-the-model-view-viewmodel-design-pattern. If you use the mvvmlight toolkit http://www.mvvmlight.net/, RelayCommand is part of it and it's under MIT license. https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/may/mvvm-commands-relaycommands-and-eventtocommand. You could just source it through that.
|
# ? Oct 29, 2020 12:11 |
|
You can just write your own RelayCommand, they’re like ten lines long.
|
# ? Oct 29, 2020 13:45 |
|
raminasi posted:You can just write your own RelayCommand, they’re like ten lines long. Until you start using async/await and have to write AsyncRelayCommand with all the complexity that comes with it
|
# ? Oct 29, 2020 14:02 |
|
epalm posted:Until you start using async/await and have to write AsyncRelayCommand with all the complexity that comes with it AsyncRelayCommand wasn't much more complex - decent MIT license example was https://johnthiriet.com/mvvm-going-async-with-async-command/. At least where I've worked nobody cared about nuget sourcing stuff like relaycommand... I've seen projects where devs either control-c control-v stuff like relaycommand / event aggregators or just use stackoverflow links and it's never really been a problem. If it's posted as sample code on the msdn website it's fair game for inclusion in a project under microsoft limited public license. I can understand trying to be thorough about this to ward off legal problems though. Bruegels Fuckbooks fucked around with this message at 15:56 on Oct 29, 2020 |
# ? Oct 29, 2020 15:52 |
|
Supersonic posted:On a sidenote, do you by any chance have recommendations for books or guides that deal with tasks and threading? I just want to make sure I don't run into any pitfalls (like Mutexes inside of Task.run) again going forward. an oldy but a goody on async await TPL best practices from Tech Ed 2014 Async Await best practices from MSDN Magazine. TPL pitfalls from MSDN
|
# ? Oct 29, 2020 17:53 |
|
Not especially related, but CancellationToken and CancellationTokenSource can do some pretty cool things. One of my personal favorites is CancellationToken.Register which lets you set up a delegate to be called when the cancellation is triggered. The registration itself can be put in a using statement, so if you wanted to, say... call SqlCommand.Cancel for only a specific critical phase of work, it's not only possible, it's easy. Once the registration is disposed, the delegate is no longer registered or called upon cancellation.
|
# ? Oct 29, 2020 18:28 |
|
Bruegels Fuckbooks posted:I've seen projects where devs either control-c control-v stuff like relaycommand / event aggregators or just use stackoverflow links and it's never really been a problem. I would concede if there really was much variation in what it was doing so that one should write it for their own needs. Even then, everybody is giving it the same name!
|
# ? Oct 29, 2020 18:56 |
|
Rocko Bonaparte posted:I'm in for the MVVM approach but I find this pretty amusing. They want everybody to use MVVM but then leave out a pretty common thing that--dare I say, "is a common pattern"--and people just copy-paste it. Creating functionality that makes a potentially really annoying thing super straightforward but neglecting to implement a crucial, yet simple part of it is extremely on brand for WPF, the framework that makes hard things easy and easy things hard.
|
# ? Oct 29, 2020 20:00 |
|
raminasi posted:Creating functionality that makes a potentially really annoying thing super straightforward but neglecting to implement a crucial, yet simple part of it is extremely on brand for WPF, the framework that makes hard things easy and easy things hard. Part of the problem is that the developers of WPF hated being constrained by "frameworks" and wanted wpf to be very open ended and to make it so the UI isn't an anchor on your code. I think they largely succeeded in that goal, but man are React and Angular easier to deal with than WPF. I also do hate that stuff like "how do I put an enum in a combo box and bind it to my viewmodel?" or "how do I do radio buttons correctly" invariably ends up with a long stack overflow article with people arguing about value converters.
|
# ? Oct 29, 2020 20:16 |
|
adaz posted:an oldy but a goody on async await TPL best practices from Tech Ed 2014 David Fowler's writeup is also a nice introduction to this stuff.
|
# ? Oct 29, 2020 20:55 |
|
You cannot talk about async await without mentioning Mr Stephen Cleary! https://blog.stephencleary.com/2012/02/async-and-await.html
|
# ? Oct 29, 2020 21:15 |
|
rarbatrol posted:Not especially related, but CancellationToken and CancellationTokenSource can do some pretty cool things. One of my personal favorites is CancellationToken.Register which lets you set up a delegate to be called when the cancellation is triggered. The registration itself can be put in a using statement, so if you wanted to, say... call SqlCommand.Cancel for only a specific critical phase of work, it's not only possible, it's easy. Once the registration is disposed, the delegate is no longer registered or called upon cancellation. I didn't know the bit about disposable registers, super cool. I've been doing some node Dev recently and the lack of a "using" pattern really sucks.
|
# ? Oct 29, 2020 21:29 |
|
Rocko Bonaparte posted:I'm in for the MVVM approach but I find this pretty amusing. They want everybody to use MVVM but then leave out a pretty common thing that--dare I say, "is a common pattern"--and people just copy-paste it. This. I just used something like MVVM light. It makes life that much easier.
|
# ? Oct 30, 2020 08:56 |
|
Mr Shiny Pants posted:This. I just used something like MVVM light. It makes life that much easier. I think mvvmlight is nice. I've been following this thread for a while https://github.com/lbugnion/mvvmlight/issues/69 Incoming personal opinion: If you build an open source project with the intention of it being widely used (i.e. not a personal hobby project), then it's your responsibility to either maintain it, or gracefully abandon it by handing over the reigns. If you are able (i.e. you're not dead or homeless), you shouldn't just ghost the entire user base.
|
# ? Oct 30, 2020 14:33 |
|
epalm posted:I think mvvmlight is nice. I've been following this thread for a while https://github.com/lbugnion/mvvmlight/issues/69 It's a legitimate opinion. My opinion is that releasing open source code for free is an act of kindness by itself, and it's your responsibility as a user, when you choose to depend on an open source project for which you did not purchase a support contract, to have a plan in place in the event that the maintainer(s) are run over by a bus or decide to do something else with their lives.
|
# ? Oct 30, 2020 16:46 |
|
NihilCredo posted:It's a legitimate opinion. My opinion is that releasing open source code for free is an act of kindness by itself, and it's your responsibility as a user, when you choose to depend on an open source project for which you did not purchase a support contract, to have a plan in place in the event that the maintainer(s) are run over by a bus or decide to do something else with their lives. I like your opinion. I think my opinion and your opinion can co-exist. I agree that you should have a plan in case your dependency becomes unavailable, this sometimes even happens when you have a support contract but a business relationship changes. But locking a project in a GitHub repo and throwing away the key, while software projects and package managers and users all reference it, chips away at that original act of kindness. I respect the decision to walk away, just give someone else the key, willya?
|
# ? Oct 30, 2020 19:43 |
|
NihilCredo posted:it's your responsibility as a user, when you choose to depend on an open source project for which you did not purchase a support contract, to have a plan in place in the event that the maintainer(s) are run over by a bus or decide to do something else with their lives. 100%, especially if you're using this OSS library/tool in a project for your employer. I found this to be one of those lines between junior engineers and actual senior engineers. A seasoned engineer will research a OSS project thoroughly to vet its main contributors and overall repo activity. On top of that, a good engineer will design abstractions around the use of the library to make it easier to substitute another option if necessary later. Always prefer highly-active, popular libraries over newer options. Take a 'wait and see' approach to newer stuff to ensure it has staying power (this applies to Microsoft's stuff as well)
|
# ? Oct 30, 2020 19:52 |
|
epalm posted:I think mvvmlight is nice. I've been following this thread for a while https://github.com/lbugnion/mvvmlight/issues/69 It's been some years since I last used it. But the one thing that stood out to me was all the half-baked WPF stuff it solved.
|
# ? Oct 31, 2020 10:39 |
|
The whole experience with learning WPF and XAML is essentially trolling because most of the time if you try to use something like a UI tookit or a library to do something, you only need to understand the subset of the library necessary for what you want to do, and don't have to read article on article about the overarching philosophy of ***. With WPF, I initially approached it like "this is not cryptography, this is just putting a window with controls on it on a computer screen, why do I need to read all these articles or care about poo poo like view models?" Having that mindset will absolutely kill you with WPF because the framework will give you all the tools you need to hang yourself with monumentally lovely code, and actually taking the time to learn and understand the patterns makes the coding actually trivial.
|
# ? Oct 31, 2020 15:58 |
|
Bruegels Fuckbooks posted:The whole experience with learning WPF and XAML is essentially trolling because most of the time if you try to use something like a UI tookit or a library to do something, you only need to understand the subset of the library necessary for what you want to do, and don't have to read article on article about the overarching philosophy of ***. With WPF, I initially approached it like "this is not cryptography, this is just putting a window with controls on it on a computer screen, why do I need to read all these articles or care about poo poo like view models?" Having that mindset will absolutely kill you with WPF because the framework will give you all the tools you need to hang yourself with monumentally lovely code, and actually taking the time to learn and understand the patterns makes the coding actually trivial. This is what I meant, if you want to do it the "right" way you need to code a lot of scaffolding first. Which is one the reasons, I guess, why it never really took off.
|
# ? Nov 1, 2020 09:42 |
|
Bruegels Fuckbooks posted:The whole experience with learning WPF and XAML is essentially trolling because most of the time if you try to use something like a UI tookit or a library to do something, you only need to understand the subset of the library necessary for what you want to do, and don't have to read article on article about the overarching philosophy of ***. With WPF, I initially approached it like "this is not cryptography, this is just putting a window with controls on it on a computer screen, why do I need to read all these articles or care about poo poo like view models?" Having that mindset will absolutely kill you with WPF because the framework will give you all the tools you need to hang yourself with monumentally lovely code, and actually taking the time to learn and understand the patterns makes the coding actually trivial. This is a gospel truth and it really, really sucks because some of those important patterns seem either estoric or needlessly verbose, especially on a first read. I actually really like WPF, but I've written some pretty trashy poo poo on my journey to writing slightly less trashy poo poo now, and almost all of it was borne from an attitude of, 'This seems needlessly complex/annoying to implement/boilerplate for the sake of boilerplate and I probably don't actually *need* it...
|
# ? Nov 1, 2020 09:46 |
|
rarbatrol posted:Not especially related, but CancellationToken and CancellationTokenSource can do some pretty cool things. One of my personal favorites is CancellationToken.Register which lets you set up a delegate to be called when the cancellation is triggered. The registration itself can be put in a using statement, so if you wanted to, say... call SqlCommand.Cancel for only a specific critical phase of work, it's not only possible, it's easy. Once the registration is disposed, the delegate is no longer registered or called upon cancellation. That's loving awesome I did a tech talk for my department earlier this year demonstrating how to use cancellation tokens responsibly to ensure you don't unnecessarily bail out of a chunk of work mid-way. I used the notion of being a 21st Century Fox exec choosing shows to cancel: Firefly stops immediately when the cancellation token is triggered Dollhouse finishes a season once the cancellation token is triggered KVille cancels itself (oh no a writers' strike!) The Simpsons never checks the cancellation token and runs forever. I was able to demonstrate how to issue tokens, check them yourself, link multiple tokens together, and trigger visceral rage all in 15 minutes.
|
# ? Nov 1, 2020 18:27 |
|
The WPF thing I wish I could go back in time and tell myself is “make a conscious architectural decision every time you add INotifyPropertyChanged to something, don’t just subscribe everything to everything willy-nilly.”
|
# ? Nov 1, 2020 18:32 |
|
Model View Update is so much more simple and elegant.
|
# ? Nov 2, 2020 08:29 |
|
WPF is annoying the hell out of my but I'm still getting further quicker with less code than the shenanigans I was doing in Unity 3d using its GUI system. Now to contradict myself by posting about my next hiccup with it: I want to prompt when the user selects to overwrite a save. I created a UserControl to show the prompt and a view model to manage the prompt and choices. The command to overwrite the save is in the ViewModel for the save button. Everything became a mess when I tried to insert it there. I needed a back-reference to my main screen, which I then had to plumb all the way from my root ViewModel. But lo, I need a parameterless constructor, so I had to add it after initial creation. Then the saves wouldn't display because I was filling my container afterwards. I even set up INotifyChanged and fired OnPropertyChanged for the container--which is an ObservableCollection<> in the first place. I don't think the solution is figuring out how to get the way I did it to work. That whole thing just stinks. I'm guessing I should hook something up in the XAML for the save buttons but I don't know what. Well, I can do something, but I don't know how I block on the prompt and then carry over to the button's code to apply itself when the user accepts the prompt. What's the least painful way to manage this? Note that I can't use Window and its ilk in Unity 3d; my main window is using it right now for screwing around but it'll eventually become a UserControl too. So I gave up on using system modal dialogs here. Also, I assumed the system modals would class with the GUI's aesthetic anyways; I'm guessing most people don't use them in WPF (?).
|
# ? Nov 2, 2020 16:56 |
|
|
# ? Jun 8, 2024 09:30 |
|
Are you sure you really mean system modal dialog boxes?
|
# ? Nov 2, 2020 17:51 |