Hallo,
ich empfehle dir einen Footer Bereich zu zeichnen und dort dein Ergebniss einzutragen.
Hierzu erstelle eine neue Klasse, leite von DataGridView ab und überschreibe das Event z.B. wie folgt.
protected override void OnRowPrePaint(DataGridViewRowPrePaintEventArgs e)
{
if (!e.IsLastVisibleRow)
{
base.OnRowPrePaint(e);
}
else
{
Rectangle rowBounds = new Rectangle(
this.RowHeadersWidth, e.RowBounds.Top,
this.Columns.GetColumnsWidth(
DataGridViewElementStates.Visible) -
this.HorizontalScrollingOffset + 1,
e.RowBounds.Height);
// Paint the custom selection background.
using (Brush backbrush = new System.Drawing.Drawing2D.LinearGradientBrush(rowBounds,
this.DefaultCellStyle.SelectionBackColor,
e.InheritedRowStyle.ForeColor,
System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal))
{
e.Graphics.FillRectangle(backbrush, rowBounds);
e.Graphics.DrawString("Das Ergebniss", this.Font, new SolidBrush(Color.Red), rowBounds.Location);
}
e.Handled = true;
}
}
Natürlich fehlen noch ein ein paar feinheiten aber dieser Weg wäre der einfachste. Um das Ergebniss zu ermitteln wirst du natürlich noch mit ForEach durch alle Rows durchgehen müssen.
Du kannst natürlich auch das RowPrePaint abonnomieren.
Evtl. hilft dir dieser Link weiter:
http://www.codeproject.com/KB/cs/OSDwindow.aspx
Ich habe es leider nicht direkt Testen können aber wenn:
Sollte folgendes nicht ausreichen (siehe Code)
ExStyle = User32.WS_EX_TOPMOST | User32.WS_EX_TOOLWINDOW | User32.WS_EX_LAYERED | User32.WS_EX_NOACTIVATE | User32.WS_EX_TRANSPARENT;
Dann kannst du versuchen das Handel des Spiels über GetActiveWindow (Win API) zu holen und es zu übermalen indem du dein Control dann darüber zeichnest 😃
Hallo,
habe es selber leider noch nicht ausprobiert und ob die Lösung die Optimalste ist kann ich dir leider auch nicht sagen.
Aber du könntest versuchen via Windows API BitBlt einen bestimmten Bereich via Screen Copy zu beeinflussen.
Dafür wirst du folgende API Funktionen benötigen:
**
GetActiveWindow
GetDesktopWindow
GetWindowRect
GetDC
CreateCompatibleDC
SelectObject
BitBlt
ReleaseDC
DeleteDC**
Mehr dazu unter www.pinvoke.net
** 1.) Lösungsansatz:**
Man könnte dem Teilabschnitt im Fremden Fenster den man Transparent zeichnen möchte, wie ein Bild behandeln. Man holt sich quasi von der aktuellen Position des Fensters die darunterliegende Fläche als Bild. Dieses Bild gestaltet man leicht Transparent und malt es in die gewünschte Position des fremden Fensters. Es sollte dabei zu keinen Flackereffekten kommen, allerdings solltest du beim bewegen des fremden Fensters das Bild immer aktualisieren.
** 2.) Lösungsansatz (schwer):**
Hierzu ließ dir als erstes in Ruhe den Artikel über Custom Borders durch.
Der Gedanke dabei wäre es über NativeWindow oder SetWindowLong die Windows Nachrichten der Zeichenroutine für den Hintergrund des fremden Fensters abzufangen. An der Stelle an der die Transparente Fläche sein sollte lässt du den normalen Zeichenvorgang weg und benutzt eine transparente Zeichenroutine. Dabei kann es zu Flackereffekten kommen.
Hierzu wirst du evtl. folgende Windows Nachrichten abfangen müssen:
WM_NCPAINT
WM_NCCALCSIZE // evtl. für die NonClient Größe
WM_PRINTCLIENT
WM_NCPAINT wirst du evtl. brauchen da es sein kann das dieser Bereich Schwarz oder Weiß gemalt wird und diesen erstmal allgemein transparent ersetzten musst. WM_NCCALCSIZE kann sein das diese Nachricht nicht benötigst, denke dabei nur an die Ermittlung der NonClient Area Größe.
WM_PRINTCLIENT wirst du benötigen um die Zeichenroutine selbst in die Hand zu nehmen, so das an der gewünschten Position transparent gemalt wird.
Denk also dran, WM_PRINTCLIENT alleine wird nicht ausreichen da sonst dein Transparenter Bereich evtl Schwarz oder weiß gemalt wird.
Du wirst da etwas rumprobieren müssen, es sei jemand findet einen besseren Ansatz.
Viel Glück 😃
Hier mal ein Beispiel Button für Ansatz2:
using System.Windows.Forms;
using System.Security.Permissions;
using System.Drawing;
using System;
namespace DynamicControlsExample
{
public class SpecialButton : Button
{
//protected override CreateParams CreateParams
//{
// [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
// get
// {
// CreateParams createParams = new CreateParams();
// createParams.ClassName = NativeMethods.TOOLBARCLASSNAME;
// createParams.ExStyle = 0x20;
// createParams.Style = NativeMethods.WS_CHILD | NativeMethods.WS_VISIBLE | NativeMethods.WS_CLIPCHILDREN | NativeMethods.WS_CLIPSIBLINGS;
// createParams.Style = NativeMethods.CCS_NODIVIDER | NativeMethods.CCS_NORESIZE | NativeMethods.CCS_NOPARENTALIGN;
// createParams.Style |= NativeMethods.TBSTYLE_TOOLTIPS | NativeMethods.TBSTYLE_FLAT | NativeMethods.TBSTYLE_TRANSPARENT;
// createParams.Style = NativeMethods.TBSTYLE_TRANSPARENT;
// createParams.Style |= NativeMethods.TBSTYLE_LIST;
// return createParams;
// }
//}
public SpecialButton()
{
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case (int)NativeMethods.WM.NCPAINT:
return;
case (int)NativeMethods.WM.PAINT:
this.WmPaint(ref m);
return;
}
base.WndProc(ref m);
}
private void WmPaint(ref Message m)
{
IntPtr hWnd = m.HWnd;
Rectangle rWnd = new Rectangle();
if (NativeMethods.GetWindowRect(hWnd, ref rWnd) == 0)
return;
Rectangle rClip = new Rectangle(0, 0, rWnd.Width, rWnd.Height);
IntPtr hDC = NativeMethods.GetWindowDC(hWnd);
IntPtr hCDC = NativeMethods.CreateCompatibleDC(hDC);
IntPtr hBitmap = NativeMethods.CreateCompatibleBitmap(hDC, rClip.Width, rClip.Height);
NativeMethods.SelectObject(hCDC, hBitmap);
NativeMethods.BitBlt(hCDC, 0, 0, rClip.Width, rClip.Height, hDC, 0, 0, (uint)NativeMethods.TernaryRasterOperations.SRCCOPY);
using (Graphics g = Graphics.FromHdc(hCDC))
{
this.OnPaint(new PaintEventArgs(g, rClip));
}
NativeMethods.BitBlt(hDC, 0, 0, rClip.Width, rClip.Height, hCDC, 0, 0, (uint)NativeMethods.TernaryRasterOperations.SRCCOPY);
NativeMethods.DeleteObject(hBitmap);
NativeMethods.DeleteDC(hCDC);
NativeMethods.ReleaseDC(hWnd, hDC);
}
protected override void OnPaint(PaintEventArgs pevent)
{
pevent.Graphics.DrawString(base.Text, base.Font, new SolidBrush(base.ForeColor), pevent.ClipRectangle.X, 0);
//base.OnPaint(pevent);
}
}
}
/PS
Native = Win32 Aufrufe, siehe dazu www.pinvoke.net
Nach etwas herum probieren habe ich eine Lösung gefunden.
Allerdings mich dagegen entschieden diese vorerst zu realisieren da der Aufwand enorm ist.
Man kann von der Command Bar das Handle besorgen und muss die WindowsNachrichten abfangen. Dann schiebt man dieser wiederum Controls unter, diese CustomControls müssen wiederum bei CreateParams überschrieben werden und deren Styles werden zum Beispiel (je nach Control) wie folgt gesetzt:
protected override CreateParams CreateParams
{
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
get
{
CreateParams createParams = base.CreateParams;
createParams.ClassName = NativeMethods.TOOLBARCLASSNAME;
createParams.ExStyle = 0;
createParams.Style = NativeMethods.WS_CHILD | NativeMethods.WS_VISIBLE | NativeMethods.WS_CLIPCHILDREN | NativeMethods.WS_CLIPSIBLINGS;
createParams.Style |= NativeMethods.CCS_NODIVIDER | NativeMethods.CCS_NORESIZE | NativeMethods.CCS_NOPARENTALIGN;
createParams.Style |= NativeMethods.TBSTYLE_TOOLTIPS | NativeMethods.TBSTYLE_FLAT | NativeMethods.TBSTYLE_TRANSPARENT;
if (Style == CommandBarStyle.Menu)
{
createParams.Style |= NativeMethods.TBSTYLE_LIST;
}
return createParams;
}
}
Wichtig ist das man sich dann auch die Koordinaten merkt, sprich man nutzt die Technik eines Controls aber setzt dieses auf das CommandBar wie ein grafisches Object (allerdings mit den Annehmlichkeiten die einen das Control schon bietet).
Für den Button müsste man also eine neue Klasse erstellen und von Button ableiten, wiederum eine neue Klasse erstellen von ComboBox ableiten und eine Klasse erstellen in der man von z.B. UserControl ableitet. In den jeweiligen Klassen überschreibt man je nachdem CreateParams.
Um UserControl werden dann die ComboBox abgeleitet wie die von Button abgeleitete Kalsse eingebunden und das USerControl mit Funktionen versehen.
Wer nun AddIn Express nutzt muss versuchen eine Klasse zu erstellen und von AddinExpress.MSO.ADXCommandBarControl ableiten. Und wiederum beim erstellen des ComObjects versuchen das Microsoft.Core.ICommandControl interface anzubinden. Dann wiederum die location mit der des UserControls tauschen, das geht wenn man die CommandBar ranzieht. Entweder über die outlookApplication oder CommandBar direkt und via NativeWindow die WndProc überschreibt und hier alles mit dem UserControl tauscht…
Man sieht schon, das artet in viel Arbeit aus.
Ein anderer Ansatz wäre die CommandBar nachzubilden was wiederum sehr schwer wird, ein Ansatz liefert dieser Link - hier muss aber bei der CommandBar.Show Methode wiederum etwas nachgebessert werden über einen Hook.
Ein anderer Ansatz:
Eine andere Möglichkeit das Problem zu Lösen wäre ein UserControl zu erstellen dieses via SetWindowLong oder bei CreateParams zu bearbeiten das dieses seine Ränder wie Ansichten Elemente verliert und dieses auf die COmmandBAr zu implementieren. Das ganze wäre etwas weniger Zeitaufwändig, amcht die Sache den noch nicht leichter.
Früher einmal war es unbestimmt - es gab kein Anfang des Tages und kein Ende. Mal waren es nur 30 Stunden mal über ~100 Stunden und ab und an habe ich das Schlafen komplett aufgegeben.
Heute sind es genau 40 Stunden, nicht mehr und nicht weniger und ich bin verdammt froh darüber.
Rauche ebenso recht viel bzw. zu viel.
Trinken tue ich unter der Woche nichts und am Wochenende je nachdem.
Sport übe ich nur je nachdem aus, gibt Tage da Jogge ich sehr gerne oder spiele Volleyball und wiederum Phasen an denen ich nichts tue.
Hallo Community,
ich arbeite zurzeit an einem MS Outlook AddIn und benötige dazu einen Button Ähnlich dem Senden und Empfangen Button von MS Outlook.
Folgende Ansätze habe ich bisher verfolgt:
Nachbilden:
Ich habe zuerst vermutet das der Button aus zwei Grafischen Objekten besteht die über die Schnittstelle CommandBarPopup und CommandBarButton realisiert werden. Dazu habe ich dann anhand der Windowsnachrichten auf der CommandBar versucht via CommandBar.accHitTest die jeweiligen Controls ausfindig zu machen. Soweit hat das ganze auch gut geklappt. Das Problem besteht nun darin das ich die Selection von beiden CommandBarControl’s nicht hinbekomme. Ich dachte wenn ich jeweils auf CommandBarPopup.accSelect und CommandBarButton.accSelect aufrufe könnte ich beide gleichzeitig markieren. Die Schnittstelle CommandBarButton bietet mir die Eigenschaft CommandBarButton.State an. Welche es mir erlaubt den MsoButtonState.msoButtonMixed zu stellen. Hierbei wäre dann der Button zwar Selectiert aber CommandBarPopup bietet diese Eigenscahft nicht an und somit komme ich an dieser Stelle auch nicht weiter. Vielleicht gibt es ja eine der in der Schnittstelle bereitgestellen Methoden die das erlaubt – leider finde ich hierzu keine Dokumentationen wie auf der MSDN Seite, diese sind leer.
// Eigene native windows nachricht für die commandbar auf dem die CommandControl's gezeichnet werden
private void OnMouseMove(object sender, ADXCommandBarMultiBoxBar.CommandBarNativeMouseEventArgs e)
{
if (_ADXOlExplorerCommandBar.CommandBarObj is CommandBar)
{
CommandBar bar = _ADXOlExplorerCommandBar.CommandBarObj as CommandBar;
if (_AdvPop.ControlObj is CommandBarPopup && _AdvBtn.ControlObj is CommandBarButton)
{
CommandBarPopup Pop = _AdvPop.ControlObj as CommandBarPopup;
CommandBarButton Btn = _AdvBtn.ControlObj as CommandBarButton;
CommandBarControl contr = bar.accHitTest(e.MouseEvent.X, e.MouseEvent.Y) as CommandBarControl;
// Tag besitzt als string eine GUID, das object selber ist kein indiez
if (contr != null && (contr.Tag == Pop.Tag || contr.Tag == Btn.Tag))
{
if (!this.IsSelected)
{
this.IsSelected = true;
Pop.accSelect(1, Type.Missing); // selectieren
Btn.accSelect(1, Type.Missing); // selectieren
Btn.State = MsoButtonState.msoButtonMixed
}
}
else
this.IsSelected = false;
}
}
}
Nachbauen:
In einem andere versuch habe ich über die Schnittstelle CommandBarControl auf der Eigenschaft CommandBarControl.Control ein UserControl hinzugefügt. Das Ergebniss funktioniert zwar da ich nun einen VS Button verwenden kann und diese dem Senden und Empfangen Button nachbilde. Aber die Sache mit dem UI ist eher bescheidener Natur und sieht nicht wirklich toll aus.
Mir ist einfach nicht ganz klar ob der Senden und Empfangen Button etwas eigenes von MS ist oder ob es eine Schnittstelle gibt mit der ich diesen Button in die CommandBar nach meinen bedürfnissen einbinden kann.
Vielleicht hat ja jemand eine Idee wie man diesne Button nachbilden könnte.
Vielen Dank im Vorraus
Andi
Hallo Manuel,
danke dir erst einmal.
Leider ist mir der Fehler wegen der Farbe nicht aufgefallen dennoch lässt dieser sich umgehen.
Ändere hierzu die Farbe über den Designer anhand des UI Tool's (siehe Bild). Anschließend zerre etwas an der Größe des Fensters herum und schon wird sich das Layout gemerkt.
Ich habe diese Komponente noch nicht komplett sauber integriert, aber ich hoffe das es ca. den Weg aufzeigt wie man eigene Styles auf Controls anwenden kann. Hierzu gibt es im Forum noch andere interessante Ansätze 🙂
Hallo Manuel,
unter folgenden Link findest du die UtilitiesLib.
In dieser habe ich genau den Code dazu verwendet. Es dauert nur etwas ganz durchzusteigen.
(Getestet WinVista32 Bit und WinXP - für Vista64Bit einfach als Win32 debug erstellen)
Hallo Community,
hier ein kleines Codesnipped für Add-In Express ADXOlExplorerCommandBar.
Folgendes Problem soll damit behoben werden, ADXCommandBarControl's bieten zum Teil nur Events an wie z.B. beim ADXCommandBarButton nur der Klick oder beim ADXCommandBarPopup sogar gar keine Events an.
Um dieses Problem zu beheben, habe ich eine kleine Komponente geschrieben.
Evtl. kann diese noch jemand gebrauchen. Die Komponente kann auch beliebig dann noch durch hinzufügen bzw. abfangen der Windowsnachrichten erweitert werden.
Hiwneis:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using AddinExpress.MSO;
using Office;
using System.Windows.Forms;
using IApplication = Outlook.Application;
using IExplorer = Outlook.Explorer;
namespace CobraOlAddIn12
{
[ComVisible(false)]
[DesignTimeVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ToolboxBitmap(typeof(Button))]
[ToolboxItem(true)]
public class ADXOlExplorerCommandBarEvents : ADXBaseAppEvents, ISupportInitialize
{
#region Declarations
/// <summary>
///
/// </summary>
private class CommandBarNative : NativeWindow
{
#region Imports
[DllImport("User32.dll")]
private static extern IntPtr FindWindow(string strClassName, string strWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x202,
WM_MBUTTONDOWN = 0x207,
WM_MBUTTONUP = 0x208,
WM_RBUTTONDOWN = 0x204,
WM_RBUTTONUP = 0x205,
WM_MOUSEMOVE = 0x200,
WM_MOUSEWHEEL = 0x20A,
WM_MOUSEHWHEEL = 0x20E,
}
private static readonly IntPtr TRUE = new IntPtr(1);
private static readonly IntPtr FALSE = IntPtr.Zero;
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct WINDOWINFO
{
/// DWORD->unsigned int
public uint cbSize;
/// RECT->tagRECT
public Rectangle rcWindow;
/// RECT->tagRECT
public Rectangle rcClient;
/// DWORD->unsigned int
public uint dwStyle;
/// DWORD->unsigned int
public uint dwExStyle;
/// DWORD->unsigned int
public uint dwWindowStatus;
/// UINT->unsigned int
public uint cxWindowBorders;
/// UINT->unsigned int
public uint cyWindowBorders;
/// ATOM->WORD->unsigned short
public ushort atomWindowType;
/// WORD->unsigned short
public ushort wCreatorVersion;
}
#endregion
#region Declarations
public event EventHandler<CommandBarNativeMouseEventArgs> MouseUpEvent;
public event EventHandler<CommandBarNativeMouseEventArgs> MouseDownEvent;
public event EventHandler<CommandBarNativeMouseEventArgs> MouseMoveEvent;
#endregion
#region Properties
/// <summary>
///
/// </summary>
public ADXOlExplorerCommandBar CommandBar { get; private set; }
/// <summary>
///
/// </summary>
public IntPtr ObjHandle
{
get
{
if (this.CommandBar == null) return IntPtr.Zero;
CommandBar cmdBar = this.CommandBar.CommandBarObj as CommandBar;
if (cmdBar == null) return IntPtr.Zero;
IApplication app = cmdBar.Application as IApplication;
if (app == null) return IntPtr.Zero;
IExplorer ex = app.Application.ActiveExplorer() as IExplorer;
IntPtr hWnd = FindWindow("rctrl_renwnd32", ex.Caption);
IntPtr hDocktop = FindWindowEx(hWnd, IntPtr.Zero, "MsoCommandBarDock", "MsoDockTop");
IntPtr hCmdBar = FindWindowEx(hDocktop, IntPtr.Zero, "MsoCommandBar", cmdBar.Name);
return hCmdBar;
}
}
#endregion
#region Constructors
/// <summary>
///
/// </summary>
/// <param name="cmdBar"></param>
public CommandBarNative(ADXOlExplorerCommandBar cmdBar)
{
this.CommandBar = cmdBar;
}
#endregion
#region Methods
/// <summary>
///
/// </summary>
/// <param name="m"></param>
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case (int)MouseMessages.WM_MBUTTONDOWN:
case (int)MouseMessages.WM_RBUTTONDOWN:
case (int)MouseMessages.WM_LBUTTONDOWN:
{
this.WmMBDown(ref m);
if (m.Result == TRUE) return;
break;
}
case (int)MouseMessages.WM_MBUTTONUP:
case (int)MouseMessages.WM_RBUTTONUP:
case (int)MouseMessages.WM_LBUTTONUP:
{
this.WmMBUp(ref m);
if (m.Result == TRUE) return;
break;
}
case (int)MouseMessages.WM_MOUSEMOVE:
{
this.WmMBMove(ref m);
if (m.Result == TRUE) return;
break;
}
}
base.WndProc(ref m);
}
/// <summary>
///
/// </summary>
/// <param name="m"></param>
private void WmMBMove(ref Message m)
{
CommandBarNativeMouseEventArgs args = new CommandBarNativeMouseEventArgs();
args.MouseEvent = this.CreateMouseEventArgs(m.LParam, m.Msg);
if (this.MouseMoveEvent != null)
this.MouseMoveEvent.Invoke(this, args);
}
/// <summary>
///
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
private MouseButtons GetMouseButton(int msg)
{
switch (msg)
{
case (int)MouseMessages.WM_LBUTTONUP:
case (int)MouseMessages.WM_LBUTTONDOWN:
return MouseButtons.Left;
case (int)MouseMessages.WM_MBUTTONUP:
case (int)MouseMessages.WM_MBUTTONDOWN:
return MouseButtons.Middle;
case (int)MouseMessages.WM_RBUTTONUP:
case (int)MouseMessages.WM_RBUTTONDOWN:
return MouseButtons.Right;
}
return MouseButtons.None;
}
/// <summary>
///
/// </summary>
/// <param name="m"></param>
private void WmMBDown(ref Message m)
{
CommandBarNativeMouseEventArgs args = new CommandBarNativeMouseEventArgs();
args.MouseEvent = this.CreateMouseEventArgs(m.LParam, m.Msg);
if (this.MouseDownEvent != null)
this.MouseDownEvent.Invoke(this, args);
m.Result = (args.Cancel) ? TRUE : FALSE;
}
/// <summary>
///
/// </summary>
/// <param name="m"></param>
private void WmMBUp(ref Message m)
{
CommandBarNativeMouseEventArgs args = new CommandBarNativeMouseEventArgs();
args.MouseEvent = this.CreateMouseEventArgs(m.LParam, m.Msg);
if (this.MouseUpEvent != null)
this.MouseUpEvent.Invoke(this, args);
m.Result = (args.Cancel) ? TRUE : FALSE;
}
/// <summary>
///
/// </summary>
/// <param name="lParam"></param>
/// <param name="m"></param>
/// <returns></returns>
private MouseEventArgs CreateMouseEventArgs(IntPtr lParam, int m)
{
Point pt = new Point(lParam.ToInt32());
Point pt2 = this.PointToCmd(pt);
return new MouseEventArgs(this.GetMouseButton(m), 0,
pt2.X, pt2.Y, 0);
}
/// <summary>
///
/// </summary>
/// <param name="screenPoint"></param>
/// <returns></returns>
private Point PointToCmd(Point screenPoint)
{
WINDOWINFO windowInfo = new WINDOWINFO();
GetWindowInfo(base.Handle, ref windowInfo);
return new Point(windowInfo.rcClient.Location.X + screenPoint.X, windowInfo.rcClient.Location.Y + screenPoint.Y);
}
#endregion
}
/// <summary>
///
/// </summary>
private class CommandBarNativeMouseEventArgs : CancelEventArgs
{
public MouseEventArgs MouseEvent { get; set; }
}
#endregion
#region Properties
/// <summary>
///
/// </summary>
private Dictionary<ADXOlExplorerCommandBar, CommandBarNative> CommandBars { get; set; }
/// <summary>
///
/// </summary>
public override string ClassName
{
get
{
this.Bind();
return this.GetType().ToString();
}
}
#endregion
#region Events
[Category("Explorer")]
[Description("Occurs before command bars events from the active explorer.")]
public event EventHandler<CommandBarControlMouseEventArgs> MouseDown;
[Category("Explorer")]
[Description("Occurs before command bars events from the active explorer.")]
public event EventHandler<CommandBarControlMouseEventArgs> MouseUp;
[Category("Explorer")]
[Description("Occurs before command bars events from the active explorer.")]
public event EventHandler<CommandBarControlMouseEventArgs> MouseMove;
#endregion
#region Constructors
/// <summary>
///
/// </summary>
public ADXOlExplorerCommandBarEvents()
: base()
{
this.CommandBars = new Dictionary<ADXOlExplorerCommandBar, CommandBarNative>();
}
/// <summary>
///
/// </summary>
/// <param name="container"></param>
public ADXOlExplorerCommandBarEvents(IContainer container)
: base(container)
{
this.CommandBars = new Dictionary<ADXOlExplorerCommandBar, CommandBarNative>();
container.Add(this);
}
#endregion
#region Methods
/// <summary>
///
/// </summary>
public void Bind()
{
foreach (ADXOlExplorerCommandBar bar in CommandBars.Keys)
{
CommandBars[bar].ReleaseHandle();
CommandBars[bar].AssignHandle(CommandBars[bar].ObjHandle);
}
}
/// <summary>
///
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
// release handles (stop wndproc/hook)
foreach (ADXOlExplorerCommandBar bar in CommandBars.Keys)
CommandBars[bar].ReleaseHandle();
base.Dispose(disposing);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMouseUpEvent(object sender, CommandBarNativeMouseEventArgs e)
{
if (sender is CommandBarNative)
{
CommandBarNative native = sender as CommandBarNative;
foreach (ADXCommandBarControl cmdCtr in native.CommandBar.Controls)
{
CommandBarControl control = cmdCtr.ControlObj as CommandBarControl;
if (control.accHitTest(e.MouseEvent.X, e.MouseEvent.Y) != null)
{
CommandBarControlMouseEventArgs ctrEvnt = new CommandBarControlMouseEventArgs(
e.Cancel,
e.MouseEvent.Button,
e.MouseEvent.Location);
if (this.MouseUp != null) this.MouseUp(cmdCtr, ctrEvnt);
e.Cancel = ctrEvnt.Cancel;
}
}
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMouseDownEvent(object sender, CommandBarNativeMouseEventArgs e)
{
if (sender is CommandBarNative)
{
CommandBarNative native = sender as CommandBarNative;
foreach (ADXCommandBarControl cmdCtr in native.CommandBar.Controls)
{
CommandBarControl control = cmdCtr.ControlObj as CommandBarControl;
if (control.accHitTest(e.MouseEvent.X, e.MouseEvent.Y) != null)
{
CommandBarControlMouseEventArgs ctrEvnt = new CommandBarControlMouseEventArgs(
e.Cancel,
e.MouseEvent.Button,
e.MouseEvent.Location);
if (this.MouseDown != null) this.MouseDown(cmdCtr, ctrEvnt);
e.Cancel = ctrEvnt.Cancel;
}
}
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMouseMoveEvent(object sender, ADXOlExplorerCommandBarEvents.CommandBarNativeMouseEventArgs e)
{
if (sender is CommandBarNative)
{
CommandBarNative native = sender as CommandBarNative;
foreach (ADXCommandBarControl cmdCtr in native.CommandBar.Controls)
{
CommandBarControl control = cmdCtr.ControlObj as CommandBarControl;
if (control.accHitTest(e.MouseEvent.X, e.MouseEvent.Y) != null)
{
CommandBarControlMouseEventArgs ctrEvnt = new CommandBarControlMouseEventArgs(
e.Cancel,
e.MouseEvent.Button,
e.MouseEvent.Location);
if (this.MouseMove != null) this.MouseMove(cmdCtr, ctrEvnt);
e.Cancel = ctrEvnt.Cancel;
}
}
}
}
/// <summary>
///
/// </summary>
public void BeginInit() { }
/// <summary>
///
/// </summary>
public void EndInit()
{
foreach (IComponent component in base.Container.Components)
{
if (component is ADXOlExplorerCommandBar)
{
ADXOlExplorerCommandBar bar = component as ADXOlExplorerCommandBar;
CommandBarNative native = new CommandBarNative(bar);
native.MouseDownEvent += new EventHandler<CommandBarNativeMouseEventArgs>(this.OnMouseDownEvent);
native.MouseUpEvent += new EventHandler<CommandBarNativeMouseEventArgs>(this.OnMouseUpEvent);
native.MouseMoveEvent += new EventHandler<CommandBarNativeMouseEventArgs>(this.OnMouseMoveEvent);
CommandBars.Add(bar, native);
}
}
}
#endregion
}
public class CommandBarControlMouseEventArgs : CancelEventArgs
{
#region Properties
/// <summary>
// Summary:
/// Gets which mouse button was pressed.
///
/// Returns:
/// One of the System.Windows.Forms.MouseButtons values.
/// </summary>
public MouseButtons Button { get; private set; }
/// <summary>
/// Summary:
/// Gets the location of the mouse during the generating mouse event.
///
/// Returns:
/// A System.Drawing.Point containing the x- and y- coordinate of the mouse,
/// in pixels.
/// </summary>
public Point Location { get; private set; }
/// <summary>
// Summary:
/// Gets the x-coordinate of the mouse during the generating mouse event.
///
/// Returns:
/// The x-coordinate of the mouse, in pixels.
/// </summary>
public int X { get; private set; }
/// <summary>
/// Summary:
/// Gets the y-coordinate of the mouse during the generating mouse event.
///
/// Returns:
/// The y-coordinate of the mouse, in pixels.
/// </summary>
public int Y { get; private set; }
#endregion
#region Constructors
/// <summary>
///
/// </summary>
/// <param name="cancel"></param>
public CommandBarControlMouseEventArgs(bool cancel, MouseButtons btn, Point location)
{
this.Cancel = cancel;
this.Button = btn;
this.Location = location;
this.X = location.X;
this.Y = location.Y;
}
#endregion
}
}
Hinweis:
Das snipped kann noch verschönert werden, aber ist im derzeitigen Zustand Funktionsfähig. Man kann den Weg den ich gegangen bin auch verwenden und ein Control ADXCommandPopup (Custom) zu erstellen und z.B. auch Bilder zusätzlich vom Menüpunkt hinzuzufügen - was standardmäßig ja nicht geht. Hierzu einfach den Weg über WindowsNative gehen ähnlich wie bei diesem Snipped.
Anwendungsbeispiel:
Clickevent für z.B. ADXCommandBarPopup mit verhindern des aufklappen der
Menüleiste.
Erst nach Dialogabfrage == true wird dann ein aufklappen der Menüleiste möglich.
/Ps
Habe es nicht unter Snipped gestellt da es eher um Office Anwendungen geht. Falls es doch an der falschen Stelle sein sollte, entschuldige ich mich jetzt schon mal dafür.
Viel Spaß damit!
Ich vermute mal du hast die Windows Vista 64 Bit Version - genau nachgelesen habe ich es auch nie, aber ich glaube bei Win32 wird expliziet die Kernel32.dll von Windows 32 Bit verwendet die vermutlich auch bei Windwos Vista 64 Bit vorliegt.
Hrm, fürchte da musst einfach mal im Internet recherchieren.
Man kann es aber auch noch anders Lösen: Link. Nur dann geht es eben nur auf den Windows 64 Bit Versionen.
Kannst das Projekt statt als "AnyCPU" mal als "WIN32" debuggen, evtl geht es dann.
Hrm, alternativ kann man auch Beginn und EndPaint verwenden allerdings nur in verbindung mit der Windows API und überschreiben der WM_PAINT um diese dann wieder auf das OnPaint des Controls zu linken.
Unter dem Artikel: [Artikel] Custom Window Border für Form's](http://www.mycsharp.de/wbb2/thread.php?threadid=27473) habe ich auch noch eine Lösung gegen Flackereffekte geschrieben, diese würde ebenso funktionieren. Sobald CreateParams und somit auch der WindowsStyle sich ändert, kommt es manchmal zu Problem beim Zeichnen.
Hrm, wie setzt du deine Forms so das sie als Owner das CRM (Haupt / MDIParent ) Form haben? - Das ist entscheidend für das Verhallten auch der der Dialoge.
Machst du das via IWin32Form oder per Win API über SetParent?
Hat das CRM Programm einen Formulardesigner (sowas wie list and Labels)?
Benutzt das CRM Programm DevExpress und du auch?
Du könntest dir global eine Zählervariable merken die du pro Tick um eines erhöhst und somit diese als Indexer verwenden.
Z.b wie folgt:
private int _Picker = 0;
private void Timer_TICK(....)
{
this.webbrowser.Navigate(LIST[_Picker++]);
if(_Picker == LIST.Count -1)
{
// beende Timer
_Timer.Stop();
// reset picker
_Picker = 0;
}
}
Gibt aber auch noch andere Wege.
Ebenso etwas verspätet aber besser als gar nie - alles gute zum ähm, Forumgebrutstag 🙂
Hrm, was hast den genau vor?
Soll die Sprache über die Installationsroutine getriggert werden?
normal reicht es wenn man alles in die Resourcen auslagert, egal ob *.dll (Plugin) oder *.Exe Datei. Die jeweiligen Resourcen werden dann in die verschiedenen Sprachen übersetzt. Hierfür eignet sich zum Beispiel das kostenpflichtige Programm
PASSOLO.
Über Installschild kann man dann die Resourcen ersetzten lassen indem man bei der Installationsroutine eine Sprachauswahl einbindet. Oder noch besser, man überlässt die Art von Drecksarbeit einem Tool wie z.B. dem FinalBuilder.
Denk dran, bei Forms kannst Localizeable = True einstellen und der PASSOLO Mensch kann diese resourcen auch ändern.
Rate dir bzw. deiner Firma eh zu diesen beiden Tools, den ohne automatischen Buildprozess und geschickter Übersetzung verschwendet man dafür viel zu viel Zeit.
Soll die Sprache dynamisch zur Laufzeit geändert werden können?
Hierzu einfach wieder den Weg über die Resourcen gehen und diese einfach über ein Interface validieren lassen, das ganze sähe dann wie es kleines_eichhoernchen vorgeschlagen hat aus.
@Malcom
Da du nicht mit MDI-Parent / MDI-Children arbeitest ist es mir nicht genau verständlich was du mit MainForm und anderen Fenstern genau meinst. Beinhaltet dein Hauptformular über MainForm.Controls.Add(Form1) ein Formular usw?
Ich denke am besten wäre ein kleines Bild wie man sich das ganze vorzustellen hat.
Irgendwie habe ich das befürchtet - daher wäre das eleganteste wohl ein Invalidate() auf das USerControl oder die Form aufzurufen wenn sich der MDIRoot ändert, im Prinzip amchst du das ja schon.
Der Fehler liegt aber nicht bei dir, hatte da auch mal was dunkel in Erinnerung das es beim Maximieren, Minimieren und vergrößern von MDIContainer schwierigkeiten bei der WM_PAINT Windowsnachricht gab. Leider weis ich nicht mehr wie ich das gelöst habe, irgendwas elegantes viel mir da schon ein.Vielleicht erinnere ich mich wieder nach ner Flasche Rum 🙂
Ansonsten, bleib mal bei deiner Lösung, die klingt nichtmal so schlecht in diesem Fall.
Hallo Xx tja xX,
eine Sache habe ich nicht ganz verstanden, der boolische Wert der als Übergabeparameter an deine Emthode "RUN" gesendet wird ist mir nicht ganz klar. Ich vermute mal, das bei "true" die entsprechende *.DLL (Plugin) dann laden soll. Und beziehe daher auch den Lösungsansatz auf diese Vermutung:
Ein Weg wäre es die Informationen als Serialisierte Klasse zur verfügung zu stellen und wie folgt würde das ganze aussehen:
Zuerst erstellst du eine Klasse namens Serializer<T> diese generische Klasse dient als Standardserializer und ist eine reine Hilfsklasse. Innerhalb dieser Klasse erstellst du ein Proeprtie namens Path vom typ string, dann erstellst du zwei statsiche Methoden die wie folgt aussehen könnten:
static internal void Save(string fileName, T obj)
{
this.FileName = fileName;
try
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (TextWriter writer = new StreamWriter(fileName))
{
serializer.Serialize(writer, obj);
writer.Flush();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.Fail("Fehler beim Speichern der " + fileName + ex.Message);
throw;
}
}
static internal T Load(string fileName)
{
try
{
T obj = null;
using (TextReader reader = new StreamReader(fileName))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
obj = serializer.Deserialize(reader);
}
return obj;
}
catch (Exception ex)
{
System.Diagnostics.Debug.Fail("Fehler beim Laden der " + fileName + ex.Message);
}
return null;
}
Ebenso erstellst du noch zwei weitere public methoden, Load und Save, die ähnlich der Statischen Methoden aufgebaut sind, du musst legendlich den generischen typen dazu weglassen und auf this.GetType() umstellen.
Danach erstellst du eine Klasse Namens PluginInfo, diese besitzt als public Properties die entsprechenden Namen äquivalent zu den <NodeTags> deiner XML. Deine XML sollte folgende "wichtigen" Tags besitzen und somit deine Kalsse auch Properties:
string ClassName // klasse der Interfaceschnittstelle
string Location // Ort der Assembly (GAC/ABSOLUT)
string AssemblyName // Absoluter Pfad + <Assembly>.dll oder GAC
Der Klasse PluginInfo verpasst du dann das Attribut [Serializable()] diese erhällst du aus den Namespace von System.Xml.Serialization. und leitest PluginInfo von Serializer<T> ab, also PluginInfo : Serializer<PluginInfo>.
Im Anschluss erstellst du weiderum eine Klasse Namens AssemblyActivator, die wird als generischer Typ für das aktivierne von Assemblys verwendet und zeitgleich in das zu verwendende Interface gecastet. Du solltest grundsätzlich immer Factory für Plugins verwenden genauso wie Interfaces.
Diese stelle ich dir mal ganz rein, da es sonst zu komplex ist das niederzuschreiben:
public enum AssemblyLocation
{
Gac, // Gloabl Assembly Cache
AbsolutePath // Der Pfad ist in AssemblyName komplett angegeben
}
public class AssemblyActivator<T, I> : Helper.Serializer<T>
{
private AssemblyLocation _Location;
public AssemblyLocation Location
{
get
{
return _Location;
}
set
{
_Location = value;
}
}
private string _AssemblyName;
public string AssemblyName
{
get
{
return _AssemblyName;
}
set
{
_AssemblyName = value;
}
}
private string _ClassName;
public string ClassName
{
get
{
return _ClassName;
}
set
{
_ClassName = value;
}
}
internal I CreateObject()
{
Assembly a = null;
string AssemblyPath = (Location == AssemblyLocation.CobraModule) ?
Cobra.APUtil.APModules.ModuleManager.ProgramDirectory + @"Module\" + AssemblyName : AssemblyName;
try
{
if (Location != AssemblyLocation.Gac)
{
a = Assembly.LoadFrom(AssemblyPath);
}
else
{
a = Assembly.Load(AssemblyPath);
}
}
catch (FileNotFoundException e)
{
MessageBox.Show(e.Message);
return default(I);
}
Type ClassType;
try
{
ClassType = a.GetType(ClassName);
}
catch (Exception ex)
{
MessageBox.Show("Class " + ClassName + " not found in Assembly " + AssemblyName + " at " + AssemblyPath + "\r\n\r\n" + ex.Message);
return default(I);
}
if (ClassType == null)
{
MessageBox.Show("Class " + ClassName + " not found in Assembly " + AssemblyName + " at " + AssemblyPath);
return default(I);
}
return (I)Activator.CreateInstance(ClassType);
}
}
}
Deine Methode Run solltest du dann wie folgt erstellen:
public static PluginInfo RUN(string path, bool initalize){};
In der Methode Run rufst du den über den Parameter path nun über PluginInfo.Load(path die Plugininfo ab. Wenn der Parameter initalize = true ist dann holst du dir über den Assemblyactivator und anhand der PluginInfofiles (daher auch selber Namensraum der Porperties) über eine Schnittstelle die du noch erstellen musst (z.B. IPlugin) das Plugin ab und ladest es somit hinein. Der activator kann dann schon automatisch anhand der Konfiguration des XML Files festellen ob die assembly im global assemblycache zu suchen ist oder ob sie irgendwo anders liegt.
Als Rückgabewert gibst dann das PluginInfo zurück, somit kann jeder der von aussen auf deine RUN Methode drauf zugreift gleich die Assembly identifizieren.
Wenn den AssemblyActivator noch mit der PluginInfo Klasse verbindest wäre das noch schöner, das sähe ca. wie folgt aus:
PluginInfo : AssemblyActivator<Serializer<PluginInfo>>,IPlugin>
Damit könnte man dann zugleich in der IPluginInfo auch die Assembly von aussen her reinladen falls sie noch nicht geladen wurde.
Wenn das zu komplex sein sollte siehe Stichwörter:
System.Xml.Serialization.IXmlSerializable
Serialize
/PS
Einen kleinen gefallen Bitte - bennen den Titel des Beitrags noch um in z.B. "[Offen] XML Serialisieren / Assemblys Laden".
Ansonsten schönes Wochenende 🙂
Hrm, das kann leider viele Ursachen haben.
Ein paar Möglichkeiten die mir spontan einfallen:
OnPaint beim UserControl wird nicht angesprungen und die damit verbundene die Windows Nachricht WM_PAINT wird nicht an das UserControl gesendet wenn das MDIRoot sich vergrößert / verkleinert.
Die grafischen Objecte des UserControls richten sich an dem sichtbaren Bereich aus, was sehr wahrscheinlich ist da die Zeichenroutine sich automatisch der größe des sichtbaren Bereichs anpassen. Das passiert wenn man z.B. beim verändern der größe des Controls die Zeitleiste und deren Inhallte vergrößern / verkleinern will.
Die Form1 sendert WM_PAINT nicht an das UserControl weiter.
Ist das UserControl den von dir?
@ markus.bodlos
Das alles lässt sich schön mit UserControls statt dann Forms abbilden 🙂
Aber hatte ohend as Bild von Echo]6[ auch Probleme zu verstehen inwiefern dann ein MDIContainer da mit einspielt.
@Echo]6[
Für die umsetzung mit UserControls zum Abbild von markus.bodlos, folgende vorgehensweise:
Ich schreibe es mal mit SplitContainer statt TableLayout, da man eigentlich dem Benutezr die Möglichkeit geben sollte die Breite der Ansichten selbst zu bestimmen.
Erstelle einfach eine MainForm, diese MainForm ist "kein MDIContainer", daher IsMdiContainer = false. Als zweites hast du einen SplitContainer der Senkrecht ist und DockStyle = Fill.
In diesen SplitContainer hast du links die Menüs rechts ist dein Content Bereich.
In den Contentbereich machst du wieder einen SplitContainer rein, diese trennt waagerecht. Oben hast du das fixe UserControl unten das dynamische Usercontrol.
So, warum UserControls, deine UserControls sind deine "ChildForms", sprich für jedes Childform was du davor hattest hast du nun ein eigenes UserControl. Damit die UserControls im unteren Bereich dynamsich reingeladen werdne können schreibst du ein Interface das du in alle UserControls implementierst.
Das Interface könnte folgende Methoden:
enum ControlType
{
NONE= 0,
ControlA,
ControlB,
.....
}
Show(Control parent);
Hide()
ControlType
Warum show und Hide, ganz einfach, getätigte Einstellungen sollen nicht verloren gehen. Daher initalisierst du deine UserControls und behällst sie in einer Liste von deiner MainForm. Wenn nun ein menüpunkt links gedrückt wird, löst du auf deiner MainForm ein CklickEvent aus, im ClickEvent selber erhällst du wieder als sender das entsprechende Menü, wenn Menü X daher gedrückt lade den Type = ControlTypeA usw.
Das ganze geht sehr schnell zu programmieren, ca. 10-20 min.
Hallo Mighty Panther,
keine Angst hier wurde noch niemand gebissen wegen einer Frage 🙂
Das was du brauchst ist das Form.Load Event die du auf deinem MDIContainer (Hauptformular, in dem die MDIForms initialisiert werden).
Wie du das genau machst findest du in folgenden Link: [FAQ] Eigenen Event definieren / Information zu Events
Wenn du das Event in deinem MDIContaine abonomiert hast, einfach den menüpunkt auf <Menu>.Enabled = false stellen und das war es. Wenn das Formular wiederum geschlossen wird, das ist dass Closed Event des MDIForms, dann den Menüpunkt auf <Menu>.Enabled = true stellen um diesen wieder verfügbar zu machen.
/PS
Wenn es etwas gehobener sein darf, schau mal im Netz nach CommandPattern -> Actions / ActionPattern. Das ganze basiert ebenso auf Events aber beinhaltet einer absolut saubere Ausführung von Events die beim initalisieren eines MDIForms sich selbst abonomieren.
Wie gesagt, das Ding hab ich in knapp ner Minute erstellt - es ist simpel die Frage ist nur was man möchte. Sollen die Border der MDIControl aktiv sein, darf der Benutzer das MDIControlerform verschieben usw.
Das beste wäre wie gesagt, Echo]6[ malt nen Bild wie es genau auszusehen hat und was der Benutzer darf und was nicht, wie das verschieben.
Schaut, ich denke er will sowas:
@markus.bodlos
Pria Weg geht auch, das Problem dabei ist, dass das ChildForm (MDIForm) innerhalb der MainForm (ParentForm) verschoben werden kann vom Benutzer. Die Möglichkeit geht auch, wenn man dem Benutzer die Möglichkeit nimmt das ChildForm zu bewegen.
Das was der Threadersteller eigentlich möchte ist so ne Sache, eigentlich ist das ein Widget Thema, kein MDI. Ein MDI ist ein Container der es expleziet dem Benutzer erlaubt innerhalb des Containers schalten und walten zu können wie es ihm beliebt.
Man kann beide Vorschläge, also deinen und Pria's mixen. Oberhalb des MDIContainers kann man über WinAPI SetParent (evtl. muss man noch ein bisschen mehr tun) das fest platzierte ChildForm anbringen und dann wie gehabt bei den variablen MDIChilds diese im Container mit aufnehmen.
Das Problem an der Geschichte ist mehr das es zu viele Möglichkeiten gibt das ganze zu lösen. Die Frage ist daher eher was man genau möchte. Im Prinzip kann man das ganze auch mit UserControls lösen. Wie gesagt, am besten wäre es Echo]6[ malt nen Bild, hängt es an und sagt, genauso und nicht anders muss es aussehen.
Allerdings denke ich das dien Vorschlag wirklich ausreicht, wenn es einfach sein darf 🙂
Hrm, das ganze ist nicht so einfach und leider gibt es viele Lösungsmöglichkeiten:
Schau mal im Forum was du unter Windows Widget so findest, ansonsten kannst dir auch mal gerne die UtilitiesLib von mir ansehen – dort habe ich es zwar etwas komplizierter gemacht aber im Prinzip lässt sich das Vereinfachen:
Erstell eine neue Klasse und leite von Form ab, erstelle einen neue Propertie vom Typ System.Windows.Forms.DockStyle mit setter und getter. Erstelle dann ein Propertie vom Typ Control für das ParentMDIControl.
Überschreibe die WndProc(ref Message m), fange die Windowsnachricht Nachrichten WindowsMessages.WM_NCHITTEST ab. Gebe anhand der Positionierung des DockStyle die entsprechenden HitTest Werte zurück. Ergo, DockStyle.Bottom -> NCHITTEST für Klick auf den linken, links unten, rechts, rechts unten, rechts oben, links oben und unteren Rand = HITTEST.HTCLIENT während bei klick auf oberen Rand = HITTEST. HTTOP. Somit unterbindest du das verschieben des Fensters.
Fange dann die Windowsnachricht WM_CREATE ab, klinke dabei über SetParent anhand des ParentMDIControl.Handel das this.Handle ein.
Soo wenn nun den Designer öffnest und das ChildForm einbindest wird es zur Laufzeit in den Designer geladen. Der Vorteil, du kannst auf deinem MainForm direkt das ChildForm bearbeiten und irgendwelche Controls draufziehen.
Kannst dir auch mal das Widget Projekt in der UtilitiesLib von mir ansehen, dann erkennst evtl. den Weg den man verwenden kann. Ich nutze dabei nur ein Panel das ich etwas modifiziere so das es wieder ein Windows Form wird. Den schlussendlich sind alle Controls wieder als Form herstellbar, kannst also auch aus einer TreeList wieder ein Form machen.
Wenn der Weg zu komplex sein sollte, gibt es auch eine reine .NET Lösung (ist eher dann ein gebastel) oder Fremdanbieter Controls (die aber kosten).
Erstmals Danke für die Antwort, svenson.
Wie definierst du "konkreten Typ" und dessen Untauglichkeit für Plug-In Implementierung?
Ein konkreten Typ wäre z.B. eine Klasse statt eines Interfaces.
Ich denke er meinte das es gut wäre vieles über Schnittstellen also Interfaces und intern so viel wie Möglich über Factory abzubilden, damit unabhängig von Typen bleibst.
[Edit] Da war er selber schneller,)
Hrm, hatte nicht alles gelesen 😉
string a = String.Format("->{0,20}<-", "Hello");
string b = String.Format("->{0,-20}<-", "Hello");
Console.WriteLine(a);
Console.WriteLine(b);
-> Hello<-
->Hello <-
Hrm, mir ist bei der zweiten Zigarette erst aufgefallen, das ich zu komplex dran gegangen bin. Eigentlich reicht eine Komponente aus und die Helper für verschiedene Controls kann man sich auch spaaren, da die wichtigen Properties aller Controls eh schon public sind (eigentlich auch logisch...) und somit braucht man nur diese durch Serializer<T> (daher keine abstrakte Basisklasse mehr) zu serialisieren indem man an Serializer<T> das Control übergibt das serialisiert werden soll. Na ja 🙂
Ansonsten hast natürlich recht, mit Kanonen auf Spatzen zu schießen ist zu viel.
/PS
Aufnehmen in die UtilitisLib werd ich es wohl erst Ende September, derzeit ist das Wetter einfach zu gut, arbeite daher zurzeit auch nicht an der UtilitiesLib weiter. Aber ich denke das Projekt rennt sicher nicht davon 🙂
Ich glaube nicht das es nicht wusstest, sondern einfach nur vergessen hast reinzumachen - mir geht es auch öfters so 🙂
Habe mir ein paar kleine Gedanken in der Mittagspause dazu gemacht, hier mal etwas ausführlicher ausformuliert:
Man erstellt eine Komponente die man klassisch im Designer auf ein Form zieht, alle Controls erhallten nun ein Zusätzliches Attribut Namens BindXML.
Dafür erstellt eine Klasse XMLBindSource diese wird von Component, IExtenderProvider, ISupportInitialize abgeleitet. Als private Member besitzt diese Klasse ein Dictionary<Control, IXmlSerializable>. Anhand der Liste wird beim setzen der Eigenschaft [ProvideProperty("BindXML", typeof(Control))] ein Designersupport gesetzt via [EditorAttribute(typeof(EditorXMLDocument), typeof(UITypeEditor))].
Um nun den Support für bestimmte Controls z.B. das TreeView dafür zu aktivieren liefert man über die Schnittstelle IExtenderProvider.CanExtend(object extend) ein true für z.B. TreeView zurück.
Der zweite Teil besteht nun darin ein paar Hilfsklassen zu implementierne und somit auch die IExtenderProvider.CanExtend Controls zu fixieren, um beim Beispiel TreeView zu bleiben sähe das wie folgt aus.
Zuerst erstellt man eine abstracte Basisklasse abstract class Serializer<T> welche IXmlSerializable implementiert. Diese implementation bildet für die interne Dictionary<Control, IXmlSerializable> in der Klasse XMLBindSource das grundgerüst.
In der abstrakten Basisklasse Serializer<T> werden nun die folgenden Statischen Methoden angeboten.
static internal void Save(string fileName, T obj)
{
this.FileName = fileName;
try
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (TextWriter writer = new StreamWriter(fileName))
{
serializer.Serialize(writer, obj);
writer.Flush();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.Fail("Fehler beim Speichern der " + fileName + ex.Message);
throw;
}
}
static internal T Load(string fileName)
{
try
{
T obj = null;
using (TextReader reader = new StreamReader(fileName))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
obj = serializer.Deserialize(reader);
}
return obj;
}
catch (Exception ex)
{
System.Diagnostics.Debug.Fail("Fehler beim Laden der " + fileName + ex.Message);
}
return null;
}
Ebenso werden die protected Methoden object GetValue(object component) und SetValue(object component, object value) erstellt welche dann in den Hilfsklassen der einzelnen Controls zur verfügung gestellt.
Über reflection werden dann in diesen Methoden die jeweiligen Propertys der Controls an die in der XML vorhandenen Daten gebunden.
Dann erstellt man diejeweiligen Controlhilfsklassen, beim GridView wäre das z.B. die Klasse XMLTreeView die von der abstrakten Basisklasse Serializer<XMLTreeView> ableitet. Über den den zweiten public Konstruktor der XMLTreeView liefert man dann ein XmlDocument xmlDocument als parameter rein welches später für das erstellen einer Datenquelle wichtig ist.
Anhand des Designersupports in XMLBindSource über die Eigenschaft welche das Attribut [EditorAttribute(typeof(EditorXMLDocument), typeof(UITypeEditor))] beinhaltet erstellt man nun einen XMLDocument Designer bei dem man vom gewählten Control also hier dann GridView die Eigenschaften aller Properties ausließt via PropertyGrid und diese mit einen XMLTag verknüpft - das resultat wird dann eben als XMLDocument an den Seter zurückgeliefert und somit auch das object an die Datenquelle geknüpft.
Damit hätte man dann eine Komponente die man im VS Designer einfach auf das Formular zieht und jedes Control das eben supported wird erhällt dann eine Eigenschaft für das Serialisieren als XML Dokument und könnte dann sogar von aussen "zur Laufzeit" wenn sich das XML ändert (einfach nen FileWatcher bei ISupportInitialize mit initalisieren) ändern. Sähe sicherlich ziemlich gut aus.
/PS
Wenn nichts dagegen hast würde ich das Thema gerne in der UtilitiesLib mit aufnehmen, schreibe es natürlich selbst anhand des aufgeführten Textes.
Hallo JAck30lena,
du könntest das z.B. wie folgt lösen über ITypedList.
Hier ein Link zu einem Lösungsweg.
Wenn das ganze mit [Serializable()] verbindest könntest daraus über eine Factory was nettes erstellen, klasse wäre das als Komponente die man auf jedes Control draufzieht und somit das Databinding erweitert.
[Helper]
[Serializable()]
public class Serializer<T>
{
static public T LoadFromString(string xmlString)....
static public T Load(string fileName)....
public string SaveToString()...
public void Save(string fileName)
}
/PS
Man könnte sogar statt den DataBinding aufgrund der ITypedList das <TreeView>.DataSource verwenden und somit die Logik rein der XML überlassen.
Hrm, hast du danach auch <form2>.Show() aufgerufen?
Was heisst denn das? 😄
Leider ist das ein kleiner Tick von mir, und bezieht sich nun nicht auf eine Wissenschaftsstudie aus der Rubrik Human Resource Management. Wenn ich anfange etwas zu erzählen beginnt alles bei mir mit einem Sinnbildlichen grübeln, daher ein „Hrm“. Ähnlich verhält es sich bei mir mit gekachelten Flächen, Essensbesteck das bereits schon jemand benutzt hat usw. Das ganze geschieht eher unbewusst und ist natürlich gerade bei einer solchen Diskussion etwas auffällig.
Hrm, ich gehöre zu der beschriebenen jüngeren Generation und kann nicht bestätigen das ausschließlich alle in meinem Alter sich derartig ausdrücken. Persönlich benutze ich sowieso keine Abkürzungen im normalen Sprachgebrauch, geschweige dem in irgendwelchen Spielechat‘s und dergleichen -da es einfach nur verwirrend ist. Spezielle „Slang“ Begriffe beherrsche ich absolut nicht und darf mir diese zumeist erst einmal erklären lassen und werde dafür wie bei einer Bildungslücke nur belächelt (wobei auslachen es besser bezeichnet). Dabei gehöre ich zu den wenigen aktiven Leseratten in meinem Freundeskreis.
Bei Fachwörtern gerade hier im Forum sehe ich das ganze etwas anders, für die Stichwortsuche ist es einfach eleganter und einfacher im Forum sowohl wie im Internet nach den Begrifflichkeiten zu recherchieren.
FreePhysicalMemory, FreeSpaceInPagingFiles, FreeVirtualMemory, SizeStoredInPagingFiles, TotalSwapSpaceSize, TotalVisibleMemorySize, TotalVirtualMemorySize from Win32_OperatingSystem
Irgendeines davon 😮)
Phu, kannst dir das mal ansehen: Link
Nutze bei deiner GenericFactory Class im Beispiel beim MS die DisplayTypeInfo Klasse sowas wie ein public static void TryPhrase<T>(Type type) (ist nur ein Ansatz). Dann könnte es gehen 🙂
Hrhr, pass mal bei Windows Vista beim virtualisieren auf (UAC), da wird das ganze noch lustiger z.B. bei:"C:\Programme\Gemeinsame Dateien"
Versuch mal beim auslesen einfach:
string.Format(@"{0}", <pfadvariable>). Glaube das herbivore schon richtig liegt, die Fehlermeldung weist ziemlich stark darauf hin.
Muh.. wart schneller als ich den Fehler bemerkt habe 🙂
JuyJuka hats dann ja als Code ausgeschrieben.
Gelobe aber besserung mit den Lesen der Fragen.
Sorry, hatte nicht genau gelesen...
Wirst dir List<object> wohl nehemn müssen und mit is und as später filtern oder anhand der value der Liste den typen bestimmen müssen.
Kannst Svenson's Vorschlag versuchen:
EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)Marshal.BindToMoniker("VisualStudio.DTE.9.0"); // VS 2008 bei VS 2005 VisualStudio.DTE.8.0
dte.Debugger.CurrentThread = <der Thread>
Bei einem AddIn brauchst dir natürlich nicht die VS IDE via BindToMoniker zu holen, da bekommst es über das object application mit. Könnte sein das den prozess nochmal anfügen musst (ob eine zuweisung wie im Beispiel reicht weis ich nicht) das geht über Attach2("Managed").
Das spiel dauert immer solange "bis" Deutschland gewinnt 😮)
Mir fällt grad ein, Werbung von Media Markt. Sind ja nun
Hab mir vor 1 Jahr nen Falchbild gekauft
Na dann ab zum Mediamarkt und Geld einfordern sollten die Deutschen Tore schießen.
Hrm, dafür gibt es zwei Wege:
Die einfachste und wahrscheinlich auch nur das was du möchtest:
[TypeConverter(typeof(ExpandableObjectConverter))]
public sealed class TypeCode
{
usw...
Denke dran, dafür sollte typeCode bereits instanziert sein - Sonst passiert da nichts!
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public TypeCode TypeCode
{
get { return _typeCode; }
}
Verschönerte und "Coole" Variante:
Ein eigenes UI beim drücken auf das Property Grid aufploppen lassen:
System.Drawing.Design.UITypeEditor siehe dazu MSDN Beispiel (das ist echt gut).