resizing dockpanel after animation, VB - wpf

I resize a dock panel like this:
Private WithEvents PanelAnimation As New DoubleAnimation
Private WithEvents PanelSB As New Storyboard
With PanelAnimation
.From = WpfDockPanel.ActualHeight
.To = s
.Duration = New Duration(TimeSpan.FromSeconds(0.5))
.AccelerationRatio = 0.5
.DecelerationRatio = 0.5
End With
PanelSB.Children.Add(PanelAnimation)
Storyboard.SetTarget(PanelAnimation, WpfDockPanel)
Storyboard.SetTargetProperty(PanelAnimation, New PropertyPath(DockPanel.HeightProperty))
PanelSB.Begin(AviMainWindow)
..which works fine. Then, I want to manually set the size, but it won't change, if I stop the code and type in a different size, the size won't change, it is as though it is readonly.
But if I change the size once, not by animating, just by setting the size, I can change it again no problem. Why can't I manually set the height after animating?
Thanks

This is because the animation's FillBehavior is set to HoldEnd by default. You could set it to Stop.
You would however also have to set the Height property of the animation target to the desired end value manually before starting the animation. Otherwise it would flip back to the value it had before the animation was started.
With PanelAnimation
.FillBehavior = FillBehavior.Stop
...
...
WpfDockPanel.Height = s
PanelSB.Begin(AviMainWindow)

Probably you need to remove the value applied by the animation. Something like
WpfDockPanel.BeginAnimation(DockPanel.HeightProperty, null)
should do the trick.

Related

Why does my ColumnHeadersDefaultCellStyle keep being reset in Visual Studio designer?

I am trying to make the column headers of my DataGridView bold, in Visual Studio 2008.
Every time I change my ColumnHeadersDefaultCellStyle to Calibri 9.75pt bold, using the properties box, the next time I reopen the saved form, the ColumnHeadersDefaultCellStyle has reverted to Calibri 9.75 without bold.
My form's font is Calibri 9.75 without bold, as is my default cell style, but I should be able to override the default cell style with my ColumnHeader style right?
I can solve this problem programmatically by setting the style when the form is shown, but we would like to have the Visual Studio designer show the bolded headers, so we can layout the columns appropriately for the space taken up by bold header text.
In addition, the actual designer file specifies that the ColumnHeadersDefaultCellStyle is bold, even though the designer interface says it is not bold.
dataGridViewCellStyle1.Font = new System.Drawing.Font("Calibri", 9.75F,
System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.receiptDetailView.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
Have you tried check EnableHeadersVisualStyles value?
According to MSDN:
If visual styles are enabled and EnableHeadersVisualStyles is set to
true, all header cells except the TopLeftHeaderCell are painted using
the current theme and the ColumnHeadersDefaultCellStyle values are
ignored.
It is a bug, although Microsoft would probably try to call it a feature. The DataGridView header cells are supposed to inherit the current theme only if EnableHeadersVisualStyles is set to TRUE, and use the settings in ColumnHeaderDefaultCellStyles if it is false. But the DGV ignores EnableHeadersVisualStyles and always inherits the font of the parent container it resides in.
Both rutlean's and Nico Engler suggestions will work. Here is what I always do as a standard practice: Put your DGV in a panel (depending on your application, you might want to set the Dock property to fill. Then set the Panel's font to your desired settings. Your DGV will now always inherit that setting.
I found a workaround where just editing the XXXX.Designer.cs with following code does the trick.
this.receiptDetailView.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
this.receiptDetailView.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font("Calibri", 9.75F, System.Drawing.FontStyle.Bold);
It seems that this is a bug, though I am not sure why it happens. I have tested it in every possible way and the value is overriden by the parent control value regardless of whether it is set or not. This is the opposite of how every other WinForms (or any other UI framework) control works, and doesn't make any sense. I have also tested various other controls and have not found another case where this happens.
The ColumnHeadersDefaultCellStyle Font only matters if the Font property is not set on the parent control (form in this case).
I am giving the bounty to the most upvoted answer but that is not what's going on here.
The "solution" to this that I've been using is to set the font again in the form load event, however this is not a perfect solution since such code doesn't belong there.
I ran into this same issue. However, my dataGridView is located in a groupbox. On a restart of VS 2010, the dataGridView fonts will always be whatever the groupBox is set to. Definitely a bug I would like.
I resolved this problem by adding a frame. For me, the datagridview was inside a groupbox (although a few other container types did the same).
Resolved by putting a panel inside the groupbox, set the appropriate font to that panel, put the datagridview inside that panel and by default it inherits the fonts.
I am using VS2010
The answer is actually pretty simple.
You set a Font Style to Form1 [Arial; 8,25pt].
Lets see the designer :
private void InitializeComponent()
{
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column3 = new System.Windows.Forms.DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle1.Font = new System.Drawing.Font("Calibri", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.dataGridView1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.Column1,
this.Column2,
this.Column3});
this.dataGridView1.EnableHeadersVisualStyles = false;
this.dataGridView1.Location = new System.Drawing.Point(49, 62);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.Size = new System.Drawing.Size(443, 309);
this.dataGridView1.TabIndex = 0;
//
// Column1
//
this.Column1.HeaderText = "Column1";
this.Column1.Name = "Column1";
//
// Column2
//
this.Column2.HeaderText = "Column2";
this.Column2.Name = "Column2";
//
// Column3
//
this.Column3.HeaderText = "Column3";
this.Column3.Name = "Column3";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 14F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(546, 457);
this.Controls.Add(this.dataGridView1);
this.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
}
Now as you can see, your font setting for Datagridview header did saved.
But still, font setting for your form appeared after that, which eventually overrides Datagridview font setting.
My advice is return the Form font setting to default.
Use this code
dataGridView1.EnableHeadersVisualStyles = false;
dataGridView1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
Try this:
DataGridView1.ColumnHeadersDefaultCellStyle.Font = new Font("Calibri", 9.75F, FontStyle.Bold);
This is a bug and still there even in .net 4.6, the problem is that the ColumnHeadersDefaultCellStyle font always overwritten by its Parent font so I figured out a fix for this:
First you need to add your DataGridView to an own Panel, the Panel will work here as a shield and I believe you need to set the Dock property of the DataGridView to Fill.
Second you need to add the following code into ColumnHeadersDefaultCellStyleChanged event.
If Parent IsNot Nothing Then
Parent.Font = ColumnHeadersDefaultCellStyle.Font
End If
I had the same issue today and it seemed that the ColumnHeadersDefaultCellStyle of the DataGridView is overwritten by the font style of the form it belongs to.
As a solution I set the GdiCharSet parameter of the form's font to 0. After that beeing done, the font of the ColumnHeadersDefaultCellStyle won't be overwritten.
I'm on VS 2010 and Window 8.
I know this topic is old, however I was having the same issue in VS 2015 with the ColumnDefaultHeadersCellStyle font size always reverting to 10pt (I needed it to be 14pt). I was able to fix this by first changing the font itself, which then allowed me to change the font size.
The font I was originally using was SEGOE UI SEMIBOLD, which I changed to just SEGOE UI and was able to change the size. I haven't looked into why using the semibold version prevented me from changing the size. Further, this method has worked for me with VisualStyles enabled, and EnableHeadersVisualStyles set to true.
If anyone is still having this problem, my suggestion would be try changing to another font.
You can try that;
Private Sub DgvListeFt_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles DgvListeFt.CellPainting
Call KolonBaslikDGV(sender, e)
End Sub
Sub KolonBaslikDGV(ByVal S As Object, ByVal E As DataGridViewCellPaintingEventArgs)
E.PaintBackground(E.CellBounds, True)
If E.RowIndex = -1 Then
If E.Value Is Nothing Then
E.Handled = True
Return
End If
E.Handled = True
Dim headerFont = New Font("Ariel", 9, FontStyle.Regular)
Dim myBounds As Rectangle = E.CellBounds
myBounds.X = E.CellBounds.X + 4
Dim sf = New StringFormat With {.Alignment = StringAlignment.Near,
.LineAlignment = StringAlignment.Center}
E.Graphics.DrawString(E.Value.ToString, headerFont, Brushes.MediumVioletRed, myBounds, sf)
headerFont.Dispose()
sf.Dispose()
End If
End Sub

WPF custom shader effect property binding for animation

I'm implementing transitions in a WPF application.
First I "save" my 2 FrameworkElement in 2 ImageBrush.
Then I set the Input & Back (Brush) properties of my shader Effect with them.
CustomEffect s = new CustomEffect();
RenderTargetBitmap rtb = new RenderTargetBitmap((int)SourceFrameWorkElement.ActualWidth, (int)SourceFrameWorkElement.ActualHeight, 96, 96, PixelFormats.Pbgra32);
rtb.Render(SourceFrameWorkElement);
ImageBrush ib = new ImageBrush(rtb);
s.Input = ib;
rtb.Render(TargetFrameWorkElement);
ib.ImageSource = rtb;
s.Back = ib;
SourceFrameWorkElement.Effect = s;
Now that all is set up, I want to animate the Time property of my shader, and i've tried this:
DoubleAnimation refDoubleAnimation = new DoubleAnimation(0.0, 1.0, Duration);
Storyboard.SetTarget(refDoubleAnimation, SourceFrameWorkElement);
Storyboard.SetTargetProperty(refDoubleAnimation, new PropertyPath("(Effect).(CustomEffect.Time)");
refStoryboard.Children.Add(refDoubleAnimation);
refStoryboard.Completed += new EventHandler(OnStoryboardCompleted);
refStoryboard.Begin(SourceFrameWorkElement, true);
and i get an InvalidOperationException on the begin method with this message:
"Cannot resolve all property references in the property path '(Effect).(CustomEffect.Time)'.
Verify that applicable objects supports the properties."
But when I use a built in Effect like BlurEffect, it works....
Can someone tell me where i'm wrong ?
Edit:
I've also tried
SourceElement.Effect.BeginAnimation(SlideInEffect.TimeProperty, refDoubleAnimation)
instead of using the storyboard, I don't get an exception but the second image pop instantly and the animation is not playing
The solution was to use BeginAnimation ^^
In fact, I had the second image with opacity to 1, and the animation was playing behind
(i checked if the time elapsed to get in my OnAnimationCompleted eventHandler matched with the transition Duration)
so i've created a second animation on the TargetElement opacity with 2 DiscreteDoubleKeyFrames to do the trick and now it works ^^
Maybe the Storyboard thing could work if i add the namespace in the PropertyPath but i have no time to test it so give it a try if you want, and update the post ^^.

WPF - Image Control Actual Size

I have a problem in getting ActualHeight and ActualWidth of image control in WPF. When user selects the image file, I want to resize the selected image based on the dimensions of the image control.
I tried to get the Image.ActualHeight and Image.ActualWidth when window initializes, but I found that both properties of Image control are '0'.
So how to get the dimensions of the image control.
the remarks for FrameworkElement.ActualHeight say that there might be some lag before the property has its real value.
This property is a calculated value
based on other height inputs, and the
layout system. The value is set by the
layout system itself, based on an
actual rendering pass, and may
therefore lag slightly behind the set
value of properties such as Height
that are the basis of the input
change.
The final size of your control is set by FrameworkElement.Arrange(-Override). You could override the method and just call the base class implementation. Its return value will be the actual size of your Image.
Off the top of my head, I think you should subscribe to the Load event on the image control, the ActualHeight/Width are not updated until that event fires.
The control's ActualSize is set after the "Measure" layout pass (the "Arrange" layout pass sets its location). The other two answers are helpful; the "Arrange" layout pass of the container only happens after its children have been measured, and the load handler of your image control should be called after its first layout pass has completed.
The Best solution I have found is to wait until after the Image has loaded.
Private Sub Update_imgImage(tURI As Uri)
imgImage.LayoutTransform = New ScaleTransform(scaleX:=1, scaleY:=1)
Dim src As BitmapImage = New BitmapImage()
src.BeginInit()
src.UriSource = tURI
src.CacheOption = BitmapCacheOption.OnLoad
src.EndInit()
imgImage.SetCurrentValue(Image.SourceProperty, src)
AddHandler src.DownloadCompleted, AddressOf ImageDownloadCompleted
End Sub
Then for ImageDownloadCompleted i have the following:
Sub ImageDownloadCompleted(sender As Object, e As System.EventArgs)
Dim src As BitmapImage
src = DirectCast(sender, BitmapImage)
Dim scaleXY As Double
If sender.Width = 0 Then Exit Sub
'default width is 600 for my item, if changed, then resize
If sender.Width <> 600 Then
scaleXY = 500 / sender.Width
imgImage.LayoutTransform = New ScaleTransform(scaleX:=scaleXY, scaleY:=scaleXY)
Else
imgImage.LayoutTransform = New ScaleTransform(scaleX:=1, scaleY:=1)
End If
RemoveHandler src.DownloadCompleted, AddressOf ImageDownloadCompleted
End Sub
I hope this works for you.

Is it possible for a WPF control to have an ActualWidth and ActualHeight if it has never been rendered?

I need a Viewport3D for the sole purpose of doing geometric calculations using Petzold.Media3D.ViewportInfo. I would prefer not to have to place it in a Window or otherwise render it.
I'm attempting to accomplish this by instantiating a Viewport3D and setting a few properties using the following C# method:
private Viewport3D CreateViewport(MainSettings settings)
{
var cameraPosition = new Point3D(0, 0, settings.CameraHeight);
var cameraLookDirection = new Vector3D(0, 0, -1);
var cameraUpDirection = new Vector3D(0, 1, 0);
var camera = new PerspectiveCamera
{
Position = cameraPosition,
LookDirection = cameraLookDirection,
UpDirection = cameraUpDirection
};
var viewport = new Viewport3D
{
Camera = camera,
Width = settings.ViewportWidth,
Height = settings.ViewportHeight
};
return viewport;
}
Later, I'm attempting to use this viewport to convert the mouse location to a 3D location using this method:
public Point3D? Point2dToPoint3d(Point point)
{
var range = new LineRange();
var isValid = ViewportInfo.Point2DtoPoint3D(_viewport, point, out range);
if (isValid)
return range.PointFromZ(0);
else
return null;
}
Unfortunately, it's not working. I think the reason is that the ActualWidth and ActualHeight of the viewport are both zero (and these are read-only properties, so I can't set them manually). (Note: I have tested the exact same method with an actual rendered Viewport3D, and it worked fine, so I know the issue is not with my converter method.)
Any idea how I can get WPF to assign the ActualWidth and ActualHeight of a control based on the Width and Height settings?
I tried setting the HorizontalAlignment and VerticalAlignment to Left and Top, respectively, and I also messed with the MinWidth and MinHeight, but none of these properties had any effect on the ActualWidth or ActualHeight.
From MSDN topic for the ActualWidth property:
This property is a calculated value based on other width inputs, and the layout system. The value is set by the layout system itself, based on an actual rendering pass, and may therefore lag slightly behind the set value of properties such as Width that are the basis of the input change.
So, this sounds like a rendering pass is necessary for the property to be set. However, you could try to call Measure(Size) and then Arrange(Rect) to simulate the layout process. Maybe this is already sufficient.

How to override application styles in a wpf control created at runtime

I am trying to create a WPF control at runtime, but I can't figure out how to make it ignore the styles coming from the App.xml resources. I've tried setting the style to null and the OverridesDefaultStyle to true but no luck. The app settings set the foreground to white, and I can't seem to explicity set it to anything else.
Label tb = new Label();
tb.OverridesDefaultStyle = true;
tb.Style = null;
tb.Foreground = new SolidColorBrush(Colors.Black);
this.Children.Add(tb);
Edit: For some reason I never could get the Label to work but when I switched to the textbox, it worked fine.
Thank you for your responses.
All you have to do is set Style to null to stop it from inheriting. Then you can set the Foreground to whatever you like:
var tb = new TextBlock() { Text = "Hello" };
tb.Style = null;
tb.Foreground = Brushes.Blue;
this.Children.Add(tb);
If this isn't working for you, I'd suggest something else entirely is going on.
PS. Use Brushes.Black rather than creating your own SolidColorBrush. Not only is it cleaner, the brush will also be frozen. Your code creates an unfrozen brush, which is less efficient. You can also freeze it yourself by calling Freeze() on the brush.
The following near-identical code works for me:
Label l = new Label();
l.Content = "Fie!!!";
l.Style = null;
l.OverridesDefaultStyle = true; // not required, see below
l.Foreground = new SolidColorBrush(Colors.Blue);
((Grid)Content).Children.Add(l);
From experimenting, however, it seems that if you set OverridesDefaultStyle = true after setting Style, it works okay. But if you set OverridesDefaultStyle before setting Style, it all goes wrong. (No, I don't know why this happens! grin) So move the OverridesDefaultStyle setter to after the Style setter, or (since it's not required for the effect you want), just remove it.

Resources