WinForms - Reloading Dynamically Created UserControl - c#

My application gets a list of files creates a panel for each file with a delete button an puts all of the panels in a flowPanel Layout. While
it is creating the panels it shows a loading panel. See the link below. All that works great. My issue is once a file is deleted I need to reload the flowpanel from the updated directory where we just deleted a file.
Since I have to make my onclick static to keep the RunAsyncProcess() method happy. I cant get back to my UI to reload the control. I hope this make sense. I'm struggling to even find the right search terms for google on this.
Reference to the loading panel methods such as RunAsyncOperation(MyDelegate1); found here.
http://www.codeproject.com/Articles/24044/AJAX-style-Asynchronous-Progress-Dialog-for-WinFor
Here is how my control is loaded.
private void button1_Click(object sender, EventArgs e)
{
SuspendLayout();
Control ctrl = Parent.Parent.Controls.Find("MainControlPanel", false).First();
MyControl myControl = new MyControl();
myControl .Dock = DockStyle.Fill;
Parent.Controls.Remove(this);//removes a menu control
ctrl.Controls.Add(myControl);
ResumeLayout();
}
Here is the control
bool isLoaded {get; set;}
List<Panel> panels {get; set;}
protected override void OnLoad(EventArgs e)
{
isLoaded = false;
panels = new List<Panel>();
RunAsyncOperation(MyDelegate1);
RunAsyncOperation(MyDelegate2);
while (!isLoaded) { //just wait }
foreach (Panel panel in panels)
{
flowLayoutPanel1.Controls.Add(panel);
}
}
AsyncProcessDelegate MyDelagate = delegate ()
{
//setting up the ui
string[] list = ...
foreach(in list)
{
Panel p1 = new Panel();
Button btn = new Button()
btn.Click += new EventHandler(MyEvent); // my event must be static
p1.Controls.Add(btn)
panels.Add(p1);
}
isloaded = true;
}
AsyncProcessDelegate MyDelagate2 = delegate ()
{
while (!isLoaded)
{
//showing the loading ui
Thread.Sleep(5000);
}
};
public static void MyEvent(object sender, EventArgs e)
{
Modifies string[] list and needs to reload
is there a way to call onload again?
How can I make it reload
//this does not work
flowLayoutPanel1.Controls.Clear();
RunAsyncOperation(MyDelegate1);
RunAsyncOperation(MyDelegate2);
while (!isLoaded) { //just wait }
foreach (Panel panel in panels)
{
flowLayoutPanel1.Controls.Add(panel);
}
}

Added flag to show changed data
static bool reload { get; set; }
Added to onload
stopwatch = new Stopwatch();
reload = false;
stopwatch.Start();
PollUpdate();
Added poll method to check if we should reload
public void PollUpdate()
{
while (true)
{
if (reload)
{
stopwatch.Stop();
reload = false;
SuspendLayout();
Control ctrl = Parent.Parent.Controls.Find("MainControlPanel", false).First();
AudioLibraryControl cr = new AudioLibraryControl();
cr.Dock = DockStyle.Fill;
Parent.Controls.Remove(this);
ctrl.Controls.Add(cr);
ResumeLayout();
}
Application.DoEvents();
}
}

Related

ContextMenuStrip in c# tray application not reacting correctly when in expanded icon window

I have made a tray application with an icon that opens a ContextMenuStrip on Icon Click. I have three ToolStripMenuItem that can be clicked.
The Tray Application is working fine as long as the icon is visible directly. However if I have to click on the chevron to expand the non visible tray icons, I run into one Problem.
I can open the Menu by click on the Item. If I click on one of the ToolStripMenuItems the Tray-Menu goes into the Background of the Expanded Tray Icons and cannot be clicked anymore. How can I prevent this?
It seems the background is capturing the click rather then the openend form.
Here is the code for the Menu.
class Menu
{
private static ContextMenuStrip contextMenuStrip;
private static NotifyIcon notifyIcon1 = new NotifyIcon();
public Menu()
{
notifyIcon1.Icon = new Icon("icon.ico");
notifyIcon1.Text = "icon";
contextMenuStrip = new ContextMenuStrip();
ToolStripItem stripItem0 = new ToolStripMenuItem("open");
contextMenuStrip.Items.AddRange(new ToolStripItem[] { stripItem0 });
ToolStripItem stripItem1 = new ToolStripMenuItem("stop");
stripItem1.Click += new EventHandler(ToggleTracking);
contextMenuStrip.Items.AddRange(new ToolStripItem[] { stripItem1 });
ToolStripItem line = new ToolStripSeparator();
contextMenuStrip.Items.AddRange(new ToolStripItem[] { line });
ToolStripItem stripItem2 = new ToolStripMenuItem("close");
stripItem2.Click += new EventHandler(Close);
contextMenuStrip.Items.AddRange(new ToolStripItem[] { stripItem2 });
notifyIcon1.ContextMenuStrip = contextMenuStrip;
//notifyIcon1.ContextMenu = contextMenu1;
notifyIcon1.Click += new EventHandler(IconClick);
notifyIcon1.Visible = true;
}
private void ToggleTracking(object Sender, EventArgs e)
{
ToolStripMenuItem stripItem1 = (ToolStripMenuItem)contextMenuStrip.Items[1];
if (stripItem1.Text == "stop")
{
stripItem1.Text = "restart";
Batch.StopTimer();
}
else
{
stripItem1.Text = "stop";
Batch.RestartTimer();
}
}
private void Close(object Sender, EventArgs e)
{
Application.Exit();
}
private void IconClick(object Sender, EventArgs e)
{
Control strip = Sender as Control;
if (contextMenuStrip.Visible)
{
contextMenuStrip.Hide();
}
else
{
contextMenuStrip.Show(Cursor.Position);
}
}
}
I had to use the BringToFront method like this.
{
contextMenuStrip.Show(Cursor.Position);
contextMenuStrip.BringToFront();
}
https://msdn.microsoft.com/de-de/library/system.windows.forms.control.bringtofront(v=vs.110).aspx

VSTO Word Content Control - adding multiple RichTextContentControls at run time

I'm creating a Word add-in which allows the user to select various text in a Word document and click a button on the ribbon which will wrap that text with a Content Control (rich text). Eventually these content controls will then be mapped to XML.
The code so far is like this:
public partial class Ribbon1
{
private RichTextContentControl titleRichTextControl;
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
}
private void addTitle_Click(object sender, RibbonControlEventArgs e)
{
AddRichTextControlAtSelection();
}
private void AddRichTextControlAtSelection()
{
word.Document currentDocument = Globals.ThisAddIn.Application.ActiveDocument;
currentDocument.ActiveWindow.Selection.Range.Select();
Document extendedDocument = Globals.Factory.GetVstoObject(currentDocument);
titleRichTextControl = extendedDocument.Controls.AddRichTextContentControl("titleRichTextControl");
titleRichTextControl.PlaceholderText = "Enter the title";
titleRichTextControl.Title = "Title";
titleRichTextControl.Tag = "title";
}
}
All this is fine and it works for the first time the button is clicked. However, if there is more than one 'title' (in this case) that needs adding, and the user presses the button a second time, it throws the error:
The control cannot be added because a control with the name titleRichTextControl already exists in the Controls collection.
It's clear why it complains, but i can't think of the correct way to go to allow multiple clicks of the button to generate multiple content controls of the same type (rich text content control) and the same name ("title" for example).
Can anybody point me in the right direction please.
OK this was how i did it in the end:
private void addTitle_Click(object sender, RibbonControlEventArgs e)
{
AddRichTextControlAtSelection();
}
int count = 0;
private void AddRichTextControlAtSelection()
{
word.Document currentDocument = Globals.ThisAddIn.Application.ActiveDocument;
Document extendedDocument = Globals.Factory.GetVstoObject(currentDocument);
if (currentDocument.ContentControls.Count > 0)
{
currentDocument.ActiveWindow.Selection.Range.HighlightColorIndex = word.WdColorIndex.wdYellow;
currentDocument.ActiveWindow.Selection.Range.Select();
richTextControls = new List<RichTextContentControl>();
foreach (word.ContentControl nativeControl in currentDocument.ContentControls)
{
if (nativeControl.Type == Microsoft.Office.Interop.Word.WdContentControlType.wdContentControlRichText)
{
count++;
RichTextContentControl tempControl = extendedDocument.Controls.AddRichTextContentControl("VSTORichTextControl" + count.ToString());
richTextControls.Add(tempControl);
tempControl.Title = "Title";
tempControl.Tag = "title";
break;
}
}
}
else
{
RichTextContentControl VSTORichTextControl;
VSTORichTextControl = extendedDocument.Controls.AddRichTextContentControl("VSTORichTextControl");
VSTORichTextControl.PlaceholderText = "Enter the DM title";
VSTORichTextControl.Title = "Title";
VSTORichTextControl.Tag = "title";
}
}

How do edit controls that were created in C# during runtime?

So i have this block of code and i have a button called AddNewButton which adds a StackPanel into a already created StackPanel called MainStackPanel which is irrelevant but the "GroupPanel" has child controls such as "GroupName", "GroupTextBox" and "GroupEdit".
Now the "GroupEdit" button has a click event that runs the void named "GroupEdit_Click" and in that void i use Button GroupEdit1 = sender as Button; Now this works and makes me able to access the buttons properties and change content but my problem is: How do i access the other controls such as "GroupPanel", "GroupName" and "GroupTextBox". I will use the AddNewButton a few times so when i access the separate controls they need to be accessed seperately
I tried to get rid of as much unnecessary code.
private void AddNewButton_Click(object sender, RoutedEventArgs e)
{
StackPanel GroupPanel = new StackPanel();
TextBlock GroupName = new TextBlock();
GroupName.Text = "Group ";
TextBox GroupTextBox = new TextBox();
GroupTextBox.Visibility = Visibility.Collapsed;
Button GroupEdit = new Button();
GroupEdit.Content = "Edit Group";
GroupEdit.Click += new RoutedEventHandler(GroupEdit_Click);
GroupPanel.Children.Add(GroupName);
GroupPanel.Children.Add(GroupTextBox);
GroupPanel.Children.Add(GroupEdit);
}
private void GroupEdit_Click(object sender,RoutedEventArgs e)
{
Button GroupEdit1 = sender as Button;
GroupEdit1.Content = "Done";
//Now how do i access these controls?
GroupName.Visibility = Visibility.Collapsed;
GroupTextBox.Visibility = Visibility.Visible;
}
}
You could maintain a private List of your dynamically added GroupEdit controls and assign them numbered tags.
private List<TextBox> dynamicGroupEdits = new List<TextBox>();
private void AddNewButton_Click(object sender, RoutedEventArgs e)
{
...
dynamicGroupEdits.Add(GroupEdit);
GroupEdit.Tag = dynamicGroupEdits.Count;
GroupPanel.Tag = GroupEdit.Tag;
GroupTextBox.Tag = GroupEdit.Tag;
...
}
private void GroupEdit_Click(object sender,RoutedEventArgs e)
{
...
tag = GroupEdit1.Tag;
// Loop through all child controls and set visibility according to tag
for each (var c in LogicalTreeHelper.GetChildren(GroupEdit1.Parent)
{
if(c is TextBox && c.Tag == tag)
c.Visible =Visibility.Visible;
else if(c is TextBlock && c.Tag == tag)
c.Visibility = Visibility.Collapsed;
}
}

Hide Form when clicked outside of DataGridView

I have a Form which holds a DataGridView, this Form also loads with an invisible Form which only holds another DataGridView. The second DGV is used to display more information on the items in the first DGV.
The second DGV should only be shown when the user clicks inside the 7th Cell of any row in the first DGV. I have already managed to get it to hide when I click other cells, but I can't seem to get it to hide when I click outside the DataGridView. I have already tried the Leave, RowLeave and LostFocus events without success. I think it is because as soon as the second DataGridView is displayed, it gets the focus and this somehow messes with the event.
Here is my code:
public class Form1
{
Form schedules = new Form();
DataGridView backups = new DataGridView();
public Form1()
{
this.schedules.Visible = false;
backups.DataBind();
}
private void backups_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex != -1 && e.ColumnIndex == 7)
{
if (this.schedules.getData(Convert.ToInt32(backups.Rows[e.RowIndex].Cells[0].Value)))
{
this.schedules.Owner = this;
this.schedules.Visible = true;
this.schedules.changePosition(Cursor.Position);
}
else
{
this.schedules.Visible = false;
}
}
else
{
this.schedules.Visible = false;
}
}
}
public class Schedules : Form
{
DataGridView grdSchedules = new DataGridView();
public Schedules()
{
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Visible = false;
this.AutoSize = true;
this.grdSchedules.RowHeadersVisible = false;
this.grdSchedules.AllowUserToAddRows = false;
this.grdSchedules.ScrollBars = ScrollBars.None;
this.grdSchedules.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
this.grdSchedules.AllowUserToResizeColumns = false;
this.grdSchedules.AllowUserToResizeRows = false;
this.grdSchedules.AllowUserToDeleteRows = false;
}
}
private void Form1_Click(object sender, EventArgs e)
{
this.schedules.Visible = false;
}
Users tend to click on the biggest window they see to close popups. You can also do the same with the secondary form; or even add a close button to it.
I think you would want to combine Form Click and Grid Leave event to make it work.
private void Form1_Click(object sender, EventArgs e)
{
detailForm.Visible = false;
}
private void dataGridView1_Leave(object sender, EventArgs e)
{
detailForm.Visible = false;
}
Now if a user clicks outside Grid on form or directly into a different control, then your detail form should be hidden.
Hope it helps.

Dynamically added ImageButton Command event not firing until second click

I have a page where I'm adding ImageButtons dynamically. I first set the OnClientClick of the buttons to simply show a popup of the image enlarged and return false for no postback.
I have a button on the page to set the "primary image" so when this button is clicked I set a property called _IsSettingPrimaryPhotoMode = true, call the function to recreate the ImageButtons, and when creating the ImageButtons if this property is true instead of adding an OnClientClick, I hook up a CommandEventHandler so I can tell which button was clicked by reading the CommandArgument.
The problem is the event handler won't fire on the first click of the image but only on the second click and thereafter. I've also moved the code from Page_Load to OnInit and I load the ImageButtons on every postback.
I save the _IsSettingPrimaryPhotoMode to the Session.
private bool _IsSettingPrimaryPhotoMode {
get {
bool result = false;
if(Session[ConstantsWeb.Session.IS_DELETE_IMAGE_MODE] != null) {
result = Convert.ToBoolean(Session[ConstantsWeb.Session.IS_SETTING_PRIMARY_IMAGE_MODE]);
}
return result;
}
set {
Session[ConstantsWeb.Session.IS_SETTING_PRIMARY_IMAGE_MODE] = value;
}
}
The page OnInit
protected override void OnInit(EventArgs e) {
base.OnInit(e);
if(!IsPostBack) {
_IsSettingPrimaryPhotoMode = false;
}
_LoadGalleryImages();
}
}
The _LoadGalleryImages method
private void _LoadGalleryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
foreach(PhotoGalleryImage image in images) {
ImageButton displayImage = new ImageButton();
Panel panel = new Panel();
panelPhotoContainer.Controls.Add(panel);
displayImage.ImageUrl = "some URL";
if(!_IsSettingPrimaryPhotoMode) {
displayImage.OnClientClick = "showPopup(); return false;";
}
else {
displayImage.Command += new CommandEventHandler(displayImage_Command);
displayImage.CommandName = "ImageButton" + image.PhotoGalleryImageId.ToString();
displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
}
panel.Controls.Add(displayImage);
}
}
btnSetPrimaryPhoto_Click
protected void btnSetPrimaryPhoto_Click(object sender, EventArgs e) {
// if I don't call this, duplicate controls will be added since they were added
// from OnInit calling _LoadGalleryImages();
panelPhotoContainer.Controls.Clear();
_IsSettingPrimaryPhotoMode = true;
// reload since _IsSettingPrimaryPhotoMode has now changed
_LoadGalleryImages();
}
What am I doing wrong?
I suppose the issue can be caused by the fact you haven't set IDs of the dynamically created controls. It's quite important, as it's used in the process of firing the post back events. Value of the ID for each of the controls should be constant and not change between postbacks.
You can try to modify your _LoadGalleryImages() method like this:
private void _LoadGalleryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
int imageCtrlCounter = 0;
foreach(PhotoGalleryImage image in images) {
ImageButton displayImage = new ImageButton() { ID = String.Format("myDisplayImage{0}", imageCtrlCounter) };
Panel panel = new Panel();
panelPhotoContainer.Controls.Add(panel);
displayImage.ImageUrl = "some URL";
if(!_IsSettingPrimaryPhotoMode) {
displayImage.OnClientClick = "showPopup(); return false;";
}
else {
displayImage.Command += new CommandEventHandler(displayImage_Command);
displayImage.CommandName = "ImageButton" + image.PhotoGalleryImageId.ToString();
displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
}
panel.Controls.Add(displayImage);
imageCtrlCounter++;
}
}
It has to be something related to the initial event wireup because the problem only happens the first time. What's different about that time is that _LoadGalleryImages is called twice (once in the init and once in the button click event handler) so I think that something is not getting cleaned up there when you clear the container panel and call _LoadGalleryImages again in the button's click handler.
Why not try this alternative:
Only call LoadImageGalleries once per page cycle (in the init).
Instead of clearing the controls and calling LoadGalleryImages again in the same postback (in the button click event), on the button click call a method that iterates through the image controls you already created when LoadGalleryImages was called and adjust them:
1) Remove the onclientclick (clear it out).
2) Attach the event.
#swannee
Actually, your method did work after I thought more about it. I do now call _LoadGalleryImages on every OnInit. I realize this is a lot of duplicate code that could be consolidated.
New _LoadGalleryImages
private void _LoadGalleryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
foreach(PhotoGalleryImage image in images) {
Panel panel = new Panel();
panelPhotoContainer.Controls.Add(panel);
ImageButton displayImage = new ImageButton();
panel.Controls.Add(displayImage);
displayImage.ID = string.Format("ImageButton{0}", image.PhotoGalleryImageId);
displayImage.ImageUrl = "Some URL";
displayImage.AlternateText = displayImage.ToolTip = image.ImageName;
if(!_IsSettingPrimaryPhotoMode) {
displayImage.OnClientClick = "showPopup(); return false;";
}
else {
// handles the image button command wireup
displayImage.Command += new CommandEventHandler(displayImage_Command);
displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
}
}
}
I added a new method as you suggested to find the controls since they've already been created in OnInit and I just need to find them after the button click and clear the OnClientClick.
private void _LoadSelectPrimaryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
foreach(PhotoGalleryImage image in images) {
Control control = panelPhotoContainer.FindControl(string.Format("ImageButton{0}", image.PhotoGalleryImageId));
if(control != null) {
ImageButton displayImage = (ImageButton)control;
displayImage.OnClientClick = "";
}
}
}
I also have a cancel button to return the image buttons to the way they were before to show the popup.
private void _ResetGalleryImages() {
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages(_photoGalleryId, false, true);
foreach(PhotoGalleryImage image in images) {
Control control = panelPhotoContainer.FindControl(string.Format("ImageButton{0}", image.PhotoGalleryImageId));
if(control != null) {
ImageButton displayImage = (ImageButton)control;
displayImage.ImageUrl = "Original URL";
displayImage.OnClientClick = "showPopup(); return false;";
}
}
}
and two page button clicks
protected void btnSetPrimaryPhoto_Click(object sender, EventArgs e) {
_IsSettingPrimaryPhotoMode = true;
_LoadSelectPrimaryImages();
}
protected void btnCancelSetPrimaryPhoto_Click(object sender, EventArgs e) {
_IsSettingPrimaryPhotoMode = false;
_ResetGalleryImages();
}
Someone said in a response earlier...looks like the response was removed...to clear the controls in _LoadGalleryImages such as:
private void _LoadGalleryImages() {
panelPhotoContainer.Controls.Clear();
PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();
foreach(PhotoGalleryImage image in images) {
ImageButton displayImage = new ImageButton();
Panel panel = new Panel();
panelPhotoContainer.Controls.Add(panel);
displayImage.ImageUrl = "some URL";
if(!_IsSettingPrimaryPhotoMode) {
displayImage.OnClientClick = "showPopup(); return false;";
}
else {
displayImage.Command += new CommandEventHandler(displayImage_Command);
displayImage.CommandName = "ImageButton" + image.PhotoGalleryImageId.ToString();
displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
}
panel.Controls.Add(displayImage);
}
}
which also works but I think that may be more inefficient than your method, #swannee. Thanks!

Categories

Resources