I have the following behavior which is unfinished. Please note that TransitionElement is basically a ContentControl.
I would like to create two storyboards that use BlurBitmapEffect to blur and unblur the control.
If the ContentControl Enabled property is set to false, I would like to add the storyboards and begin the blur.
If Enabled is set to true, I would like to run a storyboard that unblurs the control and once finished removes both storyboards, effectively removing any bitmap effects.
class ContentControlBehavior : Behavior<TransitionElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.IsEnabledChanged += AssociatedObject_IsEnabledChanged;
}
protected override void OnDetaching()
{
AssociatedObject.IsEnabledChanged -= AssociatedObject_IsEnabledChanged;
base.OnDetaching();
}
void AssociatedObject_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == false)
{
//Blur
}
else
{
//UnBlur and remove storyboards and any bitmap effects.
}
}
}
I am doing this when I lock and unlock my application.
I found doing it through XAML with styles had a huge impact on graphical performance. Then I found some notes below. So I figure why not apply these storyboards and then remove them altogther.
Be careful using WPF bitmap effects. At the time I'm writing this, WPF
bitmap effects are rendered in software mode. Any object that applies
an effect will also be rendered in software. Bitmap effects should not
be applied to large visuals. Also, animating properties of an effect
can degrade performance. At this time, I suggest that you use bitmap
effects sparingly and use them on relatively small visual UI objects
like buttons, text boxes, etc. Feel free to animate effects, but
again, I recommend relatively small, subtle animations.
I have just noticed that BitmapEffect is depreciated and Effect is the one to use.
here is a solution if you do not want to remove the storyboard at the end of unblur
assuming TransitionElement is a kind of FrameworkElement below is a sample.
class ContentControlBehavior : Behavior<TransitionElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.IsEnabledChanged += AssociatedObject_IsEnabledChanged;
// add effect to element
BlurEffect effect = new BlurEffect() { Radius = 0 };
AssociatedObject.Effect = effect;
}
protected override void OnDetaching()
{
AssociatedObject.IsEnabledChanged -= AssociatedObject_IsEnabledChanged;
base.OnDetaching();
//remove the effect
AssociatedObject.Effect = null;
}
void AssociatedObject_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == false)
{
//Blur
BlurEffect effect = AssociatedObject.Effect as BlurEffect;
effect.BeginAnimation(BlurEffect.RadiusProperty, new DoubleAnimation(10, TimeSpan.FromSeconds(0.5)));
}
else
{
//UnBlur
BlurEffect effect = AssociatedObject.Effect as BlurEffect;
effect.BeginAnimation(BlurEffect.RadiusProperty, new DoubleAnimation(0, TimeSpan.FromSeconds(0.25)));
}
}
}
in above example invoking BeginAnimation effectively removes any previous animation from the targeted property, however last one remain, but that is on the effect and will be removed as the behavior is Detached.
Related
I want to change the size of a control through animation, which looks like 3D Touch animation on iOS(not just ScaleAnimation, I want to change the length and width of it separately), and then attach the animation to the control.
I have tried to search for documents of Microsoft.Toolkit.Uwp.UI.Animations namespace but find nothing.
I have tried to search for documents of Microsoft.Toolkit.Uwp.UI.Animations namespace but find nothing.
Microsoft.Toolkit contains AnimationExtensions Scale method could be used to scale element, you could refer to document here.
You could also use a natural motion composition animation on a uielement. For more detail please refer to xaml controls gallery app.
For Example
Compositor _compositor = Window.Current.Compositor;
SpringVector3NaturalMotionAnimation _springAnimation;
private void CreateOrUpdateSpringAnimation(float finalValue)
{
if (_springAnimation == null)
{
_springAnimation = _compositor.CreateSpringVector3Animation();
_springAnimation.Target = "Scale";
}
_springAnimation.FinalValue = new Vector3(finalValue);
}
private void element_PointerEntered(object sender, PointerRoutedEventArgs e)
{
// Scale up to 1.5
CreateOrUpdateSpringAnimation(1.5f);
(sender as UIElement).StartAnimation(_springAnimation);
}
private void element_PointerExited(object sender, PointerRoutedEventArgs e)
{
// Scale back down to 1.0
CreateOrUpdateSpringAnimation(1.0f);
(sender as UIElement).StartAnimation(_springAnimation);
}
I am writing a custom drawn TabControl class in C#.
My InitializeComponent method (which is called by the constructor) behaves like so, in order to custom draw the control:
private void InitializeComponent()
{
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.UpdateStyles();
this.DrawMode = TabDrawMode.OwnerDrawFixed;
}
The TabControl uses two rectangle surfaces;
The ClientRectangle which contains the entire control
The DisplayRectangle which is the portion of the control to display TabPage content
As I want to adjust the DisplayRectangle, I have overridden its property (which is get only):
public override Rectangle DisplayRectangle
{
get
{
return this.displayRectangle; // points to a local rectangle, rather than base.DisplayRectangle
}
}
Then I've overridden OnSizeChanged in order to update the display rectangle size:
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
this.displayRectangle = this.ClientRectangle;
this.displayRectangle.Y += this.ItemSize.Height + 4;
this.displayRectangle.Height -= this.ItemSize.Height + 4;
}
The problem I'm encountering is, when the TabControl is re-sized, the DisplayRectangle works and re-sizes accordingly, but when the parent form is maximized/minimized (thus changing the control size), the display rectangle does not update.
How should I go about fixing this? Are there any guidelines for managing the display rectangle manually?
I have discovered a couple of things which help to fix this issue. They are; to resize the display rectangle using an override of the OnResize method, and to set the bounds for each tab in the tab control when you have finished resizing the display rectangle...e.g:
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.displayRectangle = this.ClientRectangle;
this.displayRectangle.Y += this.ItemSize.Height + 4;
this.displayRectangle.Height -= this.ItemSize.Height + 4;
foreach(TabPage page in this.TabPages)
{
page.SetBounds(
this.DisplayRectangle.X,
this.DisplayRectangle.Y,
this.DisplayRectangle.Width,
this.DisplayRectangle.Height,
SpecifiedBounds.All
);
}
this.Refresh(); // Can optimize this!
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I remove the border padding on container controls in WinForms?
I've developed a Winforms application in Visual studio 2008. On the main form I have a Tab control. Now I am trying to use a background image to the tab page. The problem that I am running into is that the tab control seems to have a thick border around it. Also the tab control does not cover the entire form leaving a line of space over the top between the form and tab page. (I have the tab pages alignment set at bottom). So a border around the tab control and line of space at the top making my page look ugly. I tried to give the same image as the background to form, but the tab control padding playing the spoilsport.
Any ideas to make my design better would be appreciated.
I agree with the majority of comments made here. The standard TabControl is drawn very poorly on Microsoft's Part...even in Windows Vista / 7 it doesn't look great! You would be better to write your own custom implementation by inheriting the TabControl and then drawing the additional stuff you want.
You might consider using this as a template for your new control. You just need to add some cool design / drawing work to the OnPaint and OnPaintBackground methods.
namespace CustomControls
{
#region USING
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
#endregion
public class CustomTabControl : TabControl
{
#region VARIABLES
private int hotTrackTab = -1;
#endregion
#region INSTANCE CONSTRUCTORS
public CustomTabControl() : base()
{
this.InitializeComponent();
}
#endregion
#region INSTANCE METHODS
private void InitializeComponent()
{
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.DrawMode = TabDrawMode.OwnerDrawFixed;
}
private int GetTabUnderCursor()
{
Point cursor = this.PointToClient(Cursor.Position);
for (int index = 0; index < this.TabPages.Count; index++)
{
if (this.GetTabRect(index).Contains(cursor))
{
return index;
}
}
return -1;
}
private void UpdateHotTrack()
{
int hot = GetTabUnderCursor();
if (hot != this.hotTrackTab)
{
if (this.hotTrackTab != -1)
{
this.Invalidate(this.GetTabRect(this.hotTrackTab));
}
this.hotTrackTab = hot;
if (this.hotTrackTab != -1)
{
this.Invalidate(this.GetTabRect(this.hotTrackTab));
}
this.Update();
}
}
#endregion
#region OVERRIDE METHODS
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
this.UpdateHotTrack();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
this.UpdateHotTrack();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
this.UpdateHotTrack();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
switch (this.Alignment)
{
case TabAlignment.Bottom:
case TabAlignment.Left:
case TabAlignment.Right:
case TabAlignment.Top:
default:
throw new NotImplementedException();
}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
base.OnPaintBackground(pevent);
}
#endregion
}
}
Bear in mind that the code above draw an absolutely blank TabControl that only displays the DisplayRectangle. Everything else including the tabs you will need to do yourself!
Additionally, to draw backgrounds for individual TabPages, you may need to override and custom implement TabPage as well, however you might be able to achieve the result you are looking for with just a custom tab control.
Check this out
http://www.codeproject.com/Articles/42046/Customized-TabControl-by-Repainting-Microsoft-s-Pa
IMHO This is better...
http://www.codeproject.com/Articles/38014/KRBTabControl
IMHO this is better still...
http://www.codeproject.com/Articles/91387/Painting-Your-Own-Tabs-Second-Edition
also look on VB Forums...I know I've seem some awesome custom tab controls on there!
How can I disable the focus cues on a SplitContainer?
I ask because I'd rather draw them myself using OnPaint in order to make it look somewhat smoother.
I tried this:
protected override bool ShowFocusCues
{
get
{
return false;
}
}
And this is my control:
public class cSplitContainer : SplitContainer
{
private bool IsDragging;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (!IsSplitterFixed) IsDragging = true;
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (IsDragging)
{
IsDragging = false;
IsSplitterFixed = false;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (IsDragging)
{
IsSplitterFixed = true;
if (e.Button == MouseButtons.Left)
{
if (Orientation == Orientation.Vertical)
{
if (e.X > 0 && e.X < Width) SplitterDistance = e.X;
}
else
{
if (e.Y > 0 && e.Y < Height) SplitterDistance = e.Y;
}
}
else
{
IsDragging = false;
IsSplitterFixed = false;
}
}
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
if (IsDragging)
{
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(127, 0, 0, 0)), Orientation == Orientation.Horizontal ? new Rectangle(0, SplitterDistance, Width, SplitterWidth) : new Rectangle(SplitterDistance, 0, SplitterWidth, Height));
}
}
}
but it didn't work. I also tried some other methods mentioned before, but I'm still getting focus cues.
I don't think what you are seeing is the FocusCue so much as a floating window that is used to move the slider.
If keyboard access isn't important, you can try making it unselectable:
public class MySplit : SplitContainer {
public MySplit() {
this.SetStyle(ControlStyles.Selectable, false);
}
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.Clear(Color.Red);
}
}
This prevents the SplitContainer from getting focus, but your mouse can still interact with it.
The code of SplitContainer is like:
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
if (Focused) {
DrawFocus(e.Graphics,SplitterRectangle);
}
}
DrawFocus is not virtual. So you can't override it.
Focused is virtual. Maybe you can set it to false while calling base.OnPaint(...) in your OnPaint override.
So you could add following code (I did not tested if it works):
private bool _painting;
public override bool Focused
{
get { return _painting ? false : base.Focused; }
}
protected override void OnPaint(PaintEventArgs e)
{
_painting = true;
try
{
base.OnPaint(e);
}
finally
{
_painting = false;
}
}
That is more a hack than a clean solution.
I was googling for this issue and this question came up on the top.
There is a solution and interesting discussion on a Microsoft forum regarding the splitter stealing focus for no good reason. The following comment is spot on:
The focus issue you mentioned is by design, however to get the performance you want, you can use the following workaround: ....
It may be "by design", but it is not a very good one. What spitters have you ever seen in any Microsoft production application that even temporarily take the focus from the panes they split? I also added the code you suggest, and it does keep me from permanently losing the focus to the splitter, but I still don't like the fact that my panes hide and show their selections during splitter manipulation.
This distracting selection flash just is not present in most professional applications. It is just good enough that it probably won't be worth my time to fix for a while, but not what most people really want. If you respected the TabStop property or even added a AcceptsFocus property, most people would want this off. I think you should add this option to the design in a future version.
--Brendan
Simple solution: give away focus immediately when receiving it!
Three steps:
Create a GotFocus handler for the SplitContainer
Forward the focus to another control with AnotherControl.Focus().
Set TabStop to False
That's all. The ugly focus cue is never shown.
Now, one subtlety: Which other control to give the focus to? It's up to you. Just take the first control by tab order, or a upper-left focusable control in the right pane of the SplitContainer (TextBox in the ASCII diagram below). The perfect solution would be the previous control which had focus, but sadly this is not easy to find out: Find out the control with last focus, but IMHO the upper-left focusable control is a very good response.
left pane right pane
------------------------------------------------
: :: :
: :: [TextBox] [Button] :
: :: :
: :: [Combobox V] :
: :: :
------------------------------------------------
it is a kind a similar question being asked on stackoveflow one solution is sugested as being used by you also along with overriding showfocuscues property you need to override paint method as well.
As long as the mouse is over a specific control, we show some form. When the mouse leaves the control, we hide the control after a small timeout. This is standard hover behavior.
However, when a control (for example a Treeview) has a scrollbar, and the mouse is ON or OVER the scrollbar, the events don't fire ...
If we could get a reference to the scrollbar control, this would solve our problem, as we would add the same listener events to the scrollbar. However, the scrollbar isn't accessible as far as I know ...
How can we solve this problem ?
The scrollbar is in the tree view's non-client area. When the mouse moves there, it starts generating non-client messages like WM_NCMOUSEMOVE and WM_NCMOUSELEAVE. You would have to sub-class the TreeView and override WndProc() to detect these message.
This doesn't really solve your problem though, you'll still have a hard time with edge cases. A low-tech approach with a Timer always works:
private Form frmPopup;
private void treeView1_MouseEnter(object sender, EventArgs e) {
timer1.Enabled = true;
if (frmPopup == null) {
frmPopup = new Form2();
frmPopup.StartPosition = FormStartPosition.Manual;
frmPopup.Location = PointToScreen(new Point(treeView1.Right + 20, treeView1.Top));
frmPopup.FormClosed += (o, ea) => frmPopup = null;
frmPopup.Show();
}
}
private void timer1_Tick(object sender, EventArgs e) {
Rectangle rc = treeView1.RectangleToScreen(new Rectangle(0, 0, treeView1.Width, treeView1.Height));
if (!rc.Contains(Control.MousePosition)) {
timer1.Enabled = false;
if (frmPopup != null) frmPopup.Close();
}
}
I think there are several different ways to do this, but the key is your desire to have a timeout on the action. I think a combination of two techniques might work:
Put the control on a panel, docked to fill, and use the MouseEnter of the panel to turn on your behavior -- this will include the control's scrollbar. You can use the MouseLeave event of the panel as well, but you'll have to check the cursor's position to ensure it hasn't moved into the contained control. This method is mostly reliable, but moving the mouse quickly can confuse it.
If you combine this with a timer that starts when your shown/hidden control is shown and check the cursor position periodically. This will work, but your timeout before hiding the control won't necessarily be consistent (because the timer starts when they enter the control). You could stop/start the timer on mousemoves in the control to alleviate this somewhat.
I put together a project of the different methods I tried here: http://lovethedot.s3.amazonaws.com/100609StackoverflowScrollbarQuestion.zip
By docking the control you want to track in the panel, it essentially wraps it and you'll get MouseEnter at the very edge of the tracked control:
private void panel1_MouseEnter(object sender, EventArgs e)
{
this.Text = "in";
}
private void panel1_MouseLeave(object sender, EventArgs e)
{
if (!new Rectangle(new Point(0, 0), panel1.Size).Contains(panel1.PointToClient(Control.MousePosition)))
this.Text = "out";
}
You're tracking entry into the panel surrounding the control, and exit from that panel provided the cursor isn't inside the tracked control.
To get a better "leave" experience, it's combined with a Timer that checks to see where the cursor is as well:
private void listBox3_MouseEnter(object sender, EventArgs e)
{
button1.Visible = true;
visibleTimer.Stop();
visibleTimer.Start();
}
void visibleTimer_Tick(object sender, EventArgs e)
{
if (!new Rectangle(new Point(0, 0), listBox3.Size).Contains(listBox3.PointToClient(Control.MousePosition)))
{
visibleTimer.Stop();
button1.Visible = false;
}
}