TheSwamp
Code Red => .NET => Topic started by: bncceo on August 23, 2006, 10:36:37 AM
-
VS 2005 & AC 2006
I have a problem: I have a palette in my project that contains controls such as multiple textboxes, combobox, buttons, etc. These controls are there to supply the user with calculated data as the user draws figures graphically on the drawing.
However, the only time I can get the controls to refresh on the palette is when the refreshcontrols subroutine is run by an event fired by a control on my palette. The following is the routine in the palette control code that is used to refresh the controls: (You can see everything I have tried in the commented fields)
Public Sub RefreshControls()
'Dim docLock As DocumentLock = AcadApp.DocumentManager.MdiActiveDocument.LockDocument _
' (Autodesk.AutoCAD.ApplicationServices.DocumentLockMode.Write, "NB", "NB", True)
'NativeMethods.SetFocus(Me.Handle)
'ResetUCSButton.Enabled = True
'AddNewBeamButton.Enabled = True
'DistLoadButton.Enabled = True
'PointLoadButton.Enabled = True
LengthBox.Text = AppStart.CurrentBeam.Length.ToString
BeamNameText.Text = AppStart.CurrentBeam.Name
DeflectionBox.Text = AppStart.CurrentBeam.DeflectionFactorLL & "/" & AppStart.CurrentBeam.DeflectionFactor
'MomentBox.Text = AppStart.CurrentBeam.CalcMoment.ToString
'ShearBox.Text = AppStart.CurrentBeam.CalcShear.ToString
'DeflBox.Text = AppStart.CurrentBeam.DistributedLoads.Count
'LengthBox.Invalidate()
'LengthBox.Refresh()
'BeamNameText.Refresh()
'DeflectionBox.Refresh()
'MomentBox.Refresh()
'ShearBox.Refresh()
'DeflBox.Refresh()
'ComboBox1.Refresh()
'ComboBox1.Items.Clear()
'Dim beams(AppStart.CurrentBeam.PassingBeams.Count) As String
'Dim count As Integer = 1
'For Each beam As BeamType In AppStart.CurrentBeam.PassingBeams
' beams.SetValue(beam, count)
' count += 1
'Next
ComboBox1.DataSource = Nothing
ComboBox1.DataSource = AppStart.CurrentBeam.PassingBeams
If ComboBox1.Items.Count > 0 Then
ComboBox1.SelectedIndex = 0
End If
Me.Refresh()
MyBase.Refresh()
'AppStart.mPaletteSet.Visible = False
'AppStart.mPaletteSet.Visible = True
'ComboBox1.DisplayMember = "FullName"
'docLock.Dispose()
'Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor.UpdateScreen()
'Autodesk.AutoCAD.ApplicationServices.Application.UpdateScreen()
End Sub
The following is an examble of a handled button click event. When this is fired from a real "click" on a button on my palette, everything works fine as long as I run the NewBeamCommand subroutine directly. However, if I sendstringtoexecute then i have the same problem of the controls never refreshing. It seems that whenever I pass control to the Autocad Editor my palette stops repainting.
Private Sub AddNewBeamButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddNewBeamButton.Click
AddNewBeamButton.Enabled = False
DistLoadButton.Enabled = False
PointLoadButton.Enabled = False
ResetUCSButton.Enabled = False
NativeMethods.SetFocus(AcadApp.DocumentManager.MdiActiveDocument.Window.Handle)
Dim docLock As DocumentLock = AcadApp.DocumentManager.MdiActiveDocument.LockDocument _
(Autodesk.AutoCAD.ApplicationServices.DocumentLockMode.Write, "NB", "NB", True)
Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
'Commands.Command("NB")
NewBeamCommand() '<- This sub marked with command attribute NB
'Application.DocumentManager.MdiActiveDocument.SendStringToExecute("_NB ", True, False, True)
RefreshControls() 'WHY WONT THIS WORK ARGGGHHHH!!!
Dim db As Database = HostApplicationServices.WorkingDatabase()
If Not XDataHelper.HasActiveTag(db) Then
XDataHelper.TagAcadDoc(db)
End If
ResetUCSButton.Enabled = True
AddNewBeamButton.Enabled = True
DistLoadButton.Enabled = True
PointLoadButton.Enabled = True
AcadUi.SetUCS(Matrix3d.AlignCoordinateSystem(Ge.kOrigin, Ge.kXAxis, Ge.kYAxis, Ge.kZAxis, Ge.kOrigin, Ge.kXAxis, Ge.kYAxis, Ge.kZAxis))
docLock.Dispose()
End Sub
It is important to note that during debugging, I have identified that the controls properties are updated with the correct data every time. However, the controls are never repainted.
This is very frustrating because the data the controls hold is the whole reason for this program. Unless I figure this out, I will have to force the user to click a button every time they want to use a feature of my program, instead of being able to use commands and the command buffer!
I truly appreciate any help you can give me. I have been lurking here for a while and you guys seem to know your stuff. If you need more info or code, I will be happy to supply as much as I can.
Thanks!
-
Are you using the AutoCAD version of ShowDialog()? (sorry, I haven't got a sample to hand but it is in the windows section of the managed lib's)
AutoCAD always wants to take focus away from other resources so while your controls may be getting updated they may be missing out on the paint message as acad has taken back control. Using the acad version of show dialog enables your resources to be managed by acad a lot better and helps you to keep focus on your palatte.
-
Currently I am using the following code to show the palette (Borrowed from other samples, note that there are two tabbed pages in the palette):
Public Shared Sub StartInterface()
'check for instance of the toolpaletteset
If mPaletteSet Is Nothing Then
'not yet created so create it
mPaletteSet = New Autodesk.AutoCAD.Windows.PaletteSet("", New Guid("6DDC1ED1-071E-4d33-A3B7-8602821EEDE8"))
'add the events
AddHandler mPaletteSet.StateChanged, AddressOf ps_change
AddHandler mPaletteSet.Load, AddressOf ps_Load
AddHandler mPaletteSet.Save, AddressOf ps_Save
mPaletteSet.Name = "AcadTools for Structural D " & My.Application.Info.Version.Major & "." & My.Application.Info.Version.Minor
'set how it will look/act
mPaletteSet.Style = Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowPropertiesMenu Or _
Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowAutoHideButton Or _
Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowCloseButton
'set the minimum size
mPaletteSet.MinimumSize = New System.Drawing.Size(146, 251)
'create generic UserControl object
Dim control As System.Windows.Forms.UserControl
'create reference to our user control
control = New LayerPalette
'set the control's name - appears on tab in the paletteset
control.Name = String.Format("Layers") '"AcadTools for Structural D " & My.Application.Info.Version.Major & "." & My.Application.Info.Version.Minor
'store in global var for toolpalette interop
mUC1 = control
'add the user control [a.k.a. toolpalette] to the toolpaletteset
mPaletteSet.Add(control.Name, control)
'redirect object to second control
'- comments for here are the same as above
control = New BeamPalette
control.Name = String.Format("Beams")
mUC2 = control
mPaletteSet.Add(control.Name, control)
mPaletteSet.Location = New System.Drawing.Point(20, 20)
mPaletteSet.Visible = True
'These lines solve some problems with how the palette starts (docked or not)
mPaletteSet.Dock = Autodesk.AutoCAD.Windows.DockSides.None
mPaletteSet.Visible = False
mPaletteSet.Visible = True
End If
'turn ON the toolpaletteset
mPaletteSet.Visible = True
mPaletteSet.KeepFocus = True
End Sub
I don't think I understand how to implement ShowDialog() for a palette. Will it sit on top of autocad like the tabbed options page or will it still function like a native ACAD palette? At what point in the above code do I call ShowDialog()? Maybe I've got the whole thing wrong!! Thanks again for your help.
-
Whoops! you're right, when you create your own forms you need to use the acad ShowDialog method so they play nice with acad. It seems you don't have to call showdialog() as the palette object must look after that itself(?)
Here's my code for setting up a palette that may be of some help -
private Autodesk.AutoCAD.Windows.PaletteSet ps;
[CommandMethod("DCS3D")]
public void CreateDCSPalette()
{
if(ps == null)
{
// use constructor with Guid so that we can save/load user data
ps = new Autodesk.AutoCAD.Windows.PaletteSet("DCS3D Tools");
ps.Style = Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowPropertiesMenu
| Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowAutoHideButton
| Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowCloseButton;
ps.Opacity = 90;
ps.Size = new System.Drawing.Size(250,400);
ps.MinimumSize = new System.Drawing.Size(225, 400);
ps.Add("Modelling Tools", new Dcs3dModify());
ps.Add("3D to 2D Tools", new DCS3dto2d());
ps.Add("Detailing Tools", new DCS3dDetailing());
ps.Add("Creation Database Utils", new Dcs3dUtils());
ps.Dock = Autodesk.AutoCAD.Windows.DockSides.None;
ps.KeepFocus = true;
ps.Visible = true;
}
else
{
ps.Visible = true;
}
}
-
Currently I am using the following code to show the palette (Borrowed from other samples, note that there are two tabbed pages in the palette):
...
I don't think I understand how to implement ShowDialog() for a palette. Will it sit on top of autocad like the tabbed options page or will it still function like a native ACAD palette? At what point in the above code do I call ShowDialog()? Maybe I've got the whole thing wrong!! Thanks again for your help.
Is the handler for the command you are sending to the command line via SendStringToExecute() a method of the control on the palette?
If so, then the problem is that the handler is executing in the document execution context. To get the palette controls to update, you would need to post a message to the contol's message queue (using the PostMessage API). You can try overriding the WndProc() of the control and watching for the message, and calling your control's Refresh() or Update() methods to make it happen.
-
Well guys I got it working the way it should and I couldn't have done it without your help!
After hearing your questions, it gave me some ideas and I started moving things around. Now, the palette's code only holds event handlers and the RefreshControls() method, and I have moved all of my other methods to a seperate class as Shared methods. In these shared methods I am referencing the variable I created in my StartInterface() method; mUC2 (which is the variable for the palette control I want to update). So now, I run my code as usual and when I want to update the information on the palette, I call mUC2.RefreshControls() and it works great!
I could have implemented the PostMessage() API and kept my methods in the control's class, but this is much cleaner in my opinion and there was no reason to keep the methods in the Palette's class.
Thanks a ton guys, you have saved my butt!