Afternoon,
I'm struggling at the moment to work out how I can create a view which requires a non default constructor (ie a constructor that requires input),
Public Class Bootstrapper
Inherits UnityBootstrapper
Protected Overrides Function CreateShell() As System.Windows.DependencyObject
Return New LogReader_Modular.Windows.Shell()
End Function
Protected Overrides Sub InitializeShell()
MyBase.InitializeShell()
Application.Current.MainWindow = CType(Me.Shell, Window)
Application.Current.MainWindow.Show()
End Sub
Protected Overrides Sub ConfigureModuleCatalog()
MyBase.ConfigureModuleCatalog()
Dim moduleCatalog As ModuleCatalog = CType(Me.ModuleCatalog, ModuleCatalog)
moduleCatalog.AddModule(GetType(GridModule))
End Sub
....
....
Public Class GridModule
Implements IModule
Private ReadOnly regionManager As IRegionManager
Public Sub Initialize() Implements IModule.Initialize
Try
regionManager.RegisterViewWithRegion("MainDockingRegion", GetType(Views.GridModuleView))
Catch ex As Exception
Trace.WriteLine(String.Format("An Error occured the error was {0}", ex.ToString))
End Try
End Sub
Public Sub New(ByVal regionManager As IRegionManager)
Try
Me.regionManager = regionManager
Catch ex As Exception
Trace.WriteLine(String.Format("An Error occured the error was {0}", ex.ToString))
End Try
End Sub
End Class
my issue is I want to pass in constructor values to GridModuleView, as its not really instantiated as such here, i dont really understand how I can pass in the values, any help with this would be appreciated as I've been looking at this for a few days now. EDIT * the data im wanting to pass in is coming from the shell and not the view, which is why i pasted the bootstrapper
Thanks
Tom.
You could use the RegionManager.RegisterViewWithRegion(IRegionManager, String, Func(Object)) method instead of the RegionManager.RegisterViewWithRegion(IRegionManager, String, Type) method and then pass the input from the shell to the GridModule.
Related
I am about to refactor some old VisualBasic application and have come along with the following situation:
Public Sub MySub ()
Try
' execute dangerous operation
Catch ex As System.Exception
Call HandleErrors((ErrObject) ex) ' <-- invalide cast
End Try
End SuB
Public Sub HandleErrors(ByRef objError As ErrObject) ' I can not easily change the signature of this sub as it gets referenced very often.
' process error ..
End Sub
I would like to reuse the already existing Sub ‘HandleErrors()’, which takes an ErrObject as parameter. But since I am more comfortable to use Try and Catch, I would like to pass an Object of the type Syste.Exception, rather than an ErrObject.
Question:
Is there any way of casting or transforming the Exception into an ErrObject ?
Rather than trying to force exceptions into the historic Visual Basic error handling routines, I think the better option here is to create a new overload of HandleErrors (leaving the original sub signature untouched for the places that still use it), possibly with an entirely new function that both the original function and new overload can then call. For instance, lets's assume your function currently looks like this:
Public Sub HandleErrors(ByRef objError As ErrObject)
Log(objError.Description)
PerformSomeGlobalCleanup()
End Sub
And now you want to also be able to log the new-style exceptions too. You could just create a new overload:
Public Sub HandleErrors(ByRef ex As Exception)
Log(ex.Message)
PerformSomeGlobalCleanup()
End Sub
But it would be better for this code to share the underlying structure and logic of whatever HandleErrors is actually doing, so you could do this for instance:
Private Sub InternalHandleErrors(ByVal msg as String)
Log(msg)
PerformSomeGlobalCleanup()
End Sub
Public Sub HandleErrors(ByRef ex As Exception)
InternalHandleErrors(ex.Message)
End Sub
Public Sub HandleErrors(ByRef objError As ErrObject)
'original signature, but refactored
InternalHandleErrors(objError.Description)
End Sub
You can move as much logic from the original HandleErrors into InternalHandleErrors as makes sense - whatever is common between handling an ErrObject and an Exception.
This means you're not "polluting" the newly refactored code with old-style Visual Basic objects, and means that if/when you complete the refactoring to remove the original function when nothing else references it, you don't need to go through your entire code base removing the casts.
Ok,since it seems there is no easy way to do this, I decided to overload the HandleError Sub and introduce a new class to generalise the Exceptions.
Public Sub MySub ()
Try
' execute dangerous operation
Catch ex As System.Exception
Call HandleErrors((ErrObject) ex) ' <-- invalide cast
End Try
End SuB
Class GeneralError
Public ReadOnly Number As Integer
Public ReadOnly Source As String
Public ReadOnly Description As String
Sub New(exception As System.Exception)
Number = 1
Source = exception.Source
Description = exception.Message
End Sub
Sub New(errObject As ErrObject)
Number = errObject.Number
Source = errObject.Source
Description = errObject.Description
End Sub
End Class
Public Sub HandleErrors(ByRef errObject As ErrObject) ' Overload
Dim generalError As GeneralError = New GeneralError(errObject )
Call HandleErrors(generalError)
End Sub
Public Sub HandleErrors(ByRef exception As Exception) ' Overload
Dim generalError As GeneralError = New GeneralError(exception)
Call HandleErrors(generalError)
End Sub
Private Sub HandleErrors(ByRef generalError As GeneralError) ' Original
' process error ..
End Sub
I'm tying to create a generic solution for instantiating my forms using singleton behavior in vb.net. But it's not working anyway and always protecting me to compile:
Public Class SingletonGenerator(Of TForm)
Private _inst As Object
Public ReadOnly Property Instance As SingletonInstance(Of TForm)
Get
If _inst Is Nothing Then
_inst = New TForm()
End If
Return _inst
End Get
End Property
End Class
But this error restricts me to continue:
Error 9 'New' cannot be used on a type parameter that does not have a 'New' constraint.
And I'm not sure if I replace my code with New Form() it works as expected (because it create objects of parent form() class and may loose some initialization in child class.)
Can somebody please explain why this happen or how can I have singleton instances of objects in an OOP way which not require to copy/paste those common lines of code which are used in singleton on every new defined class?
You have to convince the compiler that the TForm type in fact has a parameterless constructor so that New TForm() can never fail. That requires a constraint.
Not the only thing you need to do, a Form object becomes unusable when it is closed. And you'll have to create another one to re-display it. Failure to do so causes an ObjectDisposedException at runtime. In other words, you should be interested in the Disposed event. That requires a further constraint, the TForm type parameter always needs to derive from Form. Required to convince the compiler that it is okay to use the event. Adding it up:
Public Class SingletonGenerator(Of TForm As {Form, New})
Private _inst As TForm
Public ReadOnly Property Instance As TForm
Get
If _inst Is Nothing Then
_inst = New TForm()
AddHandler _inst.Disposed, Sub() _inst = Nothing
End If
Return _inst
End Get
End Property
End Class
Do be a bit careful with this, you are painting yourself into a corner. You can only ever use this code to create form objects whose constructor takes no argument. In practice you may find they often need one.
Check this code:
Module Startup
Public Sub Main()
Dim f As Form = FormsManager.Instance.GetForm(Of Form1)()
f.ShowDialog()
Dim f1 As Form = FormsManager.Instance.GetForm(Of Form1)()
f1.ShowDialog()
End Sub
End Module
Public Class FormsManager
Private Shared _formsManager As FormsManager
Private _forms As List(Of Form)
Public Shared ReadOnly Property Instance As FormsManager
Get
If (_formsManager Is Nothing) Then
_formsManager = New FormsManager
End If
Return _formsManager
End Get
End Property
Private Sub New()
If _forms Is Nothing Then _forms = New List(Of Form)
End Sub
Public Function GetForm(Of T As {Form, New})() As Form
Dim f As Form = _forms.Where(Function(o) o.GetType = GetType(T)).SingleOrDefault
If f Is Nothing Then
f = New T
_forms.Add(f)
End If
Return f
End Function
End Class
This is what I finally produced (a generic singlton forms generator):
Imports System.Windows.Forms
Imports System.Runtime.CompilerServices
<HideModuleName()> _
Public Module SingletoneForms
<Extension> _
Public Function GetInstance(Of TForm As {Form, New})(ByRef obj As TForm) As TForm
Return SingletonForm(Of TForm).Instance
End Function
Public Class SingletonForm(Of TForm As {Form, New})
Private Shared WithEvents _inst As TForm
Public Shared Property Instance As TForm
Get
If _inst Is Nothing Then
SetInstance(New TForm())
End If
Return _inst
End Get
Set(value As TForm)
SetInstance(value)
End Set
End Property
Private Shared Sub SetInstance(ByVal newInst As TForm)
If _inst IsNot Nothing Then
RemoveHandler _inst.FormClosing, AddressOf FormClosing
End If
_inst = newInst
AddHandler _inst.FormClosing, AddressOf FormClosing
End Sub
Private Shared Sub FormClosing(sender As Object, e As FormClosingEventArgs)
If e.CloseReason = CloseReason.UserClosing Then
e.Cancel = True
_inst.Hide()
Else
_inst = Nothing
End If
End Sub
End Class
End Module
and call it simply this way:
frmMain.GetInstance().Show()
Form1.GetInstance().Show()
Form1.GetInstance().Hide()
Form2.GetInstance().ShowDialog()
Public Class Class1
Private names As List(Of String)
Private _class2 As New Class2
Public Sub AddName(ByVal name As String)
names.Add(name)
_class2.Add()
End Sub
Public ReadOnly Property AddAge(ByVal name As String) As Class2
Get
_class2.index = names.IndexOf(name)
Return _class2
End Get
End Property
Public Sub Clear()
names.Clear()
_class2.Clear()
End Sub
Public Class Class2
Private _age As List(Of Integer)
Protected Friend index As Integer
Public Property Age() As Integer
Get
Return _age(index)
End Get
Set(ByVal value As Integer)
_age(index) = value
End Set
End Property
Public Sub Add()
_age.Add(0)
End Sub
Public Sub Clear()
_age.Clear()
End Sub
End Class
End Class
How can I hide ,Sub Clear and Sub Add on class2, so they'll only be visible on class1, like;
Public Sub Clear()
names.Clear()
_class2.Clear() '<<<<<<<
End Sub
I want they do not be visible on Sub Main(), like they are below.
Sub Main()
Dim person As New Class1
person.AddAge("kid").Clear() '<<<<<<
person.AddAge("kid").Add() '<<<<<<
End Sub
If I put Protected, I class1 cannot access it. If I put Protected Friend, Sub Main() can still access them. Thanks for your help and time.
Used -Hans Passant- comment.
"Trust in .NET follows assembly boundaries. If you get two classes in one assembly then there are two programmers that know how to find each other if there's a problem. The only way to get what you want is to put these classes in a separate class library project. Which then lets you use Friend. And whomever writes that Main method doesn't have to be friendly."
I have a custom class with constructor, the class is setup such that it would legitly fail to init in some conditions. How do I return nothing?
You can't return anything from a constructor, it's there to initialize.
There are a couple of things you could do, depending on the situation:
If the failiure to initialize is an exceptional circumstance, throw an exception and catch it using a Try block:
Public Sub New()
'... fail to initialize
Throw New ApplicationException("Some problem") 'Or whatever type of exception is appropriate
End Sub
If it fails a lot and you can't filter input or anything, make the constructor Private and construct in a Shared method:
Public Shared Function CreateMyObject()
If someFailure Then
Return Nothing
End If
Return New MyObject() 'Or something
End Function
Its a bit old school but you could have a LastException Property that is set an exception is handled:
Public Class Foo
Private _LastException As Exception = Nothing
Public ReadOnly Property LastException As Exception
Get
Return _LastException
End Get
End Property
Public Sub New()
Try
'init
Catch ex As Exception
_LastException = ex
End Try
End Sub
End Class
This would require you to check LastException after class creation but it is an option?
Usage:
Dim foo1 As New Foo
If Not foo1.LastException Is Nothing Then
'some error occurred
Else
'carry on
End If
I'm writing an application for a device running Windows XP. There are 2 versions of the device and each version has its own API to communicate with the device's software. The application I'm writing needs to pull the same data from the API. My question is how to write a application that will detect at runtime which version of the device it is on and use the appropriate API. I've figured out how to read the registry to determine the device.
I've created an interface containing all of the common methods and also classes for each device that implement the interface. Now I need to know how to activate the correct one at runtime.
Public Interface IAPI
Sub InitializeMachine()
Function GetActiveProgram() As String
Function GetActiveGCodes() As String
Function GetCurrentBlockNumber() As Integer
''#etc...
End Interface
''#Mill API
Public Class CMAPI : Implements IAPI
Private ObjMachine As Okuma.CMDATAPI.DataAPI.CMachine
Private ObjPgm As Okuma.CMDATAPI.DataAPI.CProgram
Public Sub New()
End Sub
Public Function GetActiveGCodes() As String Implements IAPI.GetActiveGCodes
Try
Return ObjPgm.GetGCodes
Catch ex As Exception
Throw ex
End Try
End Function
Public Function GetActiveProgram() As String Implements IAPI.GetActiveProgram
Try
Return ObjPgm.GetActiveProgramName
Catch ex As Exception
Throw ex
End Try
End Function
Public Function GetCurrentBlockNumber() As Integer Implements IAPI.GetCurrentBlockNumber
Try
Return ObjPgm.GetCurrentBlockNumber
Catch ex As Exception
Throw ex
End Try
End Function
''#....
End Class
''#Lathe API
Public Class CLAPI : Implements IAPI
Private ObjMachine As Okuma.CLDATAPI.DataAPI.CMachine
Private ObjPgm As Okuma.CLDATAPI.DataAPI.CProgram
Public Sub New()
End Sub
Public Function GetActiveGCodes() As String Implements IAPI.GetActiveGCodes
Try
Return ObjPgm.GetGCodes
Catch ex As Exception
Throw ex
End Try
End Function
Public Function GetActiveProgram() As String Implements IAPI.GetActiveProgram
Try
Return ObjPgm.GetActiveProgramName
Catch ex As Exception
Throw ex
End Try
End Function
''#...
End Class
Untested, theory is right - there just might be typos :P
Dim rightAPI As IAPI
If CheckForTypeCMAPI() = true Then ' You said you can determine which device youre on, replace this with the right function
rightAPI = new CMAPI()
Else
rightAPI = new CLAPI()
End If
' Use rightAPI wherever you need it
MessageBox.Show(rightAPI.GetActiveProgram())
I would use a factory method:
Dim rightAPI As IAPI
rightAPI = APIFactory.GetAPI(HowYouDistinguishDevice)
' Use rightAPI wherever you need it
MessageBox.Show(rightAPI.GetActiveProgram())
public class APIFactory
public shared function GetAPI(string HowYouDistinguishDevice) as IAPI
dim oAPI as IAPI
'do whatever it is you need to do to determine which api to use
if CMAPI then oAPI = new CMAPI
if CLAPI then oAPI = new CLAPI
'or you could use select, whatever
return oAPI
end function
end class