|
I am trying to use a GoTo type command in my WPF application. Right now it looks like this:
private void GoTo(string viewModel, int claimId)
{
switch (viewModel)
{
case "ECRsViewModel":
{
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm is ECRsViewModel)
as ECRsViewModel;
if (workspace == null)
{
workspace = new ECRsViewModel(claimId);
_mainWindow.Workspaces.Add(workspace);
}
_mainWindow.SetActiveWorkspace(workspace);
}
break;
case "ManagePropertiesViewModel":
{
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm is ManagePropertiesViewModel)
as ManagePropertiesViewModel;
if (workspace == null)
{
workspace = new ManagePropertiesViewModel(claimId);
_mainWindow.Workspaces.Add(workspace);
}
_mainWindow.SetActiveWorkspace(workspace);
}
break;
case "ClaimReportsViewModel":
{
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm is ClaimReportsViewModel)
as ClaimReportsViewModel;
if (workspace == null)
{
workspace = new ClaimReportsViewModel(claimId);
_mainWindow.Workspaces.Add(workspace);
}
_mainWindow.SetActiveWorkspace(workspace);
}
break;
}
}
Obviously, this is a terrible solution. I wanted something where I could find the type of the viewModel string, how do I do this?
I want something like this:
{
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm is typeof(viewModel)
as typeof(viewModel);
if (workspace == null)
{
workspace = new typeof(viewModel)(claimId);
_mainWindow.Workspaces.Add(workspace);
}
_mainWindow.SetActiveWorkspace(workspace);
}
Something nice and concise like that. Thoughts?
|
|
|
|
|
I recommend an enumeration:
private enum MyViews { ECRsViewModel , ManagePropertiesViewModel , ClaimReportsViewModel }
MyViews v = (MyViews) System.Enum.Parse ( typeof(MyViews) , viewModel ) ;
switch (v)
{
case MyViews.ECRsViewModel:
You can get fancy with it, but that's the basics.
I use enumerations extensively and have written a few articles about how I use them, here's one: Enum Utilities[^]
Another way would be to use something like my TypeTransmogrifier[^], but I don't know whether or not you'd get much benefit from it.
|
|
|
|
|
+5 Fascinating way to use Enums, got to go and study your articles !
thanks, Bill
"Everything we call real is made of things that cannot be regarded as real." Niels Bohr
|
|
|
|
|
PIEBALDconsult wrote: I recommend an enumeration:
I wouldn't. You are re-inventing the wheel by re-inventing something that already exists in .Net. .Net has full support for creating instances from types and/or type strings. I provided sample code in my other response. No need to "fake it" with enums.
|
|
|
|
|
You can re-write all of that code in one or two lines. You didn't mention who is calling the Goto function, but you can convert a string into a Type like this:
Type type = Type.GetType(viewModel);
Then you'd get the workspace:
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm is type);
Then you'd create the VM from the type like this:
Activator.CreateInstance(type, new object[] { claimId });
|
|
|
|
|
So how do you restrict the allowable types?
|
|
|
|
|
Store the list of allowable types in a string array and check the array before the call to GetType, perhaps?
|
|
|
|
|
Check if the type is derived from the ViewModelBase or implements an interface, but that wasn't a requirement .
|
|
|
|
|
This is what I was looking for. I had stumbled across the Activator but was not sure how to use it in this example. I have no need to restrict the allowable types in this instance, so this is perfect.
Cheers, --EA
|
|
|
|
|
Solution did not work exactly as I thought it might. This is where I am at right now:
GoTo call:
public ICommand GoToECRsCommand { get { return new RelayCommand(() => GoTo<ECRsViewModel>("ECRsViewModel", _claimId)); } }
Eventually it will be either the <t> or the viewModel argument, not both. Here is the function right now:
private void GoTo<T>(int claimId) where T : new()
{
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm is T)
as T;
if (workspace == null)
{
workspace = new T(claimId);
_mainWindow.Workspaces.Add(workspace);
}
_mainWindow.SetActiveWorkspace(workspace);
}
Obviously the issue stems from my lack of understanding of generic types (Amongst other things). I can see the problem, I just don't know how to correct it.
Cheers, --EA
|
|
|
|
|
What is the real error that the debugger is putting out?
"var workspace" should be "T workspace" if you are going that route and you might be able to drop the "as T" part.
When you new up the workspace like that, is it actually returning the correct type and calling the proper constructor? I'm surprised that the compiler didn't error out on that line because it doesn't know that some random T has a constructor(int), although it may do that at compile time...
|
|
|
|
|
Having gutted out much of what was there, here is where I am:
private void GoTo(string viewModel, int claimId)
{
Type type = Type.GetType(viewModel);
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm is type);
if (workspace == null)
{
Activator.CreateInstance(type, new object[] { claimId });
_mainWindow.Workspaces.Add(workspace);
}
_mainWindow.SetActiveWorkspace(workspace);
}
Error is "The type or namespace 'type' could not be found."
|
|
|
|
|
Change that line to:
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm.GetType().Equals(type));
|
|
|
|
|
Oh... DUH... you can't do the "is type" part because is expects an actual type, not a Type. How's that for confusing . I.e. you do blah is Window, not blah is window.GetType().
So you can either change it to:
vm.GetType() == type
Or go back to your generic method you had before and do:
vm is T
but with the above code, you need to do the vm.GetType() == type.
|
|
|
|
|
btw, you are missing a:
workspace = Activator.CreateInstance(type, new object[] { claimId });
|
|
|
|
|
Unfortunately making that changes causes an error.
An instance of type 'object' can not be assigned to a variable of type WorkspaeViewModel.
|
|
|
|
|
Ok, so you need the T casts
workspace = (T)Activator.CreateInstance(type, new object[] { claimId });
|
|
|
|
|
I needed that and also:
private void GoTo<T>(string viewModel, int claimId) where T: WorkspaceViewModel
However, this line:
Type type = Type.GetType(viewModel);
That returns null so everything else falls apart. How does it get a type from a string name? And can I pull out the string? It seems redundant since I am already giving it the type.
I can use T here:
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm is T);
and that gets rid of the need for type up until here:
workspace = (T)Activator.CreateInstance(type, new object[] { claimId });
Ayudame.
Cheers, --EA
Incidentally, without the "where T: WorkspaceViewModel I get an error on the workspace = (T)Activator... line.
|
|
|
|
|
Blargh.
For no apparent reason I had to use the fully qualified name.
So, the call looks like this:
GoTo<ClaimReportsViewModel>("litMan.ClaimReportsViewModel", _claimId)
Not sure why I have to do it that way, but it works. C'est la vie.
|
|
|
|
|
Lol, you keep switching between the two methods haha... now you are combining both of them... you should do:
GoTo<ClaimReportsViewModel>(_claimId)
Now you don't need the Type.GetType() line anymore. Your var workspace... line is correct. To fix the Activator.CreateInstance line, do:
workspace = (T)Activator.CreateInstance(typeof(T), new object[] { claimId });
Now you are using the generic method throughout .
|
|
|
|
|
I had a strong desire to get away from the mix and match, but I did not have the typeof(T) piece, I assumed you could just put the T in there and it did not work.
I tried Type.GetType(T) and T.GetType() to no avail. There are too many methods to find a type.
Regardless, thank you for the extensive help.
This is the final reslt:
public ICommand GoToECRsCommand { get { return new RelayCommand(() => GoTo<ECRsViewModel>(_claimId)); } }
private void GoTo<T>(int claimId) where T: WorkspaceViewModel
{
var workspace = _mainWindow.Workspaces.FirstOrDefault(vm => vm is T);
if (workspace == null)
{
workspace = (T)Activator.CreateInstance(typeof(T), new object[] { claimId });
_mainWindow.Workspaces.Add(workspace);
}
_mainWindow.SetActiveWorkspace(workspace);
}
Cheers, --EA
|
|
|
|
|
In my Goldlight[^] project, I have included a WorkspaceManager that might just be of help. Basically, any VM that needs to be treated as though it should be in a workspace inherits from WorkspaceViewModelBase (this provides things like the ability to close the particular workspace).
I then use this information to look the workspace up. Basically, the workspaces are maintained in an ObservableCollection and the UI binds to this.
It's all pretty simple to use. If you have any questions about the code, please feel free to ask.
|
|
|
|
|
I am using a Workspace viewModel right now that works as you have described. I can't recall where I got it, I think was an MSDN article from a year or two ago. Still, I will check out your framework is the workspace setup is a bit clunky, requiring a lot of defining throughout the project. Something more concise would be great.
Thanks for the heads up, I am always trying to find pieces like this.
Cheers, --EA
|
|
|
|
|
I just have to come back and say this framework is great. It is very feature rich. I am so deeply invested in the architecture right now (including MVVMLight) that I am apprehensive about switching over. There are a lot of tempting pieces though. This is definitely going to require some additional looking into.
|
|
|
|
|
Thanks. I wouldn't recommend switching over, Laurent did a really great job with MVVM Light - I mainly pulled it together to make it easy to combine MVVM with some of the things that you would typically use PRISM to do (as well as providing inbuilt support for theming). Please feel free to cannibalise it to your hearts content.
|
|
|
|