Suppose a TAncestorForm with an extra button (or any other control). If I remove the button, whenever I open a descendant of TAncestorForm the Delphi IDE shows a message "Ancestor component not found..." and let me choose:
Remove the reference;
Tell that the component was renamed and what is
it's new name;
Recreate the component;
I want the first option. There is any other option that would do this automatically instead of opening all descendants (like dozens of them) and clicking in each message?
I have an MvvmCross PCL and a related MonoDroid UI project (pattern copied from following Stuart Lodge's excellent N+1 video series). I want to bind the click of an Action Bar menu item to an ICommand in my ViewModel. I've seen this post but an IMenuItem doesn't appear to have a suitable property to bind to. I'm aware of the SetOnMenuItemClickListener method but (and this is no doubt my lack of understanding) don't know how to leverage this to bind a System.Windows.Input.ICommand to it.
Also, if this is possible, can it be done in the OnCreateOptionsMenu method of the MvxView as this provides a handle to the Action Bar menu itself?
I don't think you can bind it, as the ActionBar is something that is loaded outside of the XML view. Also it does not expose any C# type of events for clicks on items as they are populated from a menu xml file. However you could in your SetOnMenuItemClickListener execute commands when a MenuItem is clicked. You can simply execute a command like this:
ViewModel.MyAwesomeCommand.Execute();
We are creating a component and want to mimic the concept behind Designer.GetComponentNames, where as we give can obtain a list of the available components on the form or any form in the uses. We haven't been able to get to the root of GetComponentNames. Any input would be much appreciated.
LE: Actually I take that back. I need this from the design time aspect.
Runtime? You have the Vcl.Forms.TScreen.Forms array for all the displayed forms, and you have Vcl.Forms.Application.Components containing all your forms IIRC. Then, each form has a Components array.
If I understand the first part of your question, you want to get a list of components owned by a form (by name) at designtime.
As background, I have a non-visual component (Call it TColorEdits.) that manages the colors of selected TWinControls on a form at runtime. This component has a TStrings property that contains the names of selected TWinControls on the form. The names of TWinControls to be managed may be selected at designtime using a dialog (dlgEditColors) that contains a couple listboxes, one of which is named DstList and shows all TWinControls available for management by TColorEdits.
So, here is some (simplified) code I use to get the names of TWinControls on a form at designtime and load the TWinControl names into DstList.
{ Load names of TWinControls owned by a form into TListBox DstList }
for i := 0 to TColorEdits(GetComponent(0)).Owner.ComponentCount - 1 do
if ((TColorEdits(GetComponent(0)).Owner.Components[i] is TWinControl) then
dlgEditColors.DstList.Items.Add(TColorEdits(GetComponent(0)).Owner.Components[i].Name);
You should be able to adjust the above code as part of a custom property editor for your component. Hope this helps with the first part of your question.
I'm developing a Firefox extension. There is a menu X which I need to show in both Tools menu and Context menu. Tools menu item and Context menu item are defined in same file but menu X in another file.
As I'm reusing menu X by id only last use of it is effective. How can I reuse it multiple time in same file without redundancy?
It can be done using XBL.
I haven't found a good solution either. The approach is rather to define the menu in the overlay only once and then clone it in your "load" event handler. You can then insert the clone at the second location. You have to be careful because ID attributes have to stay unique - so if your menu uses ID attributes you will have to additionally rewrite them. Ugly, I know.
IDs are, per definitionem, unique. That means you can't share the menuitem but you can share the code that gets executed when the action is invoked. One way to achieve this is to use commands.
I am starting to learn Delphi. So I decided to write an application like MS Excel from scratch. In a new Form1, I did put a TPageControl component containing only 1 page. In that page, I did put a TAdvStringGrid and a TPanel with some buttons (button1, button2) and a Popup1 menu for defining some actions on the grid, like copy cell, copy row, delete row, etc. For that StringGrid, also, I have defined some properties, like colors, fonts, etc. I added a toolbar with a button to the main form, in order to add more pages to the PageControl. The OnClick method of that button defines two actions:
1) to add a new Page2 to the PageControl, and
2) to add a new StringGrid In the new created Page2 .
That new (runtime defined) StringGrid created in a new Page of a Tpagecontrol should inherite (get, copy, clone, duplicate) the properties and methods of the StringGrid parent already defined in the first page at design time, and should be able to call the PopUp1 menu just like the StringGrid parent. How we do this?
At the beginning, I thought I just should copy the StringGrid properties using assing(), but when using this approach, the popup menu does not pop up when right mouse clicking on the new StringGrid... and the buttons (button1 and button2) of Form1 only work with the first StringGrid but not with the new added one. I did read somewhere that in order to solve this problem, I could duplicate the StringGrid component by using the write and read TMemoryStream (save the parent stringgrid into a memorystream, create a new stringgrid and then read that memorystream into the new created stringgrid), so I did, but when the program executes this component cloning method, I get a runtime error. :-(
I did carefully chech the Help. Nothing found on that topic. Seems there is not any Delphi component library or third party components that cope with this kind of task. Can anybody help, please? :o)
I would use an tabcontrol instead of an pagecontrol. That way, you would end up with multiple tabs but only one page and grid. I would then make some kind of data structure to keep all my cell information in, and render this structure to the grid. This way, I can have multiple structures, and let the active tab decide which structure to render. You will also end up with a looser coupling between your gui and your logic, making it easier change things later. E.g. if you need to bring in some values form a different spreadsheet into a cell in the current spreadsheet, you can load up a structure and pick out the wanted values. No need to make any gui for the second spreadsheet at all.
For a 3.party component, I will recommend TMS FlexCell and TAdvSpreadGrid. That will give you most of what you need.
A tricky choice for a learner :) however you do not need to start streaming things.
Look up the assign() procedure for TPersistent this is the routine you need to copy parts of the grid easily. For example
for i := 0 to StringGrid1.RowCount - 1 do
StringGrid2.Rows[i].Assign(StringGrid1.Rows[i]);
for an easy start differentiate your grids with the Tag property(StringGrid1.Tag := 1, StringGrid2.Tag := 2 Etc.
The popup menu is pretty simple too:
StringGrid2.popupmenu := stringGrid1.popupMenu But then then you must decide in the Popup Routine Which Grid is "Active" some thing l like
Tform1.popupMenuItem1Click(Sender: TObject)
if Sender is TStringGrid then
Case TStrigngGrid(Sender).Tag of
1: // Grid 1
2: // Grid 2
You can use the same simple logic with the buttons.
As neftali mentioned the best thing would be to put the created grids in an ObjectList.
You would then end up with the slightly more complex but expandabe:
Tform1.popupMenuItem1Click(Sender: TObject)
var AGrid: TStringGrid;
if Sender is TStringGrid then
AGrid := MyListOfStringGrids[MyListOfStringGrids.IndexOf(Sender)];
DoMenuItem1Stuff(AGrid);
Have fun
"...and the buttons (button1 and button2) of Form1 only work with the first StringGrid but not with the new added one. I did read somewhere that in order to solve this problem..."
There is no generic method for solving this. Delphi offers different tools to solve it.
You can create a list of Objects (TObjectList) that containts all the StringGrid; At Button1 Click event you must search what is the grid that you are using at this moment. For example (BIS for the other buttons):
var
index:integer;
sg:TStringGrid;
begin
...
// search the active page
index := pageControl.ActivePageIndex; //0, 1, 2,...
// USe this for search the StringGrid
sg := TStringGrid(OList.Objects[index]);
// the code that you have at the event bus woking with sg
// not stringgrid1, stringgrid2,...
...
sg.Color :=
...
If you don't want use ObjectList, there are alternatives. You can use Tag property for all StringGrids. Assign 0, 1, 2, 3,...
Extract the index (active page) and search the TStringGrid that have the property Tag with the same value. You can do this with FindComponent. The first methos is better. ;-)
Regards.
P.D: Excuse for my bad english.
Dear all, I am trying to learn Delphi
The Delphi style is to find/create/buy a component that does the job and use them in the design-time. You could try making a custom component based on a grid or use TFrame. See links from Custom Component Development and help files that comes with Delphi.
If you really need to clone the control dynamically, here's an example I found that uses stream.ReadComponent.