Saving Draggable objects location wpf
I have like 10 different objects which can be draggable across canvas (textboxes, labels, WrapPanels, DockPanels, etc).
I would like to save their location so it will be shown after the restart.
What would be the best way to achieve that?
Obviously i could do like 3 bindable properties for each object (vlaue, positionX, positionY), but that would be 30 properties which would be really messy and like 150 lines of code (with mvvvm binding). Any idea?
7 Replies
I'd recommend setting up a base view model type that these items' view models can derive from, placing their positioning properties on that base type, and that way you don't have to worry about putting them on every class.
You can then pretty easily have your collection where all those items are stored in a VM just be a collection of that base type, and implement your persist / reload logic at that level.
So some kind of
SpecialBindableObejct
with at least 3 properties (value, PositionX, PositionY) and INotifyPropertyChanged
And instead of binding 3 different variable, I can use only one, and do binding in xaml likeSpecialObject.PositionX
, SpecialObject.PositionY
, etc?
or did you mean something else?
Also, if I would like to store them into a json file and do loading from there like this
How ungly is that? 😅
i really have no idea how could i improve that and not make a mess, hahSo let's say you have these items that users can drag around on a canvas, your ViewModels for each item will be unique to their own usecases, but they all share something in common, that is the fact they belong on the canvas and store positional data, so you could have your base view model type:
Omitted the
INotifyPropertyChanged
stuff for brevity.
Then let's say you have a VM to represent your canvas container itself:
If you have additional serialisation / deserialisation needs per-item, e.g. having them store and load additional data relevant to them, then you'd want to come up with a more comprehensive mechanism for storing their own data, but this would be how I'd start to tackle the problem.Okay yeah, I had started with something similar and managed to make it work, which is nice. Thank you! (I should look into stuff like "sealed record", "abstract", "immutableDictionary")
Haha ye, every new way of storing data ends totally ugly... well, the above way with hardcoding every property kinda works, maybe some better idea will pop in my mind anytime soon..
It technically works, except some properties have margin set in XAML and on fresh set of
X
and Y
form file, their margin stays there and its location is actually wrong. An easy "fix" would be get rid of margins, but yea 😅
Ahh, just when I thought I already have a solution.. looks like I don't. One more question and then I'll let you go..
oh, when I was typing, this thought occured me,actually it might even work, will test it tommorow morning.
If you are OK with that, can I ask you some questions if they will be needed?Yeah sure, not sure how rapidly I'll be able to answer but yeah, drop a message
Okay, so I managed to do some "improvements", which include less hardcoding stuff.
I have two models,
CanvasPosition
and StringCanvasPosition
(this one inherits canvas position - some elements requires string, some int, so I just separated them.
Then I have bindable properties like this:
For the serialization and deserialization I used reflection.
I am saving it to File and the code looks like this:
Saving:
and loading is like this:
I would be a lot less messy if I could have only type of objects (but I will need more of them because I need some additional formatting before saving value to object - for exampe: string can only include numbers)
Yeah, I know that reflection is usually better to be avoided, but this is currently the best idea I got, haha
So.. what do you think about this? 😅Hmmmm, my recommendation would be instead to implement an interface something like
Then have your items implement it, this is sort of similar to how certain things in Apple's ecosystem work, so the idea being your individual types can pack and unpack their specific pieces of data, and you have a consistent interface to interact with that mechanism without having to resort to reflection. Also means you're not necessarily tied into JSON going forward either.
You could also make it not use
object
and use JsonElement
for example, but then System.Text.JSON
contains primitives for making this slightly more workable like the JSON writer / reader utilities etc.
Lots of ways to potentially solve this.
Another of course would be to make your viewmodels derive from a persistable base, something like:
And then implementing it would be something like:
Then you have a well-defined data model for your persistance, that you can then ser/deser however you want, and is easy enough to just treat wholesale for your JSON storage.
Your viewmodels can then be as complex as needed, and all you're worried about is upholding that in/out data contract, and the persistance code can take care of the rest.