Prism AnimatedTabControl customization - wpf

I have a user interface like Prism StockTrader RI application with some changes whrere
i put control panel in ResearchRegion contains list of items when i select one item
its details are displayed in the AnimatedTabControl in the main region.
I need to customize the AnimatedTabControl (from StockTrader RI) like this:
The AnimatedTabControl show tab header like normal tab control where header
will contain the selected item name
When new selection is applied from a control panel that resides in the ResearchRegion a
new tab open w/o removing the previous tab selection and w/o animation
Tab header contain close button to close any of the open tabs when required
Animation take place only when changing the control panel in the ResearchRegion
public class AnimatedTabControl : TabControl
{
public static readonly RoutedEvent SelectionChangingEvent = EventManager.RegisterRoutedEvent(
"SelectionChanging", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof (AnimatedTabControl));
private DispatcherTimer timer;
public AnimatedTabControl()
{
DefaultStyleKey = typeof(AnimatedTabControl);
}
public event RoutedEventHandler SelectionChanging
{
add { AddHandler(SelectionChangingEvent, value); }
remove { RemoveHandler(SelectionChangingEvent, value); }
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
this.Dispatcher.BeginInvoke(
(Action)delegate
{
this.RaiseSelectionChangingEvent();
this.StopTimer();
this.timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 0, 500) };
EventHandler handler = null;
handler = (sender, args) =>
{
this.StopTimer();
base.OnSelectionChanged(e);
};
this.timer.Tick += handler;
this.timer.Start();
});
}
// This method raises the Tap event
private void RaiseSelectionChangingEvent()
{
var args = new RoutedEventArgs(SelectionChangingEvent);
RaiseEvent(args);
}
private void StopTimer()
{
if (this.timer != null)
{
this.timer.Stop();
this.timer = null;
}
}
}
Thanks in Advance

I have answered part#3 of your question(Tab header contain close button to close any of the open tabs when required).
Have a look at my public folder in SkyDrive Account:-
(https://skydrive.live.com/redir?resid=656548C49A72B6CD!105)

Related

WPF Cannot unsubscribe from a RoutedEvent, not working. After unsubscribing it continues firing

I have an WPF User control in which I create a RoutedEventHandler. I want to raise an event notifying every time its height changes:
Wpfusercontrol.designer.cs:
public partial class Wpfusercontrol: System.Windows.Controls.UserControl
{
public static readonly RoutedEvent HeightChangedEvent = EventManager.RegisterRoutedEvent(
"HeightChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Wpfusercontrol));
public event RoutedEventHandler HeightChanged
{
add { AddHandler(HeightChangedEvent, value); }
remove { RemoveHandler(HeightChangedEvent, value); }
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.HeightChanged && HeightChangedEvent != null)
{
RaiseEvent(new RoutedEventArgs(HeightChangedEvent));
}
}
}
Then this WPF user control is hosted in an ElementHost
WindowsFormsHostControl.Designer.cs:
partial class WindowsFormsHostControl
{
private void InitializeComponent()
{
this.ElementHostFormControl = new System.Windows.Forms.Integration.ElementHost();
this.Wpfusercontrol= new Wpfusercontrol();
this.SuspendLayout();
//
// ElementHostFormControl
//
this.ElementHostFormControl.Dock = System.Windows.Forms.DockStyle.Fill;
this.ElementHostFormControl.Location = new System.Drawing.Point(0, 0);
this.ElementHostFormControl.Margin = new System.Windows.Forms.Padding(2);
this.ElementHostFormControl.Name = "ElementHostFormControl";
this.ElementHostFormControl.Size = new System.Drawing.Size(75, 78);
this.ElementHostFormControl.TabIndex = 0;
this.ElementHostFormControl.Child = this.Wpfusercontrol;
//
// WindowsFormsHostControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.ElementHostFormControl);
this.Margin = new System.Windows.Forms.Padding(2);
this.Name = "WindowsFormsHostControl";
this.Size = new System.Drawing.Size(75, 78);
this.ResumeLayout(false);
}
private System.Windows.Forms.Integration.ElementHost ElementHostFormControl;
private Wpfusercontrol Wpfusercontrol;
}
WindowsFormsHostControl.cs:
public partial class WindowsFormsHostControl: System.Windows.Forms.UserControl
{
private RoutedEventHandler heightChangedEventHandler;
public WindowsFormsHostControl()
{
InitializeComponent();
}
public WindowsFormsHostControl(RoutedEventHandler heightChangedEventHandler) : this()
{
this.heightChangedEventHandler = heightChangedEventHandler;
this.Wpfusercontrol.HeightChanged += this.heightChangedEventHandler;
}
public void SubscribeHeightChanged()
{
this.Wpfusercontrol.HeightChanged += this.heightChangedEventHandler;
}
public void UnsubscribeHeightChanged()
{
this.Wpfusercontrol.HeightChanged -= this.heightChangedEventHandler;
}
}
This WindowsFormsHostControl is embedded within an UI object called custom task pane which is kind of UI container for VSTO Outlook Add-ins. This custom task pane has a button to resize its height but it does not provide an event to catch it. So when you resize the height of that custom task pane, the height of the wpf user control changes as well, so through the routed event in the wpf user control I know when the custom task pane is resized and I catch the event.
Now from one class in my VSTO Outlook Add-in application (which in fact is a winforms app), I perform below things:
private WindowsFormsHostControl windowsFormsHostControl = null;
this.windowsFormsHostControl = new WindowsFormsHostControl(this.WpfUserControl_HeightChanged);
System.Windows.Fomrs.Timer t;
private void WpfUserControl_HeightChanged(object sender, System.Windows.RoutedEventArgs e)
{
// Dome some stuff
...
t = new System.Windows.Fomrs.Timer();
t.Tick += new EventHandler(Update);
t.Interval = 100;
t.Enable = true;
}
private void Update(object sender, EventArgs e)
{
// Some more stuf....
....
// In below lines I update the height of the custom task pane (VSTO Outlook UI object) which in turn causes the WPF user control to resize its height as well. So then, I am trying to unsubscribe from the wpf routed event, then update the height for custom task pane, and finally subscribe again to the wpf routed event. I do this to prevent routed event in wpf user control fires again.
this.windowsFormsHostControl.UnsubscribeHeightChanged();
// here I update the height for custom task pane
this.windowsFormsHostControl.SubscribeHeightChanged();
}
The problem is that it looks like the line:
this.windowsFormsHostControl.UnsubscribeHeightChanged();
is not working because the routed event in the wpf user control continues raising each time I execute the line of code between UnsubscribeHeightChanged and SubscribeHeightChanged.
So what am i doing wrong?

change main form controls by trigger event inside canvas

I am currently working on a project that required me to use a canvas in order to draw rectangles around specific places in a picture (to mark places)
Each rectangle (actually "rectangle" since it is also a custom class that I created by inheriting from the Grid class and contain a rectangle object) contains properties and data about the marked place inside the picture.
my main form contains controls such as TextBox ,DropDownLists and etc.
Now what I am trying to do is that for each time I am clicking on the "rectangle" object the main form controls will be filled with the object data.
I do not have access to those controls from the canvas class.
this code is inside the costume canvas class to add the object into the canvas:
protected override void OnMouseLeftButtonDown( MouseButtonEventArgs e)
{
if(e.ClickCount==2)
{
testTi = new TiTest();
base.OnMouseLeftButtonDown(e);
startPoint = e.GetPosition(this);
testTi.MouseLeftButtonDown += testTi_MouseLeftButtonDown;
Canvas.SetLeft(testTi, e.GetPosition(this).X);
Canvas.SetTop(testTi, e.GetPosition(this).X);
this.Children.Add(testTi);
}
}
and by clicking an object that is placed inside the canvas i want to get the information.
for now just want to make sure i am getting the right object with a simple messagebox
void testTi_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show(sender.GetType().ToString());
}
this is my costume "Rectangle" class
class TiTest:Grid
{
private Label tiNameLabel;
private Rectangle tiRectangle;
private String SomeText = string.Empty;
private String version = "1.0";
private String application = "CRM";
private String CRID = "NNN";
public String SomeText1
{
get { return SomeText; }
set { SomeText = value; }
}
public Rectangle TiRectangle
{
get { return tiRectangle; }
set { tiRectangle = value; }
}
public Label TiNameLabel
{
get { return tiNameLabel; }
set { tiNameLabel = value; }
}
public TiTest()
{
this.SomeText = "Hello World!!";
this.TiNameLabel = new Label
{
Content = "Test Item",
VerticalAlignment = System.Windows.VerticalAlignment.Top,
HorizontalAlignment = System.Windows.HorizontalAlignment.Left
};
TiRectangle = new Rectangle
{
Stroke = Brushes.Red,
StrokeDashArray = new DoubleCollection() { 3 },//Brushes.LightBlue,
StrokeThickness = 2,
Cursor = Cursors.Hand,
Fill = new SolidColorBrush(Color.FromArgb(0, 0, 111, 0))
};
Background= Brushes.Aqua;
Opacity = 0.5;
this.Children.Add(this.tiNameLabel);
this.Children.Add(this.tiRectangle);
}
}
is there any way to access the main form controls from the costume canvas class or by the costume rectangle class?
Thanks in advance
You can have your main window be binded to a singletone ViewModel holding the properties of the rectangles.
ViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
#region Singletone
private static MainWindowViewModel _instance;
private MainWindowViewModel()
{
}
public static MainWindowViewModel Instance
{
get
{
if (_instance == null)
_instance = new MainWindowViewModel();
return _instance;
}
}
#endregion
#region Properties
private string _someInfo;
public string SomeInfo
{
get
{
return _someInfo;
}
set
{
if (_someInfo != value)
{
_someInfo = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("SomeInfo"));
}
}
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
In main window xaml
<TextBox Text="{Binding SomeInfo}"/>
Also set the view model as your main window data context (in main window constructor for exmaple)
this.DataContext = MainWindowViewModel.Instance;
Finally, from where you handle the click event of the rectangles (testTi_MouseLeftButtonDown), access the MainWindowViewModel instance and set it's properties accordingly.
MainWindowViewModel.Instance.SomeInfo = myRectangle.SomeInfo;
This will trigger the PropertyChanged event, which will update your control's on the main window.
If you are not familiar with the MVVM (Model, View. View Model) pattern you can read about it here
Hope this helps

Quickest way to hide an array of pictureboxes

I have an array of pictureboxes named from B11 (co-ords 1,1) to B55 (co-ords 5,5). I would like to hide these all on startup (and in the middle of running). I was thinking of making an array of the names manually but would it be the best solution?
If they all have a common parent control, such as a panel or groupbox (or even the form):
Parent.SuspendLayout()
For Each pbox As PictureBox in Parent.Controls.OfType(Of PictureBox)()
pbox.Visible = False
Next pbox
Parent.ResumeLayout()
The Suspend/Resume-Layout() is to avoid flickering as you modify a bunch of controls at once.
You could extend the PictureBox class and use event handling to accomplish this by:
Adding a public property to the form to tell if the picture boxes should be shown or hidden.
Adding an event to the form that is raised when the show/hide picture box property is changed.
Extending the PictureBox class so that it subscribes to the event of the parent form.
Setting the visible property of the extended PictureBox class to the show/hide property of the parent form.
When the show/hide flag is changed on the parent form all of the picture boxes will change their visibility property accordingly.
Form Code:
public partial class PictureBoxForm : Form {
public PictureBoxForm() {
InitializeComponent();
this.pictureBoxesAdd();
}
private void pictureBoxesAdd() {
MyPictureBox mp1 = new MyPictureBox();
mp1.Location = new Point(1, 1);
MyPictureBox mp2 = new MyPictureBox();
mp2.Location = new Point(200, 1);
this.Controls.Add(mp1);
this.Controls.Add(mp2);
}
public event EventHandler PictureBoxShowFlagChanged;
public bool PictureBoxShowFlag {
get { return this.pictureBoxShowFlag; }
set {
if (this.pictureBoxShowFlag != value) {
pictureBoxShowFlag = value;
if (this.PictureBoxShowFlagChanged != null) {
this.PictureBoxShowFlagChanged(this, new EventArgs());
}
}
}
}
private bool pictureBoxShowFlag = true;
private void cmdFlip_Click( object sender, EventArgs e ) {
this.PictureBoxShowFlag = !this.PictureBoxShowFlag;
}
}
Extended PictureBox Code:
public class MyPictureBox : PictureBox {
public MyPictureBox() : base() {
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.ParentChanged += new EventHandler(MyPictureBox_ParentChanged);
}
private void MyPictureBox_ParentChanged( object sender, EventArgs e ) {
try {
PictureBoxForm pbf = (PictureBoxForm)this.Parent;
this.Visible = pbf.PictureBoxShowFlag;
pbf.PictureBoxShowFlagChanged += new
EventHandler(pbf_PictureBoxShowFlagChanged);
} catch { }
}
private void pbf_PictureBoxShowFlagChanged( object sender, EventArgs e ) {
PictureBoxForm pbf = (PictureBoxForm)sender;
this.Visible = pbf.PictureBoxShowFlag;
}
}
...or just put 'em all on a Panel, and change the panel's visibility.

Devexpress PopupContainerEdit popup always open

Im'm using winform DevExpress library.
Now need to create a control, basing on PopupContainerEdit but this control must have some behaviors like when it's focused, the popup opens and when lost focus the popup closes.
This is the code I'm using but the popup dessapears after getting focus.
public class HelpEdit : PopupContainerEdit {
private PopupContainerControl _container;
private GridControl _gridControl;
private GridView _gridView;
[DefaultValue("")]
[DXCategory("Data")]
[AttributeProvider(typeof(IListSource))]
public object Datasource {
get { return _gridControl.DataSource; }
set { _gridControl.DataSource = value; }
}
public HelpEdit() : base() {
_container = new PopupContainerControl();
this.Properties.TextEditStyle = DevExpress.XtraEditors.Controls.TextEditStyles.Standard;
this._gridControl = new GridControl();
this._gridControl.Dock = DockStyle.Fill;
this._gridView = new GridView(_gridControl);
_container.Controls.Add(_gridControl);
_container.Size = new Size(this.Width, 250);
this.Properties.PopupControl = _container;
this.Properties.PopupControl.Size = new Size(this.Width, 250);
}
protected override void OnGotFocus(EventArgs e) {
base.OnGotFocus(e);
this.ShowPopup();
}
protected override void OnLostFocus(EventArgs e) {
base.OnLostFocus(e);
this.ClosePopup();
}
}
Your popup disappears because it closes by your code as soon as the popup container control(_container) got focus itself. You should not close popup within the OnLostFocus() override because the base.OnLostFocus method of PopupContainerEdit is already contains correct code for closing popup. Or close popup conditionally, using the following code:
protected override void OnLostFocus(EventArgs e) {
if(IsPopupOpen && !EditorContainsFocus)
ClosePopup(PopupCloseMode.Immediate);
base.OnLostFocus(e);
}

How do I provide designer support to a TabControl residing in a UserControl, so that I can drag/drop controls onto tab pages?

I have a user control, which contains both a Panel and a TabControl. I enabled design-time support for both. I can drag/drop controls from the toolbox onto the Panel control that resides within the user control. I can also add and remove tab pages via the designer on the TabControl. However, I am not able to drag/drop any controls onto the tab pages themselves.
Below is the code generated source code for my user control:
partial class TestUserControl
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
private void InitializeComponent()
{
this.tabControl = new System.Windows.Forms.TabControl();
this.contentPanel = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// tabControl
//
this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabControl.Location = new System.Drawing.Point(0, 0);
this.tabControl.Name = "tabControl";
this.tabControl.SelectedIndex = 0;
this.tabControl.Size = new System.Drawing.Size(306, 118);
this.tabControl.TabIndex = 0;
//
// contentPanel
//
this.contentPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
this.contentPanel.Location = new System.Drawing.Point(0, 118);
this.contentPanel.Name = "contentPanel";
this.contentPanel.Size = new System.Drawing.Size(306, 73);
this.contentPanel.TabIndex = 0;
//
// TestUserControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tabControl);
this.Controls.Add(this.contentPanel);
this.Name = "TestUserControl";
this.Size = new System.Drawing.Size(306, 191);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TabControl tabControl;
private System.Windows.Forms.Panel contentPanel;
}
Below is the source code I added to enable design-time support:
[Designer(typeof(TestUserControlDesigner))]
public partial class TestUserControl : UserControl
{
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public TabControl TabControl
{
get { return this.tabControl; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Panel ContentPanel
{
get { return this.contentPanel; }
}
public TestUserControl()
{
InitializeComponent();
}
}
internal class TestUserControlDesigner : ParentControlDesigner
{
public override void Initialize(System.ComponentModel.IComponent component)
{
base.Initialize(component);
EnableDesignMode(
(this.Control as TestUserControl).TabControl, "TabControl");
EnableDesignMode(
(this.Control as TestUserControl).ContentPanel, "ContentPanel");
}
}
What do I need to do, so that I can drag/drop controls onto the tab pages of the TabControl?
You have to enable design mode on the existing tab pages as well:
internal class TestUserControlDesigner : ParentControlDesigner {
public override void Initialize(System.ComponentModel.IComponent component) {
base.Initialize(component);
var ctl = (this.Control as TestUserControl).TabControl as TabControl;
EnableDesignMode(ctl, "TabControl");
foreach (TabPage page in ctl.TabPages) EnableDesignMode(page, page.Name);
EnableDesignMode((this.Control as TestUserControl).ContentPanel, "ContentPanel");
}
}

Resources