|
WPF question. I have a MainWindow that has a FooControl embedded in it, declared in XAML as a ContentControl. The XAML for the ContentControl, taken from MainWindow.xaml:code:
code:
There is a method on the FooControl itself that I want to call from the code-behind of the Main Window. (The method on the Main Window is an on-click handler for an image. The method I want to call on the FooControl gives keyboard focus to a button within the FooControl.) Now, I can associate the MainWindow with the MainWindowViewModel because it instantiates its own view-model on being constructed. I can associate the MainWindowViewModel with the FooControlViewModel, because the one is a property of the other and is instantiated by it. But I don't know how to get hold of the FooControl object from any of the other 3. So I can't figure out a way to call the method. Actually, that's a lie. I can call the method perfectly easily: this is a quick and dirty operation and both MainWindow and FooControl will only ever be instantiated once, so I made the FooControl a singleton with a public static "Instance" property (populated by the constructor), and I'm calling the method on the instance. But I would like to know what the proper answer is.
|
# ? Nov 28, 2020 20:58 |
|
|
# ? Jun 8, 2024 04:38 |
|
Fru fru hippy question about WPF: is it really pushing composition over inheritance? I've been doing some refactor where that is looking like the more natural thing to do now. I mean, it's what I would want to do, but I couldn't really figure out how to do it in its syntax. I'm just asking to help set up my sense of smell when doing stuff.Hammerite posted:There is a method on the FooControl itself that I want to call from the code-behind of the Main Window. (The method on the Main Window is an on-click handler for an image. The method I want to call on the FooControl gives keyboard focus to a button within the FooControl.) I've tried to do similar a few times already and WPF will punch me across the face for trying it. My spidey sense sees it in two parts. First, see if the image can send a command to the view model for when it's selected instead of trying to get the on-click event. You'd be done there but then you want to have the code-behind do something while you're inside the code for the view model. WPF will then punch you across the face there instead. The second part takes care of that trap. Create a property in the view model and implement INotifyPropertyChanged so the runtime will listen to it. Kick that off when your image's command is invoked. If the view model doesn't otherwise associate the image and the button, pass the button as an argument to the command. You'd then bind this property for the selected button in the XAML. ...or something. gently caress, just thinking about it makes me want to take a nap.
|
# ? Nov 29, 2020 19:05 |
|
I don't think you can directly assign a command to the "image is clicked" event. You can put the image on a button or something and do that. Regardless, I want to know where on the image the user clicked (I ought to have said this in the original post), so AFAIK I really do need a click event and not a command - the position on the image can be calculated using properties of the MouseButtonEventArgs.Rocko Bonaparte posted:The second part takes care of that trap. Create a property in the view model and implement INotifyPropertyChanged so the runtime will listen to it. Kick that off when your image's command is invoked. If the view model doesn't otherwise associate the image and the button, pass the button as an argument to the command. You'd then bind this property for the selected button in the XAML. The button is within FooControl, there is (AFAIK) no way to reference it from MainWindow's XAML so I don't think I can pass it as a command parameter even if I could use a command to do what I want to do (which as remarked above, I don't think I can). Both ViewModels implement INotifyPropertyChanged. If there's a way to cause a button to grab the keyboard focus in response to the PropertyChanged events of its owning control's DataContext, though, then that potentially solves my problem. I don't know that there is.
|
# ? Nov 29, 2020 23:48 |
|
Yeah okay that is more elaborate. At least for the image, have you tried using InputBinding's mouse clicking stuff? I never tried it but I want to think you can bind a command there and then pass along the control too.
|
# ? Nov 30, 2020 01:28 |
|
I found the answer. When the FooControl loads for the first time, 3 things happen in order:
For the first two, the DataContext is null. For the Loaded event, it's been set. So you can "say hello" to the FooControlViewModel at that point*, and from then on you've achieved your link. It's quite tortuous though, because when the user clicks on the image, my MainWindow code-behind has to call the MainWindow ViewModel, which has to call the FooControlViewModel, which has to call back to the FooControl code-behind. * When I do things like this I like to just provide the viewmodel with an Action<> or Func<> rather than a reference to the window itself, since that's the minimal amount of information needed in order to accomplish the goal. In this case the viewmodel will have an Action called something like "GiveFocusToButton". The Loaded event-handler in the code-behind will provide that Action to the viewmodel.
|
# ? Nov 30, 2020 11:22 |
|
It doesn't smell like the "right way" (lol) but it's not like I was particularly helpful either. I think I saw some StackOverflow stuff that was unrelated were somebody was trying to hit those handlers too and had a bunch of trouble. It looks like that was more their problem than anything else. It didn't help that it was one of those million "something something doesn't work" kind of posts where they don't even state how they expected it to work in the first place.
|
# ? Nov 30, 2020 21:30 |
|
My turn to ask WPF stuff again: how might I force a list view to show five buttons it contains without any scrolling? I'd want it to scale with the window size too. I'm trying to reuse my general user control for some presentation consistency. Otherwise, I'd just lay out those buttons explicitly in it's own XAML. I have a custom style for the list view that contains the buttons. At some point, I outright set the height for the buttons to an absolute number of pixels, but that gets screwy with different window sizes. If you wanted to see the junk I'm setting in that style: code:
Edit: I ended up doing binding shenanigans with a value converter. The button heights are set to 1/5 of the listview's height minus 1 for its padding. Or rather, it takes the number of buttons I want to use as an argument, but the argument is 5. It wasn't too huge of a chore to do it but I was surprised I had to go through all that. Also, Googling for how to disable a horizontal scrollbar in a list view was a real treat. I guess it was a huge hack for a decade or something until they just added a simple property for it. Rocko Bonaparte fucked around with this message at 22:09 on Dec 1, 2020 |
# ? Dec 1, 2020 08:58 |
|
Question about layering, I guess. So, in theory, and following the “single responsibility” principle, I should put all “business logic” in a layer between the ViewModels and some data access layer. This brings to mind a scenario where the ViewModel exposes a “Delete” command. The user clicks the delete button, only to be told (by the logic layer) that the item can’t be deleted because it has associated other items so deleting it would violate referential integrity. As an end user, I might reasonably ask, if the item can’t be deleted, why was the delete button enabled? This scenario poses to me a conundrum: how much business logic do I put in my ViewModels? As an end user, I completely understand that if an item can’t be deleted, then there either shouldn’t be a delete button, or it should be disabled. At the same time, I respect the separation of concerns. I suppose that I could have fields on my model classes like CanBeDeleted, but as the number of scenarios grows, this becomes unwieldy. Is there a good solution to this? TIA
|
# ? Dec 2, 2020 05:51 |
|
LongSack posted:Question about layering, I guess. So, in theory, and following the “single responsibility” principle, I should put all “business logic” in a layer between the ViewModels and some data access layer. In ICommand interface, there is a CanExecuteCommand(). If you implement CanBeDeleted in that method itself, then the button will enable/disable itself when RaiseCanExecuteChanged() fires (probably a property for a setting in your view model.) Exposing CanBeDeleted on your model class and checking it in CanExecuteCommand is how I handled this situation when it came up for me.
|
# ? Dec 2, 2020 06:56 |
|
Bruegels Fuckbooks posted:In ICommand interface, there is a CanExecuteCommand(). If you implement CanBeDeleted in that method itself, then the button will enable/disable itself when RaiseCanExecuteChanged() fires (probably a property for a setting in your view model.) Exposing CanBeDeleted on your model class and checking it in CanExecuteCommand is how I handled this situation when it came up for me. Yeah, that’s the only thing I could come up with. Just wanted to see if I was missing something (always a possibility). Thanks!
|
# ? Dec 3, 2020 01:00 |
|
A little bit of WPF XAML stuff: how can I draw a rectangle inside a grid, and have a plus sign inside that rectangle, and have the plus sign centered? I would have thought using center for horizontal and vertical alignment would do it, but it's actually a little below center.
|
# ? Dec 3, 2020 09:09 |
|
Rocko Bonaparte posted:A little bit of WPF XAML stuff: how can I draw a rectangle inside a grid, and have a plus sign inside that rectangle, and have the plus sign centered? I would have thought using center for horizontal and vertical alignment would do it, but it's actually a little below center. Is it text, or an image of a plus sign? Small snippets of text can be a bit of a pain in the arse to get perfectly vertically centered, not just in WPF but in other layout engines too, because the text rendering engine might not have the same idea about what vertically centered actually means. Text baselines, and all that sort of thing. An image is probably easier
|
# ? Dec 3, 2020 10:07 |
|
Hammerite posted:Is it text, or an image of a plus sign? Small snippets of text can be a bit of a pain in the arse to get perfectly vertically centered, not just in WPF but in other layout engines too, because the text rendering engine might not have the same idea about what vertically centered actually means. Text baselines, and all that sort of thing. An image is probably easier Yeah it's just text and I think you just sealed the deal on me using some kind of image instead. I can totally see a plus sign being off-center based on the font or whatever. Actually, I'll maybe delve into some of the drawing stuff in WPF for giggles but it'll probably become an image in the end.
|
# ? Dec 3, 2020 18:44 |
|
I opened up a new Project.log for a SA Forum Reader app I'm starting, Awful.NET. Right now it's a Xamarin.Forms Mobile app, with intentions to expand it out to desktop and other platforms. If anyone wants to screw around on a Xamarin app, or on a new .NET library for accessing SA, let me know.
|
# ? Dec 4, 2020 03:43 |
|
Drastic Actions posted:I opened up a new Project.log for a SA Forum Reader app I'm starting, Awful.NET. Will you be porting this to MAUI once it's practical to do so?
|
# ? Dec 4, 2020 08:32 |
|
beuges posted:Will you be porting this to MAUI once it's practical to do so? Most likely, but it'll probably still use XAML as the baseline for its views rather than all code and switch to MVU. Not because I'm against it, but I work at Microsoft on the underlying XAML Hot Reload code. So this project is a way for me to dogfood the tools I'm writing and file bugs against myself to fix them. Also, XAML is what the majority of .NET Devs know and use so I want to stick with something that others can contribute to easily. That's also (mostly) why it's in C# rather than F# .
|
# ? Dec 4, 2020 15:57 |
|
How might I attach a custom view source to a ListView in XAML? It looks like I can almost do all of this with just XAML without a custom comparer or anything, but I get stuck right at the end. I have this resource: code:
code:
As a side thing, I might actually have to use a custom Comparer<T> due to some shenanigans and I couldn't figure out how to specify that in XAML either. That was even worse. I'm trying to avoid having my buttons call back to the view model to sort the collection after operations happen.
|
# ? Dec 4, 2020 20:18 |
|
Is there any way to get a unique identifier of a Func? We want to do some caching, but right now the caller has to send a string key along with a Func.
|
# ? Dec 7, 2020 10:35 |
|
Can't you use the Func itself as a key? I know you can with a Dictionary.
|
# ? Dec 7, 2020 15:12 |
|
I have a question about dependency injection and .NET. I've tried Googling, but haven't had much luck finding an answer. I just keep finding variations of the same basic examples that aren't any more complicated than what I've already done. I'm still very new to the subject, only really messing around with it lightly from building a few simple REST services. I get the general gist of it, and it seems really straight forward in something like ASP.NET where the server has to magic an instance of a controller into existence when a request comes in and it creates the dependencies down the line without newing them up explicitly through code. But what about in something like a larger application where an end user is driving the experience and things may not be needed? For example, let's say I built some kind of swiss army knife console application with a variety of utilities in it. The user is presented with with a menu to select the task they would like to perform. Each of the various tasks does something completely different with its own set of dependencies (maybe they hit different database models, work with Windows services, read/build flat files, etc.) In this situation, there is a single entry point. I don't know what is going to be needed until the user makes a selection. I am pretty sure the option is not to inject numerous items into the base class's constructor. That would result in a lot of objects being instantiated that may not be necessary as the user might only end up performing one task out of a possible dozen. Another thought was that maybe I need a reference to the service provider and then use ActivatorUtilities (or something) to create instances when needed, but apparently passing around a reference to the service provider is an anti-pattern. It also feels like that could throw a wrench into testing as now my methods are requiring a service provider. Then I thought that maybe I do just need to "new" some of these items up, but what about when they need something I was planning to inject? I'd end up needing to pass them into the constructor, and well, then I need to new those up as well, and I'm way off track. I'm sure there are some accepted patterns to use here, but again, I'm not having any luck finding them. I either don't know what I'm trying to search for or my overall understanding is lacking. Any suggestions?
|
# ? Dec 7, 2020 15:58 |
|
GI_Clutch posted:For example, let's say I built some kind of swiss army knife console application with a variety of utilities in it. The user is presented with with a menu to select the task they would like to perform. Each of the various tasks does something completely different with its own set of dependencies (maybe they hit different database models, work with Windows services, read/build flat files, etc.) In this situation, there is a single entry point. I don't know what is going to be needed until the user makes a selection. lol'ing hard because I made an application for work that does exactly this and named it Swiss Army Knife (SAK because I'm a child ) I have no real insight as I made it out of a necessity to get some things quickly done so I'm sure anybody looking at the code would consider it a mess.
|
# ? Dec 7, 2020 17:33 |
|
You should just be able to do stuff "normally" in a console app, instances of dependencies will only be created as required. Tbh I wouldn't worry about it unless it was actually a performance problem if you've managed to set it up so that you build the world everytime anyway. e: I see what you mean actually now thinking about it. I think if it did turn out to be a problem to build everything (test it, it probably isn't), then in that case separating out the argument parsing from the rest of the app and then calling the service provider to get the object type you needed to handle those options would be fine. So you shouldn't be passing the service provider anywhere except into some big switch block to handle the args. distortion park fucked around with this message at 20:06 on Dec 7, 2020 |
# ? Dec 7, 2020 17:36 |
|
The other option is the "Factory" pattern ofc, but that's probably more effort than it's worth in this case
|
# ? Dec 7, 2020 17:44 |
|
Some frameworks (e.g. Autofac) allow dependencies to be configured as “lazy,” so they’re only instantiated once they’re needed. A concept that might help you is “lifetimes” - in normal web applications, per-request lifetime is usually the only one used so the concept can get glossed over in introductory tutorials, but there are other lifetimes to think about.
|
# ? Dec 7, 2020 18:34 |
|
pointsofdata posted:Tbh I wouldn't worry about it unless it was actually a performance problem This. Don't create a problem where none exists.
|
# ? Dec 7, 2020 19:35 |
|
Thanks for the suggestions. Thankfully, I'm not running into this problem at this point. I'm just trying to get into the habit of doing things properly. I really didn't touch .NET core until earlier this year because a lot of my code integrates with a third party system that is Framework based and only provided .NET Standard libraries within the past two months. Of course, they only work on the very latest build which none of our customers are on... Otherwise I'm typically building relatively simple console apps for backend integrations. For example, my upcoming project boils down to a console app that just polls a folder for files, parses the filenames, grabs additional data from a DB based on the metadata in the filenames, and then spits out a flat file with the expanded data so they can be ingested into a document management system. So, a very linear path where my question doesn't even come into play. Just figured I'd see if I could wrap my head around a larger solution.
|
# ? Dec 7, 2020 19:59 |
|
Thirding "don't worry about it". Your constructors aren't doing anything except storing a reference to other items anyway, no actual work happens in them (riiiiiiight? ), and references are cheap.
|
# ? Dec 7, 2020 23:12 |
|
insta posted:Thirding "don't worry about it". Your constructors aren't doing anything except storing a reference to other items anyway, no actual work happens in them (riiiiiiight? ), and references are cheap. https://blog.ploeh.dk/2011/03/04/Composeobjectgraphswithconfidence/ Build your object graph immediately, and don't worry about it. If you're going to have new objects, they should probably be popping out of Factories that the class needing them depends on.
|
# ? Dec 8, 2020 10:46 |
|
What's up with WPF visibility being an enum? I'm guessing it's some artifact from the early days that didn't get updated with the whole view model paradigm. I clearly am not the only person that had set up a boolean to determine whether to show or hide something. I see the visibility actually has three states so a boolean doesn't fully account for it, but I was kind of figuring there's be a basic show/noshow built in. That was just bizarre to deal with, and also makes me add additional stuff to expose a Visibility value instead.
|
# ? Dec 8, 2020 18:39 |
|
Rocko Bonaparte posted:What's up with WPF visibility being an enum? I'm guessing it's some artifact from the early days that didn't get updated with the whole view model paradigm. I clearly am not the only person that had set up a boolean to determine whether to show or hide something. Use a BooleanToVisibilityConverter in your XAML.
|
# ? Dec 8, 2020 18:47 |
|
Rocko Bonaparte posted:What's up with WPF visibility being an enum? I'm guessing it's some artifact from the early days that didn't get updated with the whole view model paradigm. I clearly am not the only person that had set up a boolean to determine whether to show or hide something. Having both "Hidden" (not rendered but occupies space) and "Collapsed" (not rendered, size 0x0) is legitimately useful sometimes. Most projects I've worked on have used both at least once. I've always just done it by exposing e.g. a "FooButtonVisibility" property of type Visibility on the viewmodel and setting that as appropriate but also I'm pretty sure I only barely understand MVVM so I have no idea if that's best practice or not.
|
# ? Dec 8, 2020 18:55 |
|
Rocko Bonaparte posted:What's up with WPF visibility being an enum? ... I see the visibility actually has three states so a boolean doesn't fully account for it Asked and answered! power crystals posted:I've always just done it by exposing e.g. a "FooButtonVisibility" property of type Visibility on the viewmodel and setting that as appropriate but also I'm pretty sure I only barely understand MVVM so I have no idea if that's best practice or not. Yeah that'll work in a pinch. I sometimes do this for expediency while coding. But I agree with fankey that the "correct" way in WPF is to write a reusable IValueConverter, in this case to fankey posted:Use a BooleanToVisibilityConverter in your XAML. epswing fucked around with this message at 19:52 on Dec 8, 2020 |
# ? Dec 8, 2020 19:19 |
|
epalm posted:Yeah that'll work in a pinch. I sometimes do this for expediency while coding. But I agree with fankey that the "correct" way in WPF is to write a reusable IValueConverter Honest question, how does this work when the visibility is more than a simple boolean, i.e. "visible if Foo is true and Bar is > 0, otherwise collapsed"? Am I supposed to write my own IMultiValueConverter? That seems like more work than a viewmodel property.
|
# ? Dec 9, 2020 03:55 |
|
power crystals posted:Honest question, how does this work when the visibility is more than a simple boolean, i.e. "visible if Foo is true and Bar is > 0, otherwise collapsed"? Am I supposed to write my own IMultiValueConverter? That seems like more work than a viewmodel property. I think it would be normal to expose a getter-only Boolean "IsVisible" property on your view-model whose getter contains that logic. In principle there is no difference between having a property of type Boolean converted to a Visibility, and just having a property of type Visibility. But usually when you have something that's conditionally displayed, your use case doesn't require its Visibility to be potentially able to take all 3 Visibility enum values. You just have 2 of them that you want it to take, and those are usually "Visible" and "Collapsed". This can be simplified to "is it shown or not", hence a Boolean, which is easy for someone looking at the code to understand at a glance.
|
# ? Dec 9, 2020 10:33 |
|
i.e.code:
|
# ? Dec 9, 2020 10:42 |
|
^ This is also one of the areas in which WPF XAML is lacking IMO, the Binding expressions are pretty bare bones and don't support any real logic. Probably would have been implemented if WPF development wasn't stalled for 10 years. In the past we used this thing: https://github.com/kentcb/WPFConverters which supports arbitrary expressions in XAML, but it's kind of verbose and still meh. Nowadays I would recommend https://www.reactiveui.net/ for UI stuff. It sort of has its own paradigm in which UI bindings are always defined in code, so you can pretty much do anything you like.
|
# ? Dec 9, 2020 13:34 |
|
Hammerite posted:i.e. I bind directly to the Visibility property. Sure it is three state, but there is no requirement to use Visibility.Hidden. No need for an additional property or converter.
|
# ? Dec 9, 2020 14:55 |
|
I think the decision to use a VM Visibility property vs an IValueConverter has several considerations. (A) Is this logic is reusable elsewhere, with other VMs and XAML views? If so, you probably want a converter. (B) Who do you want to make "responsible" for UI visibility? If this VM used by more than one XAML view, some of which need visibility switches, some of which don't, it doesn't sound like the VM should be responsible for visibility, and you probably want a converter. (C) How simple do you want to keep your VM? Pushing this logic out to a converter means your VM can be simpler (just a bool), and doesn't need to reference UI-related libraries and properties, which arguably makes testing your VM easier. That said, writing a converter class and hooking it up in XAML is more work that just writing a quick readonly getter property in your VM. I tend to write VM properties until it gets unwieldy (1 or 2 is fine, 10 starts to smell), and I start pushing them into converters as necessary to keep things simple, maintainable, and testable. epswing fucked around with this message at 16:49 on Dec 9, 2020 |
# ? Dec 9, 2020 15:24 |
|
power crystals posted:Honest question, how does this work when the visibility is more than a simple boolean, i.e. "visible if Foo is true and Bar is > 0, otherwise collapsed"? Am I supposed to write my own IMultiValueConverter? That seems like more work than a viewmodel property. Multi value converters aren’t that much more work than normal value converters. Here’s one I use to convert two doubles (space used, and quota) to a tooltip in the form of “xxx of xxx used”: C# code:
|
# ? Dec 10, 2020 01:38 |
|
|
# ? Jun 8, 2024 04:38 |
|
So I'm playing with .NET 5 now that it's out, and you can make .dbml files again, but there's no System.Data.Linq, so as far as I can tell, they don't frigging do anything. Do I really have to go back to data connections, writing every query out, and assigning each result to a variable manually? Because I can, but man, I don't wanna.
|
# ? Dec 10, 2020 19:39 |