I'm trying to simulate an Android UI element that unfortunately doesn't exist in Windows 7 phone: ListPreference
I thought about using a Popup, that would take exactly the whole screen (to simulate a modal window).
So the popup would be made of the following elements:
Popup -> Canvas -> Border -> StackPanel -> RadioButtons
The Canvas would be fully transparent (or lightly whitish to clearly show that the element underneath aren't available)
The border would be made so it only big enough to contain all the RadioButtons
Then the StackPanel would be opaque and black.
Unfortunately, if I make the bottom canvas transparent, all children elements are also transparent. I can only make the elements more transparent.
The way transparency works is slightly different than with Android or iPhone (where it's quite easy to have a parent fully transparent, but opaque children).
Is there a way to make a parent fully transparent with the children opaque?
Or maybe someone could suggest another way to simulate a modal window.
Who knows, maybe someone even developed a ListPreference-like UIElement :)
Thank you
Here is how I ended up doing it.
It works in a similar fashion as ListPreference on Android. The constructor takes a string, an array of string and an int indicating which is the default value
When the windows is closed, the delegate Dismissed is called..
So you call it like so:
string[] choices = { "Choice 1", "Choice 2", "Choice3" };
ListPreference lp = new ListPreference("name", choices, 1);
lp.dismissed += new ListPreferences.DismissedHandler(lp_Dismissed);
the code:
public class ListPreference
{
Popup p;
string Name;
int oldValue;
public delegate void DismissedHandler(string name, bool changed, int newvalue);
public event DismissedHandler Dismissed;
public bool IsOpen
{
get
{
return p.IsOpen;
}
set
{
p.IsOpen = value;
}
}
public ListPreference(string name, Array elements, int default_value)
{
p = new Popup();
Name = name;
Dismissed = null;
oldValue = default_value;
double height = (App.Current.RootVisual as FrameworkElement).ActualHeight;
double width = (App.Current.RootVisual as FrameworkElement).ActualWidth;
p.VerticalOffset = SystemTray.IsVisible ? 32.0 : 0.0;
p.Height = height;
p.Width = width;
Canvas canvas = new Canvas();
SolidColorBrush colorBrush = new SolidColorBrush(Colors.Black);
colorBrush.Opacity = 0.75;
//Color.FromArgb(0xff, 0x8a, 0x8a, 0x8a));
canvas.Background = colorBrush;
//canvas.Opacity = 0.765;
canvas.Height = height;
canvas.Width = width;
p.Child = canvas;
Border border = new Border();
border.Width = width - 50.0 * 2.0;
border.BorderBrush = new SolidColorBrush(Colors.LightGray);
border.BorderThickness = new Thickness(5.0);
border.Background = new SolidColorBrush(Colors.Black);
canvas.Children.Add(border);
StackPanel panel2 = new StackPanel();
panel2.Orientation = System.Windows.Controls.Orientation.Vertical;
int i = 0;
foreach (string val in elements)
{
RadioButton radio1 = new RadioButton();
radio1.GroupName = "group1";
radio1.Content = val;
if (i == default_value)
radio1.IsChecked = true;
int j = i;
radio1.Click += (sender, args) => radio1_Checked(radio1, j);
i++;
panel2.Children.Add(radio1);
}
Button button1 = new Button();
button1.Background = new SolidColorBrush(Colors.Black);
button1.Foreground = new SolidColorBrush(Colors.White);
button1.Opacity = 1.0;
button1.Content = "Cancel";
button1.Margin = new Thickness(5.0);
button1.Click += new RoutedEventHandler(closeButton_Click);
panel2.Children.Add(button1);
border.Child = panel2;
// Open the popup.
p.IsOpen = true;
p.UpdateLayout();
border.Height = panel2.DesiredSize.Height + 5.0 * 2.0;
border.SetValue(Canvas.TopProperty, (height - border.Height) / 2.0);
border.SetValue(Canvas.LeftProperty, (width - border.Width) / 2.0);
p.UpdateLayout();
}
void closeButton_Click(object sender, RoutedEventArgs e)
{
// Close the popup.
p.IsOpen = false;
if (Dismissed != null)
{
Dismissed(Name, false, -1);
}
}
void radio1_Checked(object sender, int idx)
{
p.IsOpen = false;
if (Dismissed != null)
{
Dismissed(Name, idx != oldValue, idx);
}
}
}
I would suggest creating a Usercontrol that would do what you need. Set the LayoutRoot grid's background to PhoneSemitransparentBrush or changing the opacity will change the child element's opacity as well. Then your child elements can have any opacity you'd like. You can add this control as a child to the popup. Additionally, you can add doubleanimation to the popup with the opened and closed event triggers. Change the design height of the UserControl to 480x760 to simulate full page.
To answer your question. Using resources like PhoneSemitransparentBrush and TransparentBrush for the Canvas background is one of your options. Opacity will change the opacity of the whole UIElement including its children.
Related
I've been using a UserControl to display a list of controls. I initially had AutoScroll enabled, and then opted to not using it. I chose against using it as it stood out and simply didn't 'look' good with the controls theme I've been using.
I took a shot at a framework called MetroFramework, and I've opted to use the MetroScrollBar scrollbar control for a vertical scrollbar.
I've fully disabled AutoScroll, and I then decided to implement the Scrollbar. I simply did this by:
scbMain.Scroll += (sender, e) => { VerticalScroll.Value = scbMain.Value; };
(where scbMain is the Scrollbar I'm discussing)
This works, but not as expected. As soon as I scroll, I get a crazy flickering effect from the default scrollbar, as shown here. A longer list has the same effect, but more pronounced.
I've attempted to hide the existing scrollbars:
VerticalScroll.Visible = false;
HorizontalScroll.Visible = false;
VerticalScroll.Enabled = false;
HorizontalScroll.Enabled = false;
This has had no effect on fixing my issue.
It should be noted: My scrollbar is docked to the right and there're no other container controls within the UserControl.
Ok. Problem solved. The issue was in this line of code:
scbMain.Scroll += (sender, e) => { ----> /*(Here*/ VerticalScroll.Value = scbMain.Value; <---- };
You are actully setting the scroll value of your user control, basically you tell the system to invoke the autoscroll property to set the value!
The correct way is to NOT autoscroll the user control but to scroll a container inside eg a panel. So add a panel to your user control. You are going to scroll the panel and all the controls inside it (in this example i will add the button).
this.btnExample.Location = new System.Drawing.Point(62, 0);
this.btnExample.Name = "btnExample";
this.btnExample.Size = new System.Drawing.Size(75, 390);
this.btnExample.TabIndex = 1;
this.btnExample.Text = "Out of Bounds";
this.btnExample.UseVisualStyleBackColor = true;
this.panel1.Controls.Add(this.btnExample);
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(270, 391); //the width must fit inside your user control and the height was arbitrary
this.panel1.TabIndex = 2;
this.Controls.Add(this.panel1);
this.Controls.Add(this.scbMain);
this.Name = "CtrlScroll";
this.Size = new System.Drawing.Size(474, 300);
The scrolling:
public CtrlScroll() {
InitializeComponent();
scbMain.Scroll += ( sender, e ) => {
//Normally the if statement whouldn't be needed but the metro srollbar
//has a weird behaviour when the scroll value becomes max
if( scbMain.Value > panel1.Height - this.Height ) {
panel1.Top = -( panel1.Height - this.Height );
}
else {
panel1.Top = -scbMain.Value;
};
};
int maxVertical = panel1.Height;
// SmallChange is typically 1%.
int smallChangeVertical = Math.Max( (int)( maxVertical / 100 ), 1 );
// LargeChange is one page.
int largeChangeVertical = this.Height;
scbMain.Minimum = 0;
scbMain.Maximum = maxVertical;
scbMain.SmallChange = smallChangeVertical;
scbMain.LargeChange = largeChangeVertical;
}
I finished developing my first windows forms application in c#, but when running it on a different Computer with a different screen size, the controls are not where they are supposed to be.
I used
this.WindowState = FormWindowState.Maximized;
to maximize the screen, but when doing this the form is just extended at the bottom and the controls stay at the same position.
Use anchor and dock Property for the control you need.
Dock : The Dock property forces a control to stick to a certain edge of the parent form (or control) like glue.
For example :
If you have an Image Box and you set the dock to the bottom right, after you maximize your windows, the Image Box will stay on the bottom right.
You can also use "Fill" to your Dock Property to make the size also dynamic depends on the windows size.
HI For responsive design
1st create below class
public class Resolution
{
float heightRatio = new float();
float widthRatio = new float();
int standardHeight, standardWidth;
public void ResizeForm(Form objForm, int DesignerHeight, int DesignerWidth)
{
standardHeight = DesignerHeight;
standardWidth = DesignerWidth;
int presentHeight = Screen.PrimaryScreen.WorkingArea.Height;//.Bounds.Height;
int presentWidth = Screen.PrimaryScreen.Bounds.Width;
heightRatio = (float)((float)presentHeight / (float)standardHeight);
widthRatio = (float)((float)presentWidth / (float)standardWidth);
objForm.AutoScaleMode = AutoScaleMode.None;
objForm.Scale(new SizeF(widthRatio, heightRatio));
foreach (Control c in objForm.Controls)
{
if (c.HasChildren)
{
ResizeControlStore(c);
}
else
{
c.Font = new Font(c.Font.FontFamily, c.Font.Size * heightRatio, c.Font.Style, c.Font.Unit, ((byte)(0)));
}
}
objForm.Font = new Font(objForm.Font.FontFamily, objForm.Font.Size * heightRatio, objForm.Font.Style, objForm.Font.Unit, ((byte)(0)));
}
private void ResizeControlStore(Control objCtl)
{
if (objCtl.HasChildren)
{
foreach (Control cChildren in objCtl.Controls)
{
if (cChildren.HasChildren)
{
ResizeControlStore(cChildren);
}
else
{
cChildren.Font = new Font(cChildren.Font.FontFamily, cChildren.Font.Size * heightRatio, cChildren.Font.Style, cChildren.Font.Unit, ((byte)(0)));
}
}
objCtl.Font = new Font(objCtl.Font.FontFamily, objCtl.Font.Size * heightRatio, objCtl.Font.Style, objCtl.Font.Unit, ((byte)(0)));
}
else
{
objCtl.Font = new Font(objCtl.Font.FontFamily, objCtl.Font.Size * heightRatio, objCtl.Font.Style, objCtl.Font.Unit, ((byte)(0)));
}
}
}
then when ever yo add any form the add panel control to form and dock
it to form
below
InitializeComponent();
Write below code
this.WindowState = FormWindowState.Maximized;
int screenWidth = Screen.PrimaryScreen.Bounds.Width;
int screenHeight = Screen.PrimaryScreen.Bounds.Height;
Resolution objFormResizer = new Resolution();
objFormResizer.ResizeForm(this, screenHeight, screenWidth);
this will make form responsive as much as possible as well as create system default font as well
The problem
I'm dynamically adding Buttons to the WinForm. As I do so, I'm repositioning existing Buttons to prevent overlap. The AutoSize property is being used to automatically set Width.
For longer text (that pushes Buttons beyond their default Width), the below code doesn't work.
For example:
b.Width is 75 before AutoSize is set
b.Width is 75 after AutoSize is set
When shifting other Buttons, it shifts them by b.Width + buffer = 83
However after addButton()completes, the AutoSize kicks in and sets the width to 150, overlapping the next Button which is only 83 pixels away instead of 158.
AutoSize appears to change the size of the control too late for it to be of use. How can I make it happen immediately?
Attempt 1 - Code
public void addButton(string text)
{
const int buffer = 8;
//Construct new button
Button b = new Button();
b.Text = text;
b.AutoSize = true;
b.Location = new Point(0, 0);
//Shift over all other buttons to prevent overlap
//b.Width is incorrect below, because b.AutoSize hasn't taken effect
for (int i = 0; i < Controls.Count; i++)
if (Controls[i] is Button)
Controls[i].Location = new Point(Controls[i].Location.X + b.Width + buffer, Controls[i].Location.Y);
Controls.add(b);
}
Attempt 2
Searched Google and StackOverflow for the following:
c# autosize immediately
c# autosize fast
c# autosize not working
Attempt 3
Asking here.
Last Resort
If nothing else works, a timer could be set to reposition Buttons on each tick. However this is very sloppy design, and doesn't aid in learning the intricacies of AutoSize. I'd like to avoid this workaround if possible.
The AutoSize and AutoSizeMode mode are applied only when the control is parented to the another control or form.
So invoke first
Controls.Add(b);
Now the b.Size will the adjusted accordingly and can be used in the calculations.
Alternatively, instead of Size property you can use the GetPreferredSize method to get the correct size without actually applying AutoSize and use it inside the calculations:
var bSize = b.GetPreferredSize(Size.Empty);
//Shift over all other buttons to prevent overlap
//b.Width is incorrect below, because b.AutoSize hasn't taken effect
for (int i = 0; i < Controls.Count; i++)
if (Controls[i] is Button)
Controls[i].Location = new Point(Controls[i].Location.X + bSize.Width + buffer, Controls[i].Location.Y);
The FlowLayoutPanel control does this work for you.
Place one on your form and try adding buttons in the following manner:
Button b = new Button();
b.AutoSize = true;
b.Text = text;
flowLayoutPanel1.SuspendLayout();
flowLayoutPanel1.Controls.Add(b);
flowLayoutPanel1.Controls.SetChildIndex(b, 0);
flowLayoutPanel1.ResumeLayout();
You can subscribe to the Resize event of the last button added. This will allow you to accurately change the locations of all of the buttons because now all of the buttons have been AutoSized.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var button1 = NewButton(0);
button1.Location = new Point(10, 10);
var button2 = NewButton(1);
button2.Location = new Point(button1.Right, 10);
var button3 = NewButton(2);
button3.Location = new Point(button2.Right, 10);
button3.Resize += (s, e) =>
{
button2.Location = new Point(button1.Right, 10);
button3.Location = new Point(button2.Right, 10);
};
Controls.Add(button1);
Controls.Add(button2);
Controls.Add(button3);
}
private Button NewButton(int index)
{
return new Button()
{
Text = "ButtonButtonButton" + index.ToString(),
AutoSize = true
};
}
}
In my application I've got the following situation:
I've got a Windows Form with a Tab Control with several tabs. Each tab contains arbitrary content which is added by other classes upon startup or during runtime.
I want to set up the tabs in a way that scrollbars appear automatically as soon as the Form is too small for the tab's panel to display everything.
What I've tried so far is setting the tab page's AutoScroll = true and setting the AutoScrollMinSize property to the size of the panel.
This did not work as expected as the panel's Size always seems to be (200, 100) independent of its contents.
I've created a small example application (code below) which demonstrates the issue. If you resize the form, you'll see that scroll bars only appear if the Form gets smaller than the panel (default size of (200, 100)) rather than the text box in the panel (size of 300, 150). If you set AutoScrollMinSize manually (uncomment line 34), it behaves as expected.
The question is: How can the tab page retrieve the actual size of what is displayed in it?
I could probably recurse through all controls and try calculating the size myself - but this feels really bad.
PS: Please do not suggest setting the size of the panel to the size of the label, as the actual panels are much more complex than that. ;-)
Code:
Simply create an Application in Visual Studio and override Program.cs with the following code:
using System;
using System.Windows.Forms;
namespace ScrollbarTest
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var sampleForm = CreateSampleForm();
Application.Run(sampleForm);
}
private static Form CreateSampleForm()
{
var sampleForm = new Form() { };
var tabControl = new TabControl() { Dock = DockStyle.Fill };
var tabPage = new TabPage("Test") { AutoScroll = true };
sampleForm.Controls.Add(tabControl);
tabControl.TabPages.Add(tabPage);
var samplePanel = CreateSamplePanel();
tabPage.Controls.Add(samplePanel);
// this does not provide the right size
tabPage.AutoScrollMinSize = samplePanel.Size;
// uncomment this to make it work
//tabPage.AutoScrollMinSize = new System.Drawing.Size(300, 150);
return sampleForm;
}
private static Control CreateSamplePanel()
{
// As an example, create a panel with a text box with a fixed size.
var samplePanel = new Panel() { Dock = DockStyle.Fill };
var sampleSize = new System.Drawing.Size(300, 150);
var textBox = new TextBox()
{
Dock = DockStyle.Fill,
MinimumSize = sampleSize,
MaximumSize = sampleSize,
Size = sampleSize
};
samplePanel.Controls.Add(textBox);
return samplePanel;
}
}
}
The samplePanel.Size returns (200,100). In your CreateSamplePanel method, if you set samplePanel.MinimumSize = sampleSize; then your code will work.
Panels don't calculate their size properties (e.g. Size, MinimumSize, PreferredSize) based on their child controls. You will have to subclass Panel and provide that behavior. Even TableLayoutPanel and FlowLayoutPanel don't correctly calculate the PreferredSize property, which is surprising. At the very least, normally you override the GetPreferredSize(Size proposedSize) method, and optionally have the MinimumSize property return the PreferredSize property.
It's worth noting that DockStyle.Fill and MinimumSize are at odds with each other. TabPage controls are inherently DockStyle.Fill mode, which is why you have to set the AutoScrollMinSize property.
Edit: Isn't there any existing function which retrieves the total required size of a list of controls (recursively), e.g. through their X/Y and Size?
It's up to the host container itself (e.g. TableLayoutPanel) to calculate its PreferredSize correctly because only it knows the exact details of how its layout is performed.
You can set the AutoSize property to true and then hope that GetPreferredSize(...)/PreferredSize calculates the right size. For TableLayoutPanel, I recall there was a case where it wasn't calculating correctly and I had to subclass it and override the GetPreferredSize(...) method. GetPreferredSize(...) won't be called unless AutoSize is true.
If you're talking about a plain Panel or UserControl, by default these use the WYSIWYG LayoutEngine, and do not calculate the PreferredSize. You could subclass and then calculate maximum control.X + control.Width and same thing for height, and use that as the preferred size.
First try setting AutoSize to true and see if that works for you. If not, you might have to override the GetPreferredSize(...) method. Here is a crude example:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var sampleForm = new Form() { AutoScroll = true };
var panel = new MyPanel() { AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, BackColor = Color.LightYellow };
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 3; j++) {
Button b = new Button { Text = "Button" + panel.Controls.Count, AutoSize = true };
b.Click += delegate {
MessageBox.Show("Preferred Size: " + panel.PreferredSize);
};
panel.Controls.Add(b, j, i);
}
}
sampleForm.Controls.Add(panel);
Application.Run(sampleForm);
}
private class MyPanel : TableLayoutPanel {
public override Size MinimumSize {
get {
return PreferredSize;
}
set {
}
}
public override Size GetPreferredSize(Size proposedSize) {
Size s = new Size();
int[] harr = new int[100];//this.RowCount];
int[] warr = new int[100];//this.ColumnCount];
foreach (Control c in this.Controls) {
var cell = this.GetPositionFromControl(c);
var ps = c.PreferredSize;
Padding m = c.Margin;
int w = ps.Width + m.Horizontal;
int h = ps.Height + m.Vertical;
if (w > warr[cell.Column])
warr[cell.Column] = w;
if (h > harr[cell.Row])
harr[cell.Row] = h;
}
foreach (int w in warr)
s.Width += w;
foreach (int h in harr)
s.Height += h;
return s;
}
}
I'm looking to implement a Visual Studio-style undo drop-down button:
I've looked all over the internet, and can't seem to find any real implementations of this.
I've started by deriving from ToolStripSplitButton, but don't really know where to go from there. Its DropDown property is a ToolStripDropDown, but that doesn't seem to have anything regarding multiple items being selected, much less scrolling, and the text at the bottom.
So instead of the default ToolStripDropDown, I'm thinking maybe the whole drop down part should be a custom control, based on a combobox. The question then, is how to cause the right-side (drop down arrow) button to do something other than show its default drop down?
Am I on the right track here? Thanks!
Yes, I think you're on the right track. And in this case, ToolStripControlHost is your friend.
You don't necessarily need to derive from it (unless you are making your own control), but try just subscribing to the ToolStripSplitButton's DropDownOpening event:
Working example:
private ListBox listBox1;
public Form1()
{
InitializeComponent();
listBox1 = new ListBox();
listBox1.IntegralHeight = false;
listBox1.MinimumSize = new Size(120, 120); \\ <- important
listBox1.Items.Add("Item 1");
listBox1.Items.Add("Item 2");
}
private void toolStripSplitButton1_DropDownOpening(object sender, EventArgs e) {
ToolStripControlHost toolHost = new ToolStripControlHost(listBox1);
toolHost.Size = new Size(120, 120);
toolHost.Margin = new Padding(0);
ToolStripDropDown toolDrop = new ToolStripDropDown();
toolDrop.Padding = new Padding(0);
toolDrop.Items.Add(toolHost);
toolDrop.Show(this, new Point(toolStripSplitButton1.Bounds.Left,
toolStripSplitButton1.Bounds.Bottom));
}
Here is the result:
For your application, you would need to replace the ListBox with your own UserControl, so you can contain whatever your want in it. The ToolStripControlHost can only hold one control, and it's important to set the MinimumSize property, or else the dropped control isn't sized correctly.
Extra thanks to LarsTech! (I didn't know about ToolStripControlHost a few hours ago)
Here is my implementation, which is really close to the VS drop down...
You should be able to just drop this delegate & function into your Form:
public delegate void UndoRedoCallback(int count);
private void DrawDropDown(ToolStripSplitButton button, string action, IEnumerable<string> commands, UndoRedoCallback callback)
{
int width = 277;
int listHeight = 181;
int textHeight = 29;
Panel panel = new Panel()
{
Size = new Size(width, textHeight + listHeight),
Padding = new Padding(0),
Margin = new Padding(0),
BorderStyle = BorderStyle.FixedSingle,
};
Label label = new Label()
{
Size = new Size(width, textHeight),
Location = new Point(1, listHeight - 2),
TextAlign = ContentAlignment.MiddleCenter,
Text = String.Format("{0} 1 Action", action),
Padding = new Padding(0),
Margin = new Padding(0),
};
ListBox list = new ListBox()
{
Size = new Size(width, listHeight),
Location = new Point(1,1),
SelectionMode = SelectionMode.MultiSimple,
ScrollAlwaysVisible = true,
Padding = new Padding(0),
Margin = new Padding(0),
BorderStyle = BorderStyle.None,
Font = new Font(panel.Font.FontFamily, 9),
};
foreach (var item in commands) { list.Items.Add(item); }
if (list.Items.Count == 0) return;
list.SelectedIndex = 0;
ToolStripControlHost toolHost = new ToolStripControlHost(panel)
{
Size = panel.Size,
Margin = new Padding(0),
};
ToolStripDropDown toolDrop = new ToolStripDropDown()
{
Padding = new Padding(0),
};
toolDrop.Items.Add(toolHost);
panel.Controls.Add(list);
panel.Controls.Add(label);
toolDrop.Show(this, new Point(button.Bounds.Left + button.Owner.Left, button.Bounds.Bottom + button.Owner.Top));
// *Note: These will be "up values" that will exist beyond the scope of this function
int index = 1;
int lastIndex = 1;
list.Click += (sender, e) => { toolDrop.Close(); callback(index); };
list.MouseMove += (sender, e) =>
{
index = Math.Max(1, list.IndexFromPoint(e.Location) + 1);
if (lastIndex != index)
{
int topIndex = Math.Max(0, Math.Min(list.TopIndex + e.Delta, list.Items.Count - 1));
list.BeginUpdate();
list.ClearSelected();
for (int i = 0; i < index; ++i) { list.SelectedIndex = i; }
label.Text = String.Format("{0} {1} Action{2}", action, index, index == 1 ? "" : "s");
lastIndex = index;
list.EndUpdate();
list.TopIndex = topIndex;
}
};
list.Focus();
}
You can set it up and test like this, assuming you have a blank form (Form1) with a toolStrip that has 1 ToolStripSplitButton (toolStripSplitButton1) added:
public Form1()
{
InitializeComponent();
// Call DrawDropDown with:
// The clicked ToolStripSplitButton
// "Undo" as the action
// TestDropDown for the enumerable string source for the list box
// UndoCommands for the click callback
toolStripSplitButton1.DropDownOpening += (sender, e) => { DrawDropDown(
toolStripSplitButton1,
"Undo",
TestDropDown,
UndoCommands
); };
}
private IEnumerable<string> TestDropDown
{
// Provides a list of strings for testing the drop down
get { for (int i = 1; i < 1000; ++i) { yield return "test " + i; } }
}
private void UndoCommands(int count)
{
// Do something with the count when an action is clicked
Console.WriteLine("Undo: {0}", count);
}
Here is a better example using the Undo/Redo system from: http://www.codeproject.com/KB/cs/AutomatingUndoRedo.aspx
public Form1()
{
InitializeComponent();
// Call DrawDropDown with:
// The Undo ToolStripSplitButton button on the Standard tool strip
// "Undo" as the action name
// The list of UndoCommands from the UndoRedoManager
// The Undo method of the UndoRedoManager
m_TSSB_Standard_Undo.DropDownOpening += (sender, e) => { DrawDropDown(
m_TSSB_Standard_Undo,
"Undo",
UndoRedoManager.UndoCommands,
UndoRedoManager.Undo
); };
}
*Note: I did modify the Undo & Redo methods in the UndoRedoManager to accept a count:
// Based on code by Siarhei Arkhipenka (Sergey Arhipenko) (http://www.codeproject.com/KB/cs/AutomatingUndoRedo.aspx)
public static void Undo(int count)
{
AssertNoCommand();
if (CanUndo == false) return;
for (int i = 0; (i < count) && CanUndo; ++i)
{
Command command = history[currentPosition--];
foreach (IUndoRedo member in command.Keys)
{
member.OnUndo(command[member]);
}
}
OnCommandDone(CommandDoneType.Undo);
}
I'd suggest implementing the popup separately from the toolbar button. Popups are separate windows with a topmost-flag which auto-close when losing focus or pressing escape. If you code your own popup window that frees you from having to fit your behaviour to a preexisting model (which is going to be hard in your case). Just make a new topmost window with a listbox and status bar, then you are free to implement the selection behavior on the listbox like you need it.
Vs 2010 is a WPF application. If you are in the beginning of this application development than use WPF as a core technology. WPF drop down button is implemented in WPF ribbon. Source code is available on CodePlex.