I have an app with two regions, one serving as a selector for data type (called NavigationPane) and the other one as a setter view for that data type (called SimulationPane). The SimulatorView.xaml I use to fill the SimulationPane has a corresponding SimulatorViewModel which dynamically creates a list of settable properties for TDataType and eventually binds it to a ItemsControl in SimulatorView.xaml. So my ViewModel needs System.Type as input:
I want to set it up as following:
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<TopicSelectorView, TopicSelectorViewModel>("Selector");
containerRegistry.RegisterForNavigation<SimulatorView, SimulatorViewModel<A>>("Simulator_A");
containerRegistry.RegisterForNavigation<SimulatorView, SimulatorViewModel<B>>("Simulator_B"); // and so on..
}
Once I have it registered, I want to be able to call (from other module):
regionManager.RequestNavigate("SimulationPane", $"Simulator_{topicType.Name}");
where topicType is the data type based on user's selection (here: 'A', 'B', and so on).
The problem with this approach is that I end up with just one ViewModel, i.e. the one I registered last. My impression is that that the registration uses some kind of dictionary with view as a key.
What am I doing wrong here? How else can I achieve my goal of being able to provide a type for VM at runtime, and navigate to it?
How else can I achieve my goal of being able to provide a type for VM at runtime, and navigate to it?
Register multiple viewmodels with the same view is not supported in Prism. See #brianlagunas answer on GitHub:
As I said in my reply to your PR, this is not something we will support in Prism. You have a few options, two of which we have already discussed; create a unique view, or have a single VM and load the relevant data.
Why do you need to pass A and B as generic parameters?
I'd have a single SimulatorViewModel and inject a service from which the view model can get the list of parameters to be set by the user. This could be done through reflection (on the simulator type) or a list of parameter descriptors (IReadOnlyCollection<Parameter> ISimulator.Parameters { get; }), whatever you prefer.
When changing the simulator type, you update it in the service and the SimulatorViewModel updates its list of parameters, because it listens to the service's INotifyPropertyChanged.PropertyChanged.
Related
I have a simple entity class in a WPF application that essentially looks like this:
public class Customer : MyBaseEntityClass
{
private IList<Order> _Orders;
public virtual IList<Order> Orders
{
get { return this._Orders; }
set {this._Orders = new ObservableCollection<Order>(value);}
}
}
I'm also using the Fluent automapper in an offline utility to create an NHibernate config file which is then loaded at runtime. This all works fine but there's an obvious performance hit due to the fact that I'm not passing the original collection back to NHibernate, so I'm trying to add a convention to get NHibernate to create the collection for me:
public class ObservableListConvention : ICollectionConvention
{
public void Apply(ICollectionInstance instance)
{
Type collectionType =
typeof(uNhAddIns.WPF.Collections.Types.ObservableListType<>)
.MakeGenericType(instance.ChildType);
instance.CollectionType(collectionType);
}
}
As you can see I'm using one of the uNhAddIns collections which I understand is supposed to provide support for both the convention and INotification changes, but for some reason doing this seems to break lazy-loading. If I load a custom record like this...
var result = this.Session.Get<Customer>(id);
...then the Orders field does get assigned an instance of type PersistentObservableGenericList but its EntityId and EntityName fields are null, and attempting to expand the orders results in the dreaded "illegal access to loading collection" message.
Can anyone tell me what I'm doing wrong and/or what I need to do to get this to work? Am I correct is assuming that the original proxy object (which normally contains the Customer ID needed to lazy-load the Orders member) is being replaced by the uNhAddIns collection item which isn't tracking the correct object?
UPDATE: I have created a test project demonstrating this issue, it doesn't reference the uNhAddins project directly but the collection classes have been added manually. It should be pretty straightforward how it works but basically it creates a database from the domain, adds a record with a child list and then tries to load it back into another session using the collection class as the implementation for the child list. An assert is thrown due to lazy-loading failing.
I FINALLY figured out the answer to this myself...the problem was due to my use of ObservableListType. In NHibernate semantics a list is an ordered collection of entities, if you want to use something for IList then you want an unordered collection i.e. a Bag.
The Eureka moment for me came after reading the answer to another StackOverflow question about this topic.
I have one view for a type of article, I need to extends this view and if user open article type "Special" I need to show some new fields in this view.
I don't want to create a separate view for this type of form because differs only one field.
Also I need to save in database, in field "type" one different value if "Special" article is saved.
Please suggest me how I can do this.
Well, you should simply use a if statement in your view to display, or not, additional fields, and use beforeSave method in your model to handle your type attribute.
protected function beforeSave()
{
// if ('Special' article)
// $this->type = 'value';
parent::beforeSave();
}
You should also consider using scenario.
I resolved this by adding a public variable in Article model, in controller I set the variable with one string, and on view I verify this string.
the title pretty much explains my issue:
I am right now taking care of drag & drop in my app. I can have many instances of my app running at the same time, and I can drag from one instance to the other without trouble.
Now, I would like to know if I'm drag & dropping "internally" (i.e: the drop occurs in the same instance as the drag) or "externally" (the opposite)
I went this far: I need to add to my dragged data a unique ID (something like a PUID) that identifies the app where I'm making the drag. Then I can just compare this id to the one I have locally on the drop and see if it is the same.
I have no problem transferring such info in my drag Data, the issue is more to find this UId.
I have been thinking using the Process.GetCurrentProcess().MainWindowHandle; but I'm not sure if this is a good idea.
What option(s) do I have to make this work?
I would simply create a readonly Guid that gets set when you start your app.
You can put this wherever your main logic lives (MainWindow or ViewModel).
Here is a snippet:
public class MyViewModel
{
private readonly Guid mUID = Guid.NewGuid();
// In case you want a property for it
public string UniqueApplicationID
{
get { return mUID; }
}
public void OnDropHandler(MyViewModel objectBeingDropped)
{
if (objectBeingDropped.UniqueApplicationID == mUID)
return;
// Handle drop normally here
}
}
The D-n-D is much like an UI activity, than an internal one.
I would distinguish two contexts: dropping a file, and dropping some object (e.g. VS designer). In the first context there's no problem at all, because it doesn't matter where you pull the data. In the second case, you should know what object has been chosen. For instance, you have a listbox with many items (e.g. the alphabet chars), once the user D-n-D any of those items, the internal operation is a simple reference to the selected object. By pulling the data from another app, you won't be able to find your object, because the source is different.
In case of structs or strings, you may wrap them with a GUID, as you correctly proposed.
I want to use the data of my grid in an other grid
when I create a window, I call a function and give it parameter, so I want that the grid in my window use this data
//In my main pag
functionThatCreatesMyWindow(villeGrid.store.data);
//In my window
myGrid.store.loadData(myParameter);
It doesn't work :(
First of all, you need to understand object scopes work in the DOM. If the store is named using a registered namespace, you can access any objects using that namespace from any JS within a document. When you have multiple windows, these will be functioning under two separate scopes.
In your scenario though there is a helper object that may be able to help you out.
Each store created on a page is automatically registered in the global, static, Ext.StoreMgr object. If the stores have storeID's (see docs for Ext.data.Store), you can use the Static StoreMgr object to reference the store in your window.
//returns reference to store object from the StoreMgr
var referenceToStore = Ext.StoreMgr.getKey('myStoreID');
If that doesn't work, create a factory method where you pass a store to the method that can consume the store.
I'm trying to do custom per-client localization in Silverlight and am running into problems. I tried using custom cultures (en-US-c1, en-US-c2, etc), but found that doesn't work because the culture needs to exist on the client. Is there a good clean way to do this?
You'll need to write the user's culture to Isolated Storage
The values are stored as a Key/Value pair:
// Create an instance of IsolatedStorageSettings.
private IsolatedStorageSettings userSettings =
IsolatedStorageSettings.ApplicationSettings;
// Add a key and its value.
userSettings.Add("userCulture", "en-US-c1");
// Remove the setting.
userSettings.Remove("userCulture");
Just default the value to something sensible and you'll need an option to allow the user to select their culture.