I have 2 user controls. My MainPage control and my edit functions control. My edit control uses WCF to update a database. Once this is done I need to reload the Mainpage control which searched the database to see the changes mad by the edit functions control.
I did this in an asp.net project by redirecting to the MainPage - do you know how this is done in Silverlight.
Ok so i did this by creating a Button at the top of my main page which fires a reload of the page.
I then used the Visual tree helper to get the button and invoke it. I did this by:
Create a class to search Controls:
public static class ControlFinder
{
public static T FindParent(UIElement control) where T : UIElement
{
UIElement p = VisualTreeHelper.GetParent(control) as UIElement;
if (p != null)
{
if (p is T)
return p as T;
else
return ControlFinder.FindParent(p);
}
return null;
}
}
Find the Button within the controls:
UserControl uc = ControlFinder.FindParent(this);
UserControl mainControls = ControlFinder.FindParent(uc);
var PageGrid = VisualTreeHelper.GetChild(mainControls, 0);
var StackPanel = VisualTreeHelper.GetChild(PageGrid, 0);
Button RefreshButton = (Button)VisualTreeHelper.GetChild(StackPanel, 0);
Invoke the button event which fires the refresh
ButtonAutomationPeer buttonAutoPeer = new ButtonAutomationPeer(RefreshButton);
IInvokeProvider invokeProvider = buttonAutoPeer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
invokeProvider.Invoke();
Related
I have a panel that contains a lot of buttons(right panel). I want to add a shortcut of selected button to another panel(left panel) with the same properties and events dynamically at runtime.
Buttons have so many properties like image, text, backcolor, forecolore, ... etc.
Also the buttons will open new form inside main panel:
private void butntest_Click(object sender, EventArgs e)
{
this.main_panel.Controls.Clear();
Form1 myForm = new Form1();
myForm.TopLevel = false;
myForm.AutoScroll = true;
this.main_panel.Controls.Add(myForm);
myForm.Show();
}
How Can i create a shortcut on left panel?
You can create a clone method which accepts a button as input and creates another button based on the input button's properties, also handle click event of the cloned button and just call PerformClick method of the input button:
public Button Clone(Button input)
{
var output = new Button();
output.Text = input.Text;
// do the same for other properties that you need to clone
output.Click += (s,e)=>input.PerformClick();
return output;
}
Then you can use it this way:
var btn = Clone(button1);
panel1.Controls.Add(btn);
Also instead of a panel, it's better to use a FlowLayoutPanel or TableLayoutPanel, so you don't need to handle the location and the layout yourself.
Note: If it's a dynamic UI and users can reorder command buttons or create whatever you called shortcut, the probably for the next step you may need to store the status of the panel to be able to reload buttons at the next load of the application after the application closed. In this case it's better to consider a pattern like command pattern. Then you can have your commands as classes. The then you can say which button is responsible to run which command at run-time and you can simply store the relation between buttons and commands using their names.
Create class Button like so
Button leftpannelbutton = new Button();
leftpannelbutton = button1.Clone();
Now leftpannelbutton is eqaul to button1. Now just add that to your form.
Find Below ( Reflection)
public static class ControlExtensions
{
public static T Clone<T>(this T controlToClone)
where T : Control
{
PropertyInfo[] controlProperties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
T instance = Activator.CreateInstance<T>();
foreach (PropertyInfo propInfo in controlProperties)
{
if (propInfo.CanWrite)
{
if(propInfo.Name != "WindowTarget")
propInfo.SetValue(instance, propInfo.GetValue(controlToClone, null), null);
}
}
return instance;
}
}
I know about the FindControl BUT my button is inside a Login control which is inside a LoginView control,below is my code but its not working!!
Login log = LoginView1.FindControl("Login1") as Login;
Button logButton = log.FindControl("LoginButton") as Button;
this.Form.DefaultButton = logButton.UniqueID;
Th error I get is
Object reference not set to an instance of an object.
FindControl only looks at the immediate children. You'd need to recursively navigate all the children, the children's children, etc., to find the control you're looking for.
public Control MyFindControl(Control parent, string controlIdToFind)
{
foreach(Control c in parent.Controls)
{
Control found = MyFindControl(c, controlIdToFind);
if (found != null)
{
return found;
}
}
// control not found.
return null;
}
Then change your code to:
Button logButton = (Button) MyFindControl(LoginView1, "LoginButton");
if (logButton != null)
{
this.Form.DefaultButton = logButton.UniqueID;
}
I have tons of Buttons named like this x0y1
How do I access the variable name dynamically so I could loop all names by xiy1 or so.
in PHP it would be like ${"myString" . $randomvar}
I can't use a list or array because the the button already exist defined through the xaml
You can use:
var textbox =
this.Controls.OfType<TextBox>().Where(txb => txb.Name == "myString").FirstOrDefault();
This assumes you are in the context of your form (this.Controls).
And of course, don't forget to add using System.Linq;...
You can get all the textbox using this method
void AllTextBox(System.Windows.Forms.Control.ControlCollection ctrls)
{
foreach (Control ctrl in ctrls)
{
if (ctrl is TextBox)
{
if (ctrl.Name == "textBox1")
{
// do your stuf with textbox
}
}
}
}
You can create function that return control by name :
Control GetControlByName(string Name)
{
foreach(Control control in this.Controls)
if(c.Name == Name) return control ;
return null;
}
or Function with a specific control like that :
Button GetButtonByName(string Name)
{
foreach (Control c in this.Controls.OfType<Button>())
if (c.Name == Name) return c;
return null;
}
For wpf project...
Let's say you have a grid named MyGrid and there's lot of buttons on it.
You want to refer to the button named x0y1:
var btn = MyGrid.Children.OfType<Button>().Where(x=>x.Name=="x0y1");
Note: above code should work for flat structure (one level deep only).
You can achieve the same by using code provided in this thread: How can I find WPF controls by name or type?
Just call FindName("elementName"). FindName searches through all child elements of a FrameworkElement. To access any button by its name as string in a window, call the FindName() method of the window !
If your code is in a class inheriting from Window, just use:
Button button = (Button)FindName("xiy1");
If you write the code in a class not inheriting from Window but FrameworkElement, which is unlikely, use:
Window window = Window.GetWindow(this);
Button button = (Button)window.FindName("xiy1");
Check the MSDN documentation about Namescopes for more information about limitations.
I am developing an application which consists of 2 forms, parent and child.
In parent form I have a frame. If button 1 of parent form is clicked then child form will open inside the frame. Now what I need is when button 2 of child form is clicked then it should call the Button2_click of the parent form.
Here is my parent form code:
public void MethodToExecute() //call this method
{
UPCCharges.Update();
if (HttpContext.Current.Session["CCost"] != null)
{
TxtCCost.Text = Session["CCost"].ToString();
}
DivCCharges.Visible = false;
IFMCCharge.Visible = false;
}
and this is Form 2 code:
protected void dgCFrom_ItemCommand(Object source, DataGridCommandEventArgs e)
{
UPCFromGrid.Update();
for (int vLoop2 = 0; vLoop2 < gvInner1.Items.Count; vLoop2++)
{
if (TxtTotalCFrom1 != null && TxtTotalCFrom2 != null)
{
TextBox TxtTotalCFrom = (TextBox)dgCFrom.Items[vLoop].FindControl("TxtTotalCFrom");
TextBox TxtTotalCYeild = (TextBox)dgCFrom.Items[vLoop].FindControl("TxtTotalCYeild");
Session["CCost"] = (mobjGenlib.ConvertDecimal(TxtTotalCFrom1.Text) + mobjGenlib.ConvertDecimal(TxtTotalCFrom2.Text)).ToString();
Session["CYeild"] = (mobjGenlib.ConvertDecimal(TxtRecoveryOrigin.Text) - mobjGenlib.ConvertDecimal(TxtTotalCFrom.Text)).ToString();
Session["CName"] = dgCFrom.Items[vLoop].Cells[1].Text;
Session["CJobID"] = HBLGeneralID;
}
}
}
FrmMasterSimulationChartNewUF frm = new FrmMasterSimulationChartNewUF();
frm.MethodToExecute();
}
The error I am getting is:
When keeping break point in the main form function MethodtoExecute getting as Object reference not set to null. But from form1 if execute it was working with no error.
Can anyone please help me solve this?
You should reference to master page
so add something like this line to your Contetnt page design:
<%# MasterType VirtualPath="~/Site.master" %>
and try something like this:
var master = Master as SiteMaster;
SiteMaster mm = new SiteMaster();
mm.MethodToExecute();
master.MethodToExecute();
Let me know the feedback.
Assuming here your "child" form is actually inside an iframe of the "parent" Form, and that both of these pages, are hosted on the same application and domain.
You can attach a javascript click event to Button2 of the child form to then invoke the click event of Button2 on the parent form using parent.document
E.g.
<button id="Button2" onclick="parent.document.getElementById('Button2').click();return false;">Child button 2</button>
Just beware of the actual ID values of your buttons , as they maybe changed due to UpdatePanels etc.
I'm trying to get all controls in a winform disabled at the Load event.
I have a form (MDI) which loads a Login Form. I want to disable the controls behind the Login Form to only let the user enter his username and password, and then if the user is valid re-enable the controls again.
Just show the login form as a modal dialog, i.e., frm.ShowDialog( ).
Or, if you really want to disable each control, use the Form's Controls collection:
void ChangeEnabled( bool enabled )
{
foreach ( Control c in this.Controls )
{
c.Enabled = enabled;
}
}
I suggest doing it this way instead of simply setting the Form's Enabled propery because if you disable the form itself you also disable the tool bar buttons. If that is ok with you then just set the form to disabled:
this.Enabled = false;
However, if you are going to do this you may as well just show the login prompt as a modal dialog :)
Simple Lambda Solution
form.Controls.Cast<Control>()
.ToList()
.ForEach(x=>x.Enabled = false);
Container like Panel control that contains other controls
then I used queue and recursive function get all controls.
for (Control control in GetAllControls(this.Controls))
{
control.Enabled = false;
}
public List<Control> GetAllControls(Control.ControlCollection containerControls, params Control[] excludeControlList)
{
List<Control> controlList = new List<Control>();
Queue<Control.ControlCollection> queue = new Queue<Control.ControlCollection>();
queue.Enqueue(containerControls);
while (queue.Count > 0)
{
Control.ControlCollection controls = queue.Dequeue();
if (controls == null || controls.Count == 0)
continue;
foreach (Control control in controls)
{
if (excludeControlList != null)
{
if (excludeControlList.SingleOrDefault(expControl => (control == expControl)) != null)
continue;
}
controlList.Add(control);
queue.Enqueue(control.Controls);
}
}
return controlList;
}
Just for some fun with linq, because you can.....
What you could do is create a "BatchExecute" extension method for IEnumerable and update all your controls in 1 hit.
public static class BatchExecuteExtension
{
public static void BatchExecute<T>(this IEnumerable<T> list, Action<T> action)
{
foreach (T obj in list)
{
action(obj);
}
}
}
Then in your code....
this.Controls.Cast<Control>().BatchExecute( c => c.enabled = false);
Cool.
I agree that ShowDialog is the way to go, but to answer the original question, you can do this if you want to disable all controls:
foreach (Control c in this.Controls)
{
c.Enabled = false;
}
As Ed said, showing the form as a modal dialog will do what you want. Be sure to check the dialog result returned from ShowDialog in case they cancel it instead of clicking login.
But if you really want to disable all the controls on the form then you should be able to just disable the form itself, or some other parent control like a panel that has all controls in it. That will disable all child controls. This will also allow the child controls to go back to their previous state when the parent control is enabled again.
Trying the ShowDialog show this exception:
Form that is not a top-level form cannot be displayed as a modal dialog box. Remove the form from any parent form before calling showDialog.
What im doing is this:
private void frmControlPanel_Load(object sender, EventArgs e)
{
WindowState = FormWindowState.Maximized;
ShowLogin();
//User = "GutierrezDev"; // Get user name.
//tssObject02.Text = User;
}
private void ShowLogin()
{
Login = new frmLogin
{
MdiParent = this,
Text = "Login",
MaximizeBox = false,
MinimizeBox = false,
FormBorderStyle = FormBorderStyle.FixedDialog,
StartPosition = FormStartPosition.CenterScreen
};
Login.ShowDialog();
}