Laden...

[Offen] Outlook Senden/Empfangen Button nachbilden

Erstellt von Andreas.May vor 14 Jahren Letzter Beitrag vor 14 Jahren 4.287 Views
Andreas.May Themenstarter:in
915 Beiträge seit 2006
vor 14 Jahren
[Offen] Outlook Senden/Empfangen Button nachbilden

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

Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(

Andreas.May Themenstarter:in
915 Beiträge seit 2006
vor 14 Jahren

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.

Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(

Andreas.May Themenstarter:in
915 Beiträge seit 2006
vor 14 Jahren

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

Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(

2.921 Beiträge seit 2005
vor 14 Jahren

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.