How to get button name added on UniformGrid runtime? - c#

Get Button name added on UniformGrid during run time.
My code is:
for (int i = 1; i <= no; ++i)
{
Button button = new Button()
{
Content = i,
Tag = i,
Background = Brushes.White,
Height = 30,
Width = 30,
Name="A" + i.ToString()
};
string name=button.Name;
button.Click += new RoutedEventHandler(button_Click);
this.grid1.Children.Add(button);
if (name.Equals("A1"))
{
button.Background = Brushes.White;
}
}
My requirement is to get Button name in other function:
private void Sum()
{
}
Here is my XAML:
<UniformGrid x:Name="grid1" Margin="816,115,96,354" Grid.Column="1" />

It isn't clear what is the ultimate goal here. But you can loop through all child of UniformGrid which type is Button to get name of each button and take action accordingly :
foreach (var btn in grid.Children.OfType<Button>())
{
var btnName = btn.Name;
//take action according to button name
}

Related

Data Template Button created in XamlReader don't firing events

I'm trying to create a ListView Page that works for every object in my app where I can show all the objects received by parameter from a List<object> where I don't know which object the page will have to handle, I also receive the fields to show as parameters in a List <string, string> where the first string is the type of the field (header/subheader/image) and for that, I had to use XAML Reader so I could create the data bindings in the code behind.
Here's my code:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var param = (Dictionary<string, object>)e.Parameter;
_ItemsList = (List<object>)param["itemsList"];
_Fields = (Dictionary<string, string>)param["fields"];
_DetailsPage = (Type)param["detailPage"];
EditCommand = new UniversalListViewCommand();
ObjListView.ItemsSource = UniversalAutoSuggestBox.ItemsSource = _ItemsList;
MainStackPanel.DataContext = this;
ObjListView.ItemTemplate = NormalItemTemplate = (DataTemplate)XamlReader.Load(GenerateDataTemplate("NormalItemTemplate"));
SelectedItemTemplate = (DataTemplate)XamlReader.Load(GenerateDataTemplate("SelectedItemTemplate"));
}
public string GenerateDataTemplate(string param)
{
StringBuilder sbTemp = new();
//Data Template definition
if (param == "NormalItemTemplate") sbTemp.Append("<DataTemplate x:Key=\"NormalItemTemplate\" ");
if (param == "SelectedItemTemplate") sbTemp.Append("<DataTemplate x:Key=\"SelectedItemTemplate\" ");
//sbTemp.Append("x:Class = \"xizPrototipo_0_2.Pages.UniversalListViewPage\" ");
sbTemp.Append(#"xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" ");
sbTemp.Append(#"xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">");
//Grid definition
sbTemp.Append("<Grid MinWidth=\"350\" Margin=\"5\">");
//Grid row definition
sbTemp.Append("<Grid.RowDefinitions>");
sbTemp.Append("<RowDefinition Height = \"*\" />");
sbTemp.Append("<RowDefinition Height = \"*\" />");
sbTemp.Append("<RowDefinition Height = \"*\" />");
sbTemp.Append("</Grid.RowDefinitions>");
//Grid column definition
sbTemp.Append("<Grid.ColumnDefinitions>");
sbTemp.Append("<ColumnDefinition Width = \"Auto\"/>");
sbTemp.Append("<ColumnDefinition Width = \"*\" />");
sbTemp.Append("</Grid.ColumnDefinitions>");
//Ellipse definition
sbTemp.Append("<Ellipse Grid.Row=\"0\" Grid.RowSpan=\"2\" Width = \"32\" Height = \"32\" Margin = \"6\" VerticalAlignment = \"Center\" HorizontalAlignment = \"Center\">");
sbTemp.Append("<Ellipse.Fill> <ImageBrush x:Name =\"LogoImage\" ImageSource = \"{Binding " + _Fields["Image"] + "}\" /> </Ellipse.Fill> ");
sbTemp.Append("</Ellipse>");
//Header Text Block Definition
sbTemp.Append("<TextBlock Grid.Row = \"0\" Grid.Column = \"1\" Text = \"{Binding " + _Fields["Header"] + "}\" Style = \"{ThemeResource BaseTextBlockStyle}\" Margin = \"12,6,0,0\"/> ");
//Subheader Text Block Definition
sbTemp.Append("<TextBlock Grid.Row=\"1\" Grid.Column = \"1\" Text = \"{Binding " + _Fields["Subheader"] + "}\" Style = \"{ThemeResource BodyTextBlockStyle}\" Margin = \"12,0,0,6\" /> ");
//Button (case Selected)
if (param == "SelectedItemTemplate")
{
sbTemp.Append("<StackPanel Grid.Row=\"2\" Grid.Column=\"1\" Orientation =\"Horizontal\" HorizontalAlignment =\"Right\" Spacing = \"5\" > ");
sbTemp.Append("<Button x:Name=\"EditButton\" Content=\"Editar\" Click=\"AlterButton_Click\" />");
sbTemp.Append("</StackPanel>");
}
//Grid end
sbTemp.Append("</Grid>");
//DataTemplate end
sbTemp.Append("</DataTemplate>");
return sbTemp.ToString();
}
With this method I could get the outcome that I wanted but when I click the button created in the following line it don't fires any event:
sbTemp.Append("<Button x:Name=\"EditButton\" Content=\"Editar\" Click=\"AlterButton_Click\" />");
I also tried using commands, Data Template selector and still I couldn't do anything with that button.
Does anyone know how can I put that button to work?
(Yes, I have the event on the button created and a function to change the Data Template to show the button.)
Data Template Button created in XamlReader don't firing events
I am afraid it will not respond to the click event handler created from the string xaml. Because the click event registration process will be saved in the xxpage.g.cs file during pre-compilation. However, if you load the data template from the string runtime. It will not register for this event.
So the better way is binding command for button.
For example
public MainPage()
{
this.InitializeComponent();
DataTemplate itmeTemplate = (DataTemplate)XamlReader.Load(
#"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
<Button Command='{Binding BtnClickCommand}' Content='Editor' />
</DataTemplate>");
TestListView.ItemTemplate = itmeTemplate;
NumbersList = new ObservableCollection<Item>();
for (int i = 0; i < 50; i++)
{
var item = new Item ();
NumbersList.Add(item);
}
TestListView.ItemsSource = NumbersList;
}
public ObservableCollection<Item> NumbersList { get; set; }
Model
public class Item : INotifyPropertyChanged
{
public ICommand BtnClickCommand
{
get
{
return new RelayCommand(() =>
{
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Xaml Code
<Grid x:Name="RootGrid">
<ListView
x:Name="TestListView"
ItemsSource="{x:Bind NumbersList}"
Visibility="Visible">
</ListView>
</Grid>
Update 1
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
DataTemplate itmeTemplate = (DataTemplate)XamlReader.Load(
#"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
<Button Command='{Binding DataContext.BtnClickCommand, ElementName=TestListView}' Content='Editor' />
</DataTemplate>");
TestListView.ItemTemplate = itmeTemplate;
NumbersList = new ObservableCollection<Item>();
for (int i = 0; i < 50; i++)
{
var item = new Item ();
NumbersList.Add(item);
}
TestListView.ItemsSource = NumbersList;
}
public ICommand BtnClickCommand
{
get
{
return new RelayCommand(async () =>
{
});
}
}

How to Create Dynamic combo boxes in stack panel in wpf, retrieve their values and delete them

I want create dynamic comboboxes in wpf stack panel, retrive their values and delete them when the user enters the number in a textbox. Following is the code that I have used, that when the user enter the number in the textbox, (on TextEventChaged) to add comboboxes to the stackpanel(i.e, VehiclesPerday):
<TextBox x:Name="NumberOfVehciles" FontSize="15" HorizontalAlignment="Left" Height="40" TextChanged="NumberOfVehciles_TextChanged"/>
<WrapPanel x:Name="VehiclesPerday" HorizontalAlignment="Left">
</WrapPanel>
BackEnd
private void NumberOfVehciles_TextChanged(object sender, TextChangedEventArgs e)
{
int _count = Convert.ToInt32(NumberOfVehciles.Text.Trim());
for (int x = 1; x <= _count; x++)
{
ComboBox cmb = new ComboBox();
cmb.Name = "cmbd" + x.ToString();
cmb.Height = 40;
cmb.HorizontalAlignment = HorizontalAlignment.Left;
cmb.FontSize = 15;
cmb.Width = 200;
cmb.VerticalAlignment = VerticalAlignment.Top;
cmb.Margin = new Thickness(50, 40, 0, 0);
VehiclesPerday.Children.Add(cmb);
}
}
SubmitButton for retrieving data i have tried, it show null value to comboxbox when i debug it
private void SubmitButton_Click(object sender, RoutedEventArgs e)
{
int _count = Convert.ToInt32(NumberOfVehciles.Text.Trim());
for (int x = 1; x <= _count; x++)
{
ComboBox _vehicle = (ComboBox)this.VehiclesPerday.FindName("cmbd" + x.ToString());
}
}
And also when the user changes the value in the textbox, it should remove the combo boxes created in the stack panel and do the vice-versa after changing his value, Eg.
If the user on first go enters 2 in the textbox, 2 combo boxes should be created.
Now if user wants to change the value to 2 to 1 , it should delete the created combo boxes from the stack panel and recreate.
I've added checking if text in your textbox is number and can be converted to int
Added call VehiclesPerday.Children.Clear() just for tests
Added foreach loop to find the proper ComboBox by Name
private void NumberOfVehciles_TextChanged(object sender, TextChangedEventArgs e)
{
if (int.TryParse(NumberOfVehciles.Text.Trim(), out int _count))
{
VehiclesPerday.Children.Clear(); // for tests
for (int x = 1; x <= _count; x++)
{
ComboBox cmb = new ComboBox // Visual studio simplified object creation here
{
Name = "cmbd" + x.ToString(),
Height = 40,
HorizontalAlignment = HorizontalAlignment.Left,
FontSize = 15,
Width = 200,
VerticalAlignment = VerticalAlignment.Top,
Margin = new Thickness(50, 40, 0, 0)
};
VehiclesPerday.Children.Add(cmb);
}
}
}
private void SubmitButton_Click(object sender, RoutedEventArgs e)
{
if (int.TryParse(NumberOfVehciles.Text.Trim(), out int _count))
{
for (int x = 1; x <= _count; x++)
{
ComboBox _vehicle = null;
foreach (ComboBox box in VehiclesPerday.Children)
{
if (box.Name == "cmbd" + x.ToString())
{
_vehicle = box; // ComboBox found
break;
}
}
MessageBox.Show(_vehicle?.Name ?? "ComboBox not found!");
}
}
}

Switching to dynamically created TabPage on button click

I'm practicing my coding and am trying to create a till by Dynamically prefill the items that are stored in a text file. I can dynamically create Tabs, Buttons and create menu buttons based on the categories of items. Where I'm struggling is I'm trying to switch the Tab on a button click. The Tabs are given a Name, which is the category ID, and the Text displays the category. In the event that trys to switch the tab I get the following error:
Error CS0266 Cannot implicitly convert type 'object' to 'System.Windows.Forms.TabPage'. An explicit conversion exists (are you missing a cast?)
I'm presuming that I need to Create a tab page or something, but I can't find out how to do this. Been on it for hours! Here's my code....
public partial class Form1 : Form
{
private void Form1_Load(object sender, EventArgs e)
{
string[] loadedFile = File.ReadAllLines(#"h:\shopItemsV2.txt");
foreach (string line in loadedFile)
{
// Split string and create required variables
string[] newBtnData = line.Split(',');
int catID = int.Parse(newBtnData[0]);
string cat = newBtnData[1];
string item = newBtnData[2];
double price = double.Parse(newBtnData[3]);
// Create tab if needed
if (tabControl1.TabCount < catID)
{
TabPage tp = new TabPage()
{
Text = cat,
Name = catID.ToString()
};
tabControl1.TabPages.Add(tp);
// Add FlowLayoutPanel with unique name
FlowLayoutPanel fp = new FlowLayoutPanel()
{
Name = "fp" + catID.ToString(),
Dock = DockStyle.Fill
};
// Add FlowLayoutPanel to correct Tab
tabControl1.TabPages[catID-1].Controls.Add(fp);
// Create Button for menu
Button newMenuBtn = new Button()
{
Name = cat + "Btn",
Tag = catID,
Width = 100,
Height = 50,
Text = cat,
};
newMenuBtn.Click += SwitchTab;
menuFP.Controls.Add(newMenuBtn);
}
// Create Button
Button newBtn = new Button()
{
Name = item,
Tag = price,
Width = 100,
Height = 100,
Text = item,
};
newBtn.Click += AddItem;
//Add button to correct tab
foreach (TabPage tabP in tabControl1.TabPages)
{
if (tabP.Name == catID.ToString())
{
Control fp = this.Controls.Find("fp"+catID, true).First();
fp.Controls.Add(newBtn);
}
}
}
}
private void SwitchTab(object sender, EventArgs e)
{
// Create button, switch to required Tab
// Tabs named the same as Tag on the button
Button clickedBtn = sender as Button;
tabControl1.SelectedTab = clickedBtn.Tag;
}
}
Any help would be greatly appreciated.
You can store anything in the Tag() property of your button. With that in mind, store a reference to your TabPage!
Change:
// Create Button for menu
Button newMenuBtn = new Button()
{
Name = cat + "Btn",
Tag = catID,
Width = 100,
Height = 50,
Text = cat,
};
To:
// Create Button for menu
Button newMenuBtn = new Button()
{
Name = cat + "Btn",
Tag = tp; // store the reference to the TabPage you created
Width = 100,
Height = 50,
Text = cat,
};
Then the suggestion by Uwe Keim should work:
tabControl1.SelectedTab = clickedBtn.Tag as TabPage;
private void AddNewPr_Click(object sender, EventArgs e)
{
TabPage tab = new TabPage();
_list = new ListBox();
_list2 = new ListBox();
PictureBox picBox = new PictureBox();
picBox.Click = picBox_Click;
//More stuff here
//Add the controls
tabControl1.Controls.Add(tab);
tab.Controls.Add(list);
tab.Controls.Add(list2);
tab.Controls.Add(pictureBox);
}

Create StackPanels dynamically and refer to any of them in code behind

In its simplest form...
I would like to create as many StackPanels as I want and then add Rectangles in them. Then to be able to change the Fill color of any one of the Rectangles when I click the Start Button for instance. All in Code Behind.
Any help would be appreciated.
For example, if our favorite beer wrote the framework I could do it like this:
XAML:
<Page
x:Class="Test2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Test2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button Name="StartButton" Content="Start" Click="StartButton_Click" Height="30" Width="200" Margin="5"/>
</StackPanel>
<StackPanel Grid.Row="1" Name="myStackPanel" VerticalAlignment="Top"/>
</Grid>
</Page>
Code Behind:
namespace Test2
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
for (var i = 0; i < 5; i++) // The 5 here could be any number
{
myStackPanel.Children.Add(new StackPanel
{
Name = "myPanel" + i,
Orientation = Orientation.Horizontal
});
for (var j = 0; j < 10; j++) // The 10 here could be any number
{
("myPanel" + i).Children.Add(new Rectangle
{
Name = "myRectangle" + i + "-" + j,
Fill = new SolidColorBrush(Colors.Black),
Width = 20,
Height = 20,
Margin = new Thickness(1)
});
}
}
}
private void StartButton_Click(object sender, RoutedEventArgs e)
{
// E.G. To change the Fill color of Rectangle4 in StackPanel2
("myRectangle" + 2 + "-" + 4).Fill = new SolidColorBrush(Colors.Red);
}
}
}
Firstly, to add Rectangle shapes, we can create an instance of StackPanel and manipulate its Children elements:
for (var i = 0; i < 5; i++) // The 5 here could be any number
{
StackPanel sp = new StackPanel
{
Name = "myPanel" + i,
Orientation = Orientation.Horizontal
};
myStackPanel.Children.Add(sp);
for (var j = 0; j < 10; j++) // The 10 here could be any number
{
sp.Children.Add(new Rectangle
{
Name = "myRectangle" + i + "-" + j,
Fill = new SolidColorBrush(Colors.Black),
Width = 20,
Height = 20,
Margin = new Thickness(1)
});
}
}
Then to be able to change the Fill color of any one of the Rectangles when I click the Start Button for instance. All in Code Behind.
As tgpdyk mentioned, we need to use VisualTreeHelper to find the specified rectangle shape.
Helper class:
public static class FrameworkElementExtensions
{
public static T TraverseCTFindShape<T>(DependencyObject root, String name) where T : Windows.UI.Xaml.Shapes.Shape
{
T control = null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)
{
var child = VisualTreeHelper.GetChild(root, i);
string childName = child.GetValue(FrameworkElement.NameProperty) as string;
control = child as T;
if (childName == name)
{
return control;
}
else
{
control = TraverseCTFindShape<T>(child, name);
if (control != null)
{
return control;
}
}
}
return control;
}
}
How to use it:
private void StartButton_Click(object sender, RoutedEventArgs e)
{
// E.G. To change the Fill color of Rectangle4 in StackPanel2
var rec = FrameworkElementExtensions.TraverseCTFindShape<Shape>(myStackPanel, "myRectangle" + 2 + "-" + 4);
rec.Fill = new SolidColorBrush(Colors.Red);
}
I've uploaded my sample to Github repository
That is not how you approach this in WPF, at all.
You usually do not concern yourself with any UI components but only the data. In this case you data bind an ItemsControl to a list of rows, each row containing a list of cells. In the ItemsControl definition you then set an ItemTemplate that contains another ItemsControl binding to the cells. In the nested ItemsControl you then can set an ItemTemplate where you bind the Background to a (notifying) property of your cells which you then just need to change in code.
Check out these overviews:
Data Binding Overview
Data Templating Overview
You may also want to look into the Model-View-ViewModel pattern to ensure a suitable application architecture.

Visual Studio-style undo drop-down button - custom ToolStripSplitButton

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.

Categories