I'm creating a custom C# control (form's title bar). One form can have only one title bar, and that's why i'm wondering something: When user (programmer) adds my title bar to his form, is there ANY way i can check if ParentForm already contains my title bar, and if so can i cancel adding another instance of my control?
I know how to perform check to see types of controls ParentForm contains, but what event is raised when my control is dropped from toolbox to form, and how to "cancel" layout of my control if necessary?
You should read in-depth about the designer technologies available in .NET, because these are not what I would call production-ready examples. However, this gives you a solid start and both code snippets do what you are asking.
For design time, you can override the designer site in your control and do the following:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Design;
using System.Diagnostics;
namespace WindowsFormsControlLibrary1 {
public partial class DebugControl : UserControl {
public DebugControl() {
InitializeComponent();
}
public override ISite Site
{
get
{
return base.Site;
}
set
{
base.Site = value;
IComponentChangeService service = (IComponentChangeService)GetService(typeof(IComponentChangeService));
service.ComponentAdding += (sender, e) => {
IDesignerHost host = (IDesignerHost)value.Container;
Component component = (Component)host.RootComponent;
if (component as Form != null)
{
Form form = (Form)component;
foreach (Control c in form.Controls)
{
if (c.GetType() == this.GetType())
{
throw new System.ArgumentException("You cannot add two of these controls to a form!");
}
}
}
};
}
}
}
}
For runtime in your form you can override OnControlAdded and do the following:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using WindowsFormsControlLibrary1;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void OnShown(EventArgs e)
{
Controls.Add(new DebugControl());
}
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (e.Control.GetType() == typeof(DebugControl))
{
int count = 0;
foreach (Control c in Controls)
{
if (c is DebugControl)
{
count++;
}
}
if (count > 1)
{
Controls.Remove(e.Control);
Debug.Assert(false, "Cannot add two of these controls!");
}
}
}
}
}
There are more than one way to do this, but these are rough examples, mind you. Read up on design-time support that the .NET framework, it is very rich and there are extensive documentation on it. Another method is to implement custom designers and implement CanBeParentedTo and CanParent, but mind you CanBeParentedTo is not called when your control is drug from the ToolBox to your form.
You may use Controls collection of the active form.
Handle the ParentChanged event, check the parent's Controls, and throw an exception if necessary.
Related
I am working on an app where the user has to discover places. I am using this to show areas with undiscovered places on a map:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/map/circle-map-overlay
But later while app grew in functionality, it no longer runs well. Here is the link to my github.
https://github.com/jakuboles/TDKInz2020/tree/master/TDK
After the user login TDK.Android.CustomMapRenderer.OnElementChanged function is called way faster before TDK.MainPage.xaml.cs.DisplayInMap where I set which places should be shown as discovered, and which as undiscovered. In result now app always on TDK.Android.CustomMapRenderer.OnElementChanged line 36 list of places always will have null and on calling OnMapReady to draw circles list is null.
Is there some way to call OnElementChanged once more when DisplayInMap will assign places to list? Or to make OnElementChanged run later, after DisplayInMap will set list.
Sorry if it's a complicated description; didn't know exactly how to properly describe.
Here's my Android renderer:
using Android.Content;
using Android.Gms.Maps.Model;
using Java.Lang;
using MapOverlay;
using MapOverlay.Droid;
using System.Collections.Generic;
using TDK.MapsCustoms;
using Xamarin.Forms;
using Xamarin.Forms.Maps.Android;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace MapOverlay.Droid
{
public class CustomMapRenderer : MapRenderer
{
List<CustomCircle> circles;
public CustomMapRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.Maps.Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
circles = formsMap.CircleList;
}
}
protected override void OnMapReady(Android.Gms.Maps.GoogleMap map)
{
base.OnMapReady(map);
foreach (var circle in circles)
{
var circleOptions = new CircleOptions();
circleOptions.InvokeCenter(new LatLng(circle.Position.Latitude, circle.Position.Longitude));
circleOptions.InvokeRadius(circle.Radius);
circleOptions.InvokeFillColor(0X66FF0000);
circleOptions.InvokeStrokeColor(0X66FF0000);
circleOptions.InvokeStrokeWidth(0);
NativeMap.AddCircle(circleOptions);
}
}
}
}
Move the line
circles = formsMap.CircleList;
from OnElementChanged to OnMapReady
working on a login method, using Mdi, and MVC. The Class structure is very elaborate, so constant references between classes is required. However, when I try to change the Main Menu view, I get the "object reference is required for non-static field, method or property".
I am still only an amateur, started 2 months ago and self-taught, so I am still fuzzy on what the error is actually referring to and what it means.
Here is the Menu View Class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DCIM_With_Test.User;
namespace DCIM_With_Test.Menu
{
public partial class Menu_View : Form
{
public static int btnUser;
public Menu_View()
{
InitializeComponent(); //runs the Main Menu form
User_Controller CreateLoginView = new User_Controller(); //opens the Show_Login method in the User_Controller
CreateLoginView.Show_Login(this); //sets the Mdi Parent container
}
public void SetMenuView()
{
switch (Db_Facade.ACCESS)
{
case 1:
plantAreaCodeToolStripMenuItem.Visible = true;
cableIDToolStripMenuItem.Visible = true;
logOutToolStripMenuItem.Visible = true;
createNewUserToolStripMenuItem.Visible = true;
editUserToolStripMenuItem.Visible = true;
break;
default:
plantAreaCodeToolStripMenuItem.Visible = false;
cableIDToolStripMenuItem.Visible = false;
logOutToolStripMenuItem.Visible = false;
createNewUserToolStripMenuItem.Visible = false;
editUserToolStripMenuItem.Visible = false;
break;
}
}
The User Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DCIM_With_Test.Menu;
namespace DCIM_With_Test.User
{
class User_Controller
{
public void Show_Login(Menu_View Main_Menu)
{
User_Login_View LoginView = new User_Login_View(); // Creates an object of the User_Login_View.
LoginView.MdiParent = Main_Menu; // Set the Parent Form of the Child window.
LoginView.Show(); // Display the new form.
}
public void Show_User(Menu_View Main_Menu)
{
User_Edit_View EditUserView = new User_Edit_View(); // Creates an objet of the User_View.
EditUserView.MdiParent = Main_Menu; // Set the Parent Form of the Child window.
EditUserView.Show(); // Display the new form.
}
public static void Compare_Login(User_Login_View Login_View)
{
User_Model getACCESS = new User_Model();
getACCESS.uName = Login_View.txtUsername.Text;
getACCESS.uPwd = Login_View.txtPassword.Text;
Db_Facade.ACCESS = 1;
if (Db_Facade.ACCESS > 0)
{
Login_View.Close();
}
else
{
Login_View.lblError.Visible = true;
}
Menu_View.SetMenuView(); //here is where the error occurs
}
}
}
The Db_Facade Class is currently just a collection of Variables, hence why ACCESS is set to 1 in the User_Controller
Your problem occurs because you don't have a reference to the Menu_View object inside your function, so it tries to reference the Menu_View class, which doesn't have any static members assigned. It looks like what you want to do is call Login_View.MdiParent.SetMenuView()
EDIT
You probably need to cast your call, as you are saving Main_Menu into LoginView.MdiParent which stores it as it's base class Form. Try: (Main_Menu)Login_View.MdiParent.SetMenuView()
If casting the object isn't possible, then what you can do is create a Property to access the object directly.
In your User_Login_View, create a new property public Menu_View Menu {get;set;}. Then, in your Show_Login function, add a line to set the Menu object LoginView Menu = Main_Menu;. Now, you can reference LoginView.Menu.SetMenuView(); without needing a cast.
I need to programitically add tabs to a Silver.UI toolbox after load, and after I add the tabs and call refresh, it still does not show them. But for some reason, when I put the code in load, it works! Here's my code:
//Load the objects into the desinger
DesignDeserializer deserializer = new DesignDeserializer();
deserializer.load();
public void createTab(string title)
{
ToolBoxTab tab = new ToolBoxTab(title, 1);
objectBox.AddTab(tab);
objectBox.RefreshTabs();
}
Here's my DesignDeserializer:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Silver.UI;
namespace EmuGUI
{
class DesignDeserializer : main
{
public void load()
{
//Send to create the tabs...
createTab("foo");
}
}
}
It does not give me any errors...
I want to do something a simple as loading a webpage. For some reason Awesomium is not updating properties such as IsLoading, or triggering events such as DocumentReady or LoadingFrameComplete and I have no idea why, can anyone help me out?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Awesomium.Core;
namespace DownloaderTest
{
class ParsingHelper
{
WebView wv;
public ParsingHelper(WebView web)
{
this.wv = web;
}
public void ParsingInitiation(string link)
{
wv.LoadingFrameComplete +=wv_LoadingFrameComplete;
wv.Source = new Uri(link);
}
void wv_LoadingFrameComplete(object sender, FrameEventArgs e)
{
if(e.IsMainFrame)
{
//BeginParsing
((WebView)sender).LoadingFrameComplete -= wv_LoadingFrameComplete;
}
}
}
class Teste
{
WebView MainWeb = WebCore.CreateWebView(1024,768);
public object[] ObtainInformation(int id)
{
ParsingHelper ph = new ParsingHelper(MainWeb);
ph.ParsingInitiation("http://www.google.com");
//More code
return new object[] {};
}
}
}
If I run something like...
Teste t = new Teste();
t.ObtainInformation(1);
wv_LoadingFrameComplete is never triggered and I have no idea why.
try this code to detect page loaded completely
loadingFrameCompete event + IsLoading property
private void Awesomium_Windows_Forms_WebControl_LoadingFrameComplete(object sender, Awesomium.Core.FrameEventArgs e)
{
if (!webControl1.IsLoading)
MessageBox.Show("Page Loaded Completely");
}
Answered here: http://answers.awesomium.com/questions/2260/awesomium-not-loading-page-or-triggering-any-event.html
You are either using Awesomium in non UI environment (not WPF/WinForms control) and must call WebCore.Update() implicitly or you just blocking the same thread so it can't fire events.
I'm trying to handle an event when elements are added into a diagram, however AddAdvice() throws an unhandled COM exception:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Visio = Microsoft.Office.Interop.Visio;
namespace VisioAddAdviceWinForms
{
public partial class Form1 : Form
{
private EventSink eventSink = null;
public Form1()
{
InitializeComponent();
this.eventSink = new EventSink();
unchecked
{
axDrawingControl1.Window.EventList.AddAdvise(((short)Visio.VisEventCodes.visEvtAdd + (short)Visio.VisEventCodes.visEvtShape), this.eventSink, "", "");
}
}
}
public class EventSink : Visio.IVisEventProc
{
object Visio.IVisEventProc.VisEventProc(
short eventCode,
object source,
int eventID,
int eventSeqNum,
object subject,
object moreInfo)
{
Visio.IVApplication app = null;
Visio.IVDocument doc = null;
Visio.IVShape shape;
try
{
if (source is Visio.IVApplication)
{
app = (Visio.Application)source;
}
else if (source is Visio.IVDocument)
{
doc = (Visio.Document)source;
}
switch (eventCode)
{
case unchecked((short)Visio.VisEventCodes.visEvtAdd) +
(short)Visio.VisEventCodes.visEvtShape:
shape = (Visio.Shape)subject;
MessageBox.Show("added");
break;
case (short)Visio.VisEventCodes.visEvtApp +
(short)Visio.VisEventCodes.visEvtNonePending:
MessageBox.Show("pending");
break;
case (short)Visio.VisEventCodes.visEvtDel + (short)
Visio.VisEventCodes.visEvtShape:
shape = (Visio.Shape)subject;
MessageBox.Show("deleted");
break;
default:
break;
}
}
catch (Exception err)
{
MessageBox.Show("Exception in IVisEventProc.VisEventProc: "
+ err.Message);
}
return null;
}
}
}
Not sure about the exception you're seeing with AddAdvise, but why not bypass AddAdvise and use the managed event wrappers provided by Visio's interop layer? Is there a reason to use AddAdvise instead of the Visio Primary Interop Assembly?
Can you simply add a handler for the ShapeAdded event directly on the control itself? Or, if not on the control, then certainly on the Visio.Document contained inside the control.
See also the sample code in this forum post:
http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/c80df85f-4e97-4f4c-8563-52cb40786b13/
And the answer to this other stackoverflow question:
C# - Is there any OnShapeMoved or OnShapeDeleted event in Visio?
Add this:
using System.Runtime.InteropServices;
And where you have this:
public class EventSink : Visio.IVisEventProc{
Put this:
[ComVisible(true)]
public class EventSink : Microsoft.Office.Interop.Visio.IVisEventProc{