My ViewModel:
class ViewModel
{
public string FileName {get;set;}
}
and in my View I bind a label's content to ViewModel's FileName.
now When I do drag-drop a file to my View, How can I update the label's Content property, so that the ViewMode's FileName also get updated via binding?
Directly set the label's Content property won't work, it just simply clear the binding.
3 quick choices... (Make sure the class implements INotifyPropertyChanged, and FileName is raising this event.)
You can simply pull the VM out of the View's DataContext and during the Drag-and-Drop event set the FileName property of the ViewModel.
Use an AttachedBehavior to allow the Event (Drag-and-Drop) to be used like a Command (http://geekswithblogs.net/HouseOfBilz/archive/2009/08/27/adventures-in-mvvm-ndash-binding-commands-to-any-event.aspx)
Use a Messenger pattern, like MVVMLight's Messenger, to send a Message from the View to the ViewModel and handle the Message on the VM like you would a Command Action.
Related
I'm working on a SwiftUI app that is to display a number of entries from a Core Data database. Basically just about what the XCode template for such apps implements.
I've made two changes:
I put the code for the list item view into a separate file (BookmarkableItemView)
I added a property bookmarked to the item, which I called BookmarkableItem
The code in my view to show the list of items is now:
List(bookmarkableItems) { item in
BookmarkableItemView(item: item)
}
In BookmarkableItemView, the item property is an #ObservedObject.
Now, my BookmarkableItemView also contains a button that should toggle the bookmarked property on the item that the view represents. All fine and well - this is easy. But now I have to persist the changes...
I can think of the following two solutions:
Pass an action (simple a (BookmarkableItem) -> Void) to the BookmarkableItemView that's then called when button in the view is pressed
Have the view itself save the managed object context
The latter is a no-go in my opinion. The first solution works. There's now an bookmarkAction property in the BookmarkableItemView, so the above code looks like that:
List(bookmarkableItems) { item in
BookmarkableItemView(bookmarkAction: { toggleBookmark(item) }, item: item)
}
The action is called by the BookmarkableItemView and as a consequence, the toggleBookmark(_ item:) method is called.
But somehow I feel that I'm missing something about bindings in SwiftUI that would make the process easier? How can I have my parent view get a notification when a sub view performs changes to the data model so I can persist them?
onDisappear check if item.hasChanges
or use onChange on item.hasChanges
I have this route
Get.toNamed('/community/discussion/${controller.community.topicId}}');
While navigating to the view, I want to pass the route parameter topicId to the view's controller so that it uses as document ID and load the content which will be stream to the view.
How can I send this parameter to the controller before the view's content is streamed?
I guess you're not using Get.toNamed the way it is supposed to.
Function toNamed takes a dynamic parameter arguments that you can use for your purpose.
In your source screen:
Get.toNamed<void>("/community/discussion/",
arguments: {"topicId": controller.community.topicId});
In your destination screen:
var topicId = Get.parameters['topicId'];
Then you can easily set the topic id into your controller:
controller.topicId = topicId;
class YourController extends GetxController {
int? topicId;
}
If what you're trying to pass already lives in a GetX class, which it appears that it does, then you don't need to pass it at all. Anything that lives in a GetX class is already accessible from anywhere with Get.find...
Just access it on the next page with
Get.find<WhateverThisClassIsCalled>().community.topicId
I was wondering what your thoughts are on having a ViewModel containing a collection of other ViewModels.
For example if i have a stock price screen. In the MainView i want to be able to selct a stock ticker. When i press the ADD button on the MainView it should display a new stock price in the MainView.
My question is about how the add button should work?
Which of the two options should the Add button on the MainView do:
1) Pass the stock ticker (MSFT) to StockPriceService. The StockPriceService will retrive a StockPrice object. I can then pass the StockPrice object into a StockPriceViewModel. The MainViewModel will contain a collection of StockPriceViewModel.
2) pass the stock ticker(MSFT) into the StockPriceViewModel. The StockPriceViewModel will be implemented to call the StockPriceService and retrive the StockPrice object. The the StockPrice object will then be wrapped in the StockPriceViewModel.
Thanks,
CA
If the Add button is part of the MainView then it's events really should be handled by the MainViewModel and access to data for the StockPriceViewModel and thus StockPrice object, by the StockPrice related code.
The way to look at this is that you should still be able to display a StockPriceViewModel with populated data without recourse to any code in any other ViewModels, but in this case it is the MainViewModel that triggers the creation/instantiation of a new StockPriceViewModel etc.
So that would mean go with mostly method 2, say passing an initialisation value to the StockPriceViewModel constructor.
I am attempting to call a controller via an actionLink() in a view. This controller get's data from a TempData repository. However, it seems that no matter what I do, if I set the TempData repository in the view, it won't go over to the controller? Should I use ViewData instead? What is your recommendation for a system such as that?
Thanks
TempData, nor ViewData is supposed to be set in a view. A view is supposed to consume data that has been stored in those structures inside your controller actions (well, actually it isn't, a view is supposed to consume a view model but that's another topic).
TempData could be used when you want to persist information between two redirects. It should be set inside a controller action which redirects to another controller action that will read the data:
public ActionResult Foo()
{
SomeModel model = ...
TempData["foo"] = model;
return RedirectToAction("Bar");
}
public ActionResult Bar()
{
var model = TempData["foo"] as SomeModel;
...
}
So a controller action should get data from the TempData structure only if this action has been invoked after a redirect from another action that set the data. Such controller action should never be invoked from a view because if you have a view this means that this view was rendered from a controller action that presumably set the data into TempData but there is always a risk (if the view performs in between a request to the server - AJAX or something), the TempData will be lost.
For your case, when a view needs to invoke the server there are basically 3 techniques:
Use an HTML <form> with input fields that will send the data to the server
Use an anchor and pass data as query string parameters to the controller
Use javascript and send an AJAX request or a redirect to the server
You should set the TempData value beforehand, in the controller that renders your view. The value will then get picked up by the controller action that renders your second (ActionLink) view.
We add tabcontrols to our application at runtime. Each tabcontrol is given a ViewModel as a DataContext. We add the tabcontrols by sending a message to the main app View; the message contains the ViewModel to be used as datacontext.
From the main app ViewModel, we add tabitems to the tab controls by sending a message to the main app view to create a TabItem and add it to the specified TabControl.
I'd like to bind certain properties of the TabItem to certain properties of the TabControl's ViewModel; this needs to be done programmaticaly, of course.
Since the tabcontrol and tabitem don't know about ViewModels (only DataContext), how do I specify the properties of the ViewModel to bind the tabitem properties too?
Thanks for any advice...
Messenger.Default.Register<AddTabControlMessage>(this, m =>
{
TabControl tc = new TabControl();
tc.DataContext = m.ViewModel;
// etc.
} );
You can cast the DataContext to the type of the ViewModel and then access the properties that way.
tc.SomeProperty = ((MyViewModel)DataContext).SomeVMProperty;