Can't access control state in tabcontrol pages ! C# - c#

I have an issue in my project where I have to use "n" number of Usercontrols with tabcontrol's in them.
I am creating txt files with the name and state of all the controls present in the Usercontrols.
The problem is that I can't seem to access the state of the tabcontrol and all the controls in it.
I use this command that works for all the other controls appart from the tabcontrol one...
Any help would be well appreciated.
sw = new StreamWriter(filename.txt);
foreach (Control crl in theformname.Controls)
{
TabPage tab = new TabPage();
if (crl.GetType() == tab.GetType())
{
sw.WriteLine ("tabcontrol accessed");
if (Ctrl.GetType() == cbx.GetType())
{
CheckBox CheckBoxCrt;
CheckBoxCrt = (CheckBox)Ctrl;
sw.WriteLine(CheckBoxCrt.Checked.ToString()); //State of the checkbox
}
}
}

The following would need one layer above TabControl for your UserControl which would be done by mimicking TabControlList or CheckBoxList
Example
public static List<UserControlType> MyUserControlList(this Control control)
=> control.Descendants<UserControlType>().ToList();
Here are the current methods for use in the next code block.
public static class GenericExtensions
{
public static IEnumerable<T> Descendants<T>(this Control control) where T : class
{
foreach (Control child in control.Controls)
{
if (child is T thisControl)
{
yield return (T)thisControl;
}
if (child.HasChildren)
{
foreach (T descendant in Descendants<T>(child))
{
yield return descendant;
}
}
}
}
public static List<TabControl> TabControlList(this Control control)
=> control.Descendants<TabControl>().ToList();
public static List<CheckBox> CheckBoxList(this Control control)
=> control.Descendants<CheckBox>().ToList();
}
Usage (remember you need to add a list above the TabControl check) using a StringBuilder which can be used to write wherever you want e.g. filename.txt.
StringBuilder builder = new StringBuilder();
var tabs = this.TabControlList();
foreach (TabControl tab in tabs)
{
builder.AppendLine(tab.Name);
foreach (CheckBox box in tab.CheckBoxList())
{
builder.AppendLine($"\t{box.Parent.Name,-20}{box.Name, -20}{box.Checked}");
}
}
Debug.WriteLine(builder);

Related

Adding a control to the main container of unknown object

void Visualize(object CoreObj, object ParentControl)
{
if(CoreObj is typeA)
{
object control1 = new MyControl1(CoreObj);
ParentControl.FirstChild.Children.Add(control1);
foreach (object obj in CoreObj.Children)
{
Visualize(obj, control1);
}
}
else if (CoreObj is typeB)
{
object control2 = new MyControl2(CoreObj);
ParentControl.FirstChild.Children.Add(control2);
foreach (object obj in CoreObj.Children)
{
Visualize(obj, control2);
}
}
}
Where FirstChild is always container, no matter StackPanel, Grid or Canvas, or whatever.
How I get the first child, and the harder part, how to do Children.Add() on object?
I can require something else in case "Children" is inherited from somewhere in all wpf containers, but I can't find out which ancestor/interface contains "Children". Or I can use Reflection probably..
How to do this?
Here's what I came with, finally
interface IContain
{
Panel GetMain(); //return main container
}
// ...
void Visualize(object CoreObj, Panel ParentControl)
{
UIElement control = new UIElement();
if (CoreObj is File) { control = new NameSpacer(); } //new NameSpacer(obj);
else if (CoreObj is Namespace) { control = new NameSpacer(); }
else if(CoreObj is Using) { control = new NameSpacer(); }
if (control.GetType() == typeof(UIElement)) return;
ParentControl.Children.Add(control);
FieldInfo finf = CoreObj.GetType().GetField("Children"); if (finf == null) return;
var val = finf.GetValue(CoreObj); if (val.GetType() != typeof(IEnumerable<object>)) return;
if (control is IContain == false) return;
Panel container = ((IContain)control).GetMain();
foreach (object o in val as IEnumerable<object>)
{
Visualize(o, container);
}
}
You can use VisualTreeHelper class to get the first child.
Children property is defined in abstract class Panel.
var firstChild = parentControl.Descendants().OfType<Panel>().First();
firstChild.Children.Add(control1);
The descendants method leverages VisualTreeHelper in order to get all descendants and you have to define it as extension method:
public static IEnumerable<DependencyObject> Descendants(this DependencyObject element)
{
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childrenCount; i++)
{
var visualChild = VisualTreeHelper.GetChild(element, i);
yield return visualChild;
foreach (var visualChildren in Descendants(visualChild))
{
yield return visualChildren;
}
}
}
StackPanel, Grid and Canvas, all derive from the Panel class. This is also the class that contains the Children property.
if you know your argument is a Panel, you also have access to Children.First() and Children.Add(..)

Control is an ambigious reference between System.Web.UI.Control and System.Windows.Forms.Control error for Textboxes

I want to clear textboxes values on button click, but When I write the below code, I get error as
Control is an ambigious reference between System.Web.UI.Control and System.Windows.Forms.Control.
Here is my code:-
public void CleartextBoxes(Control parent)
{
foreach (Control x in parent.Controls)
{
if ((x.GetType() == typeof(TextBox)))
{
((TextBox)(x)).Text = "";
}
if (x.HasControls())
{
CleartextBoxes(x);
}
}
}
I tried a link from here but it did not match my requirement. Please suggest any help
Apparently you have referenced the libraries System.Web.UI and System.Windows.Forms. Both the libraries have a class called Control. So you have to specify which library you want to use:
public void CleartextBoxes(System.Windows.Forms.Control parent)
{
foreach (System.Windows.Forms.Control x in parent.Controls)
{
if ((x.GetType() == typeof(TextBox)))
{
((TextBox)(x)).Text = "";
}
if (x.HasChildren)
{
CleartextBoxes(x);
}
}
}

give same property to all textbox controls

how to give same property to all textboxes present in the same form.
foreach (var textbox in this.Controls.OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
The above code works only if the textboxes are not in nested format.
In my project I have multiple tabpages in tabcontrol. so i cant implement the above code. but i can implement the below code:
foreach (TextBox textbox in this.Controls.OfType<TabControl>().SelectMany(tc => tc.Controls.OfType<TabPage>().SelectMany(page => page.Controls.OfType<TextBox>())))
{
textbox.ContextMenu = new ContextMenu();
}
foreach (var textbox in this.tabCarInsurance.Controls.OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
foreach (var textbox in this.tabHomeLoans.Controls.OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
foreach (var textbox in this.tabRetirement.Controls.OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
Here I am implementing for each tabControl. which still i dont like (because I have more tab pages to take care of). Is there anyway to reduce the above code.
I tried the below code: (not working)
foreach (var textbox in this.Controls.OfType<TabControl>().OfType<TextBox>())
{
textbox.ContextMenu = new ContextMenu();
}
I got the above code knowledge from my previous question.
Please Help
Thanks in Advance.
private void SetProperty(Control ctr)
{
foreach(Control control in ctr.Controls)
{
if (control is TextBox)
{
control.ContextMenu = new ContextMenu();
}
else
{
if (control.HasChildren)
{
SetProperty(control);
}
}
}
}
How about an extension method to do it, called from your tabcontrol container...
public static class ControlExtensions
{
public static void SetContextMenuOnChildTextBoxes(this Control control)
{
if (control is TextBox)
{
control.ContextMenu = new ContextMenu();
}
if (control.Controls != null)
{
foreach (Control controlChild in control.Controls)
{
controlChild.SetContextMenuOnChildTextBoxes();
}
}
}
}
This could be put in a common area of code so that it could be called from any parents that wanted this functionality.
Just use the recursion to go through all controls subcollections:
void SetControl(ContextMenu menu, Control control)
{
if (control is TextBox)
control.ContextMenu = menu;
else
{
foreach (Control c in control.Controls)
SetControl(menu, c);
}
}
It will find all the textboxes and set one and the same context menu to all of them.
You mal call it,say, from form's OnLoad event handler. While it's assumed that you have yourContextMenu defined for the form.
private void Form1_Load(object sender, EventArgs e)
{
SetControl(yourContextMenu, this);
}
Try:
private void CtxMenu(Control parent)
{
foreach (Control child in parent.Controls)
{
if (child is TextBox)
{
(child as TextBox).ContextMenu = new ContextMenu();
}
}

How to get TabPage on which a user control data type resides

I'm building a custom data type using the user control wrappper method. Within it I am adding the existing TinyMCE data type. The problem is that I need to find a way to dynamically get a hold of the current TabPage on which the data type resides so that I can add the TinyMCE buttons to the menu. This is what I have currently (the TabPage is hardcoded):
Using statements:
using umbraco.cms.businesslogic.datatype;
using umbraco.editorControls.tinyMCE3;
using umbraco.uicontrols;
OnInit method:
private TinyMCE _tinymce = null;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.ID = "crte";
DataTypeDefinition d = DataTypeDefinition.GetDataTypeDefinition(-87);
_tinymce = d.DataType.DataEditor as TinyMCE;
ConditionalRTEControls.Controls.Add(_tinymce);
TabView tabView = Page.FindControl("TabView1", true) as TabView;
TabPage tabPage = tabView.Controls[0] as TabPage;
tabPage.Menu.InsertSplitter();
tabPage.Menu.NewElement("div", "umbTinymceMenu_" + _tinymce.ClientID, "tinymceMenuBar", 0);
}
User control:
<asp:PlaceHolder ID="ConditionalRTEControls" runat="server" />
Note: Page.FindControl is using a custom extension method that recursively finds the control.
I'd love if there was a way to access the TabPage via the Umbraco API, but, after working on this for the past several hours, the only way I could get the tab was by traversing the parent controls until I came to the tab.
Code:
private TinyMCE _tinymce = null;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.ID = "crte";
DataTypeDefinition d = DataTypeDefinition.GetDataTypeDefinition(-87);
_tinymce = d.DataType.DataEditor as TinyMCE;
ConditionalRTEControls.Controls.Add(_tinymce);
}
protected void Page_Load(object sender, EventArgs e)
{
TabView tabView = Page.FindControl("TabView1", true) as TabView;
TabPage tabPage = GetCurrentTab(ConditionalRTEControls, tabView);
tabPage.Menu.NewElement("div", "umbTinymceMenu_" + _tinymce.ClientID, "tinymceMenuBar", 0);
}
private TabPage GetCurrentTab(Control control, TabView tabView)
{
return control.FindAncestor(c => tabView.Controls.Cast<Control>().Any(t => t.ID == c.ID)) as TabPage;
}
Extension Methods:
public static class Extensions
{
public static Control FindControl(this Page page, string id, bool recursive)
{
return ((Control)page).FindControl(id, recursive);
}
public static Control FindControl(this Control control, string id, bool recursive)
{
if (recursive)
{
if (control.ID == id)
return control;
foreach (Control ctl in control.Controls)
{
Control found = ctl.FindControl(id, recursive);
if (found != null)
return found;
}
return null;
}
else
{
return control.FindControl(id);
}
}
public static Control FindAncestor(this Control control, Func<Control, bool> predicate)
{
if (predicate(control))
return control;
if (control.Parent != null)
return control.Parent.FindAncestor(predicate);
return null;
}
}

How to set focus to a control with Caliburn.Micro MVVM

I have a form and I want to set the focus to a text box when certain user actions happen. I know the MVVM way of doing things is to bind to VM properties, however the TextBox does not have a property that will allow this to happen. What's the best way to set the focus from the VM?
I have created an IResult implementation that works quite well for achieving this. You can get the view from the ActionExecutionContext of the IResult, which you can then search (I search by name) for the control you want to focus.
public class GiveFocusByName : ResultBase
{
public GiveFocusByName(string controlToFocus)
{
_controlToFocus = controlToFocus;
}
private string _controlToFocus;
public override void Execute(ActionExecutionContext context)
{
var view = context.View as UserControl;
// add support for further controls here
List<Control> editableControls =
view.GetChildrenByType<Control>(c => c is CheckBox ||
c is TextBox ||
c is Button);
var control = editableControls.SingleOrDefault(c =>
c.Name == _controlToFocus);
if (control != null)
control.Dispatcher.BeginInvoke(() =>
{
control.Focus();
var textBox = control as TextBox;
if (textBox != null)
textBox.Select(textBox.Text.Length, 0);
});
RaiseCompletedEvent();
}
}
I have ommitted some extra code to get the view from the context when the view is a ChildWindow I can provide if you require.
Also GetChildrenByType is an extension method, here is one of many implementations available in the wild:
public static List<T> GetChildrenByType<T>(this UIElement element,
Func<T, bool> condition) where T : UIElement
{
List<T> results = new List<T>();
GetChildrenByType<T>(element, condition, results);
return results;
}
private static void GetChildrenByType<T>(UIElement element,
Func<T, bool> condition, List<T> results) where T : UIElement
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
UIElement child = VisualTreeHelper.GetChild(element, i) as UIElement;
if (child != null)
{
T t = child as T;
if (t != null)
{
if (condition == null)
results.Add(t);
else if (condition(t))
results.Add(t);
}
GetChildrenByType<T>(child, condition, results);
}
}
}
Your action would then be something like the following (invoked in Caliburn.Micro ActionMessage style).
public IEnumerable<IResult> MyAction()
{
// do whatever
yield return new GiveFocusByName("NameOfControlToFocus");
}
There is an easier way.
1º In the ViewModel add property _view as your UserControl
2º You must override OnViewLoaded of your ViewModel and
set _view to View object.
3º Set focus from any method.
public UserControlView _view { get; set; }
protected override void OnViewLoaded(object view)
{
base.OnViewLoaded(view);
_view = (UserControlView)view;
}
public void SetFocus()
{
_view.TextBox1.Focus();
}
I hope help you.

Categories

Resources