WinForms - Background is grey during runtime but not in the design window - winforms

During runtime the background is grey but I haven't made this the case in the design window or the Form's code.
I have no code in Form1's class that changes the colour of the form's background, however I believe the issue lies in the code in Program.cs:
namespace ImageTagger
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
public static Form1 form1 = new Form1();
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.SetCompatibleTextRenderingDefault(false);
form1.IsMdiContainer = true;
Application.Run(form1);
}
}
}
I can prove this isn't an issue with changing Form1's background colour because upon changing the background colour to blue in the design window, the background still turns grey but the labels are now blue.
Is this some issue with rendering?

As LarsTech commented, the solution was to simply remove form1.IsMdiContainer = true;

Related

WinForms Control.Scale Method

The code below shows a small WinForms app which includes a simple Control that draws a circle. I'm trying to understand the behavior of the Control.Scale method.
If I call the Scale method on the Control from Main, as shown in the code, it scales properly. But if I instead call Scale from Circle's constructor, no scaling occurs.
My puzzlement here no doubt indicates a gross misunderstanding on my part regarding what Scale is supposed to do. Can anyone enlighten me?
using System;
using System.Windows.Forms;
using System.Drawing;
class Program
{
[STAThread]
public static void Main()
{
var circle = new Circle(Color.Orange)
{
Size = new Size(23, 23),
Location = new Point(50, 50)
};
circle.Scale(new SizeF(3.0f, 3.0f)); // <-- scaling here works
var form = new Form();
form.Controls.Add(circle);
Application.Run(form);
}
}
class Circle : Control
{
public Circle(Color color)
{
ForeColor = color;
// Scale(new SizeF(3.0f, 3.0f)); // <-- scaling here DOESN'T work
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.FillEllipse(new SolidBrush(ForeColor), ClientRectangle);
}
}
The Scale() method isn't meant to do this. It is a helper method to implement the AutoScaleMode property. When your control is created by the form's InitializeComponent() method, scaling is suspended with SuspendLayout(). Which is why it has no effect in your constructor. The AutoScaleMode property value is applied when the form handle is created. Which cancels any scaling you applied.
I think you are looking for e.Graphics.ScaleTransform() in your OnPaint method. It doesn't scale the control, it scales the drawing. If you really did mean to scale the control then just change its Size property.

Trigger repaint of WPF Button control from external thread

I am having some issues with WPF not fully repainting a button control when the button is changed from another thread, and I am not sure how to force it to do a full repaint.
The situation is that on receipt of a message (via WCF - but the source isn't important, except that it is an external thread) I update the foreground color and visibility of a button. WPF immediately repaints the text on the button face, but the surface of the button is not repainted until I click anywhere on the application.
I have tried calling InvalidateVisual() on the button, but that did not help. I think that I am not understanding how a background thread can force a repaint. But the frustrating thing is that something is getting repainted and every other control I am using (text and image controls) are also getting properly repainted when I update them from my same message receipt.
I have now tried sending an empty message to the Dispatcher of the application via Invoke(), but no luck there either.
So I am looking for tips on how to tell WPF that it needs to update the rest of the button and not just the text.
Edit
This is a rough skeleton of my program. Note that I have wrapped the button in a class as there is other related state information I am keeping with it.
class myButton
{
Button theButton
void SetButton()
{
theButton.Forground = a new color
}
}
main
{
myButton.theButton = (Button on WPF canvass)
RegisterCallback( mycallbackFunction) with WCF client endpoint
}
void myCallbackFunction(message)
{
if message has button related stuff, call myButton.SetButton
}
Edit 2
Solved my problem .. it was actually a conflict between a "CanExecute" method and setting the buttons attributes in the callback. Once I removed the "CanExecute" function it all worked.
Setting properties on the button itself from code, especially another thread/callback, is an entrance to a painful world of inconsistent states.
What you should do is bind your button's properties to properties in your code, and then have your callback change those external properties.
I know the code you posted was kind of a mock up for what you actually want to do in your program, and I couldn't really follow your logic, but here's a complete program that operates similarly to your example and shows what I'm talking about. Let me know if I've missed the mark.
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public class MyButton : INotifyPropertyChanged
{
private Button _theButton;
public Button TheButton
{
get { return _theButton; }
set
{
_theButton = value;
//set text binding
Binding textBind = new Binding("Text");
textBind.Source = this;
textBind.Mode = BindingMode.OneWay;
_theButton.SetBinding(Button.ContentProperty, textBind);
//set color binding
Binding colorBind = new Binding("Brush");
colorBind.Source = this;
colorBind.Mode = BindingMode.OneWay;
_theButton.SetBinding(Button.ForegroundProperty, colorBind);
NotifyPropertyChanged("TheButton");
}
}
public void Set(string text, Brush brush)
{
this.Text = text;
this.Brush = brush;
}
private string _text;
public string Text
{
get { return _text; }
set { _text = value; NotifyPropertyChanged("Text"); }
}
private Brush _brush;
public Brush Brush
{
get { return _brush; }
set { _brush = value; NotifyPropertyChanged("Brush"); }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
public partial class MainWindow : Window
{
MyButton _myButton = new MyButton();
public MainWindow()
{
InitializeComponent();
//button1 is defined in XAML markup
_myButton.TheButton = this.button1;
//or else this could be your callback, same thing really
Thread t = new Thread(SetButton);
t.Start();
}
void SetButton()
{
_myButton.Text = "wo0t!";
_myButton.Brush = Brushes.Red;
//or
_myButton.Set("giggidy!", Brushes.Yellow);
}
}
}
Note that binding your Button properties in XAML is much less ugly, but then we're getting into UserControls and DataContexts which is another topic. I would look at inheriting the Button class to implement the features you want.
I recommend reading the article (Build More Responsive Apps With The Dispatcher) from MSDN magazine that describes how WPF works with the Dispatcher when using BackgroundWorker.
As per my edit, I had conflict between the buttons CanExecute binding in the XAML and me setting the background color in the callback. I didn't really need the CanExecute, so getting rid of that solved my problem.

WPF WindowStartupLocation="CenterOwner" not really center, and pops all over, why?

Well this question and this question are similar but no answers that work. In fact I was hoping WindowStartupLocation=CenterOwner would work...it doesn't. It seems to center the new window in the center of a grid column, not the center of the main window. So I'm assuming it thinks that is the parent. Second when I close the dialog and open it again it is not centered but moved down and right from the previous position. And if I move the main window to a second monitor the popup still opens on the default monitor. Are these properties wrong or am I just thinking it should work in a different way. I suppose I could calculate the Top and Left properties manually. I just want the popup to be centered in the main window no matter where it is.
Probably because you didn't set the owner:
this.Owner = App.MainWindow; // for example
That's how I do it and it centers the window perfectly all the time.
To extend on what Will Eddins commented, you could create an overload method for ShowDialog() or Show() in your Window:
public void ShowDialog(Window owner)
{
this.Owner = owner;
this.ShowDialog();
}
public void Show(Window owner)
{
this.Owner = owner;
this.Show();
}
Or overload a constructor:
public MyWindow(Window owner)
: this()
{
this.Owner = owner;
}
If you create an extention for this, you could reuse this fine idea:
/// <summary>
/// Opens a window modally, with an owner
/// </summary>
/// <param name="window">The window to open</param>
/// <param name="opener">The owner of the window getting opened</param>
/// <returns>window.ShowDialog()</returns>
public static bool? ShowDialog(this Window window, Window opener)
{
window.Owner = opener;
return window.ShowDialog();
}
In addition, we can use:
this.Owner = App.Current.MainWindow;
Or Application instead of App.
And place it in a child window constructor:
public partial class ChildWindow : Window
{
public ChildWindow()
{
InitializeComponent();
DataContext = new ChildWindowViewModel();
this.Owner = App.Current.MainWindow;
}
}
I had the same problem...but it was mostly due to the fact that, when i wanted to get rid of the child window, I used hide() instead of close() ... so when you reopen it, because it was hidden and not closed, when the parent window is moved, it still opens at it's startup location...
So when close the child window instead of hiding it for example when finished working with it.
Something else that can cause this is setting DataContext after InitializeComponent() is called.
If you have code-behind like this:
public CustomWindow(CustomViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
Change it to:
public CustomWindow(CustomViewModel viewModel)
{
DataContext = viewModel;
InitializeComponent();
}

XAML Without WPF - Animations

I am trying to use XAML completely outside WPF, in particular inside an XNA application. So far, I have managed (quite easily, I am surprised to admit) to load some data inside my XNA application from a XAML file. The problems start when I decided that I wanted to animate one of the properties of my class...Nothing happens :(
Here is the main class I load from the XAML file:
[ContentPropertyAttribute("Animation")]
public class Test : FrameworkContentElement
{
public string Text { get; set; }
public Vector2 Position { get; set; }
public Color Color { get; set; }
public Storyboard Animation { get; set; }
public static DependencyProperty RotationProperty =
DependencyProperty.Register("Rotation", typeof(double), typeof(Test), new PropertyMetadata(0.0));
public double Rotation { get { return (double)GetValue(RotationProperty); } set { SetValue(RotationProperty, value); } }
}
Here is the XAML file:
<l:Test xmlns:l="clr-namespace:XAMLAndXNA;assembly=XAMLAndXNA"
xmlns:a1="clr-namespace:System.Windows.Media.Animation;assembly=PresentationFramework"
xmlns:a2="clr-namespace:System.Windows.Media.Animation;assembly=PresentationCore"
Text="Testo" Position="55,60" Color="0,255,255,255">
<a1:Storyboard>
<a2:DoubleAnimation a1:Storyboard.TargetProperty="Rotation"
From="0"
To="360"
Duration="00:00:10.0"/>
</a1:Storyboard>
</l:Test>
And here is the loading and animation launching (attempt):
Test test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test;
test.Animation.Begin(test);
I am dying of curiosity :)
Although XAML is independent of WPF, the visual elements aren't. In particular, animation and layout are part of WPF, and depends on the WPF plumbing being present -- through an Application object, a PresentationSource such as a HwndSource, the XBAP PresentationHost.exe, etc.
So you can read in your XAML and get an object graph of a Test object with a child Storyboard object, but that Test object isn't hooked up to the animation or layout engines until it's placed in a WPF context. All that the XAML gets you is a dumb in-memory object graph: it's WPF, not XAML, that makes the objects "live."
So as Ben says, you'll probably end up needing to "push or prod" the animation yourself. I'm not aware of any documentation on how to do this, but from poking around in Reflector, it looks like the key API is Storyboard.SeekAlignedToLastTick, of which the docs say:
Values are immediately updated to
reflect the changes due to
SeekAlignedToLastTick, even though the
screen does not reflect these changes
until the screen updates.
Notice that second clause. Normally, WPF handles the updating of the screen as visual object values change. If you're not using WPF, then it's up to you to read the changed values out and redraw the screen accordingly: you don't have the WPF layout manager to handle it for you.
Finally, please note I haven't tested whether SeekAlignedToLastTick will work in an environment without the WPF plumbing loaded. It sounds like it should, because it doesn't care whether it's WPF or user code which is driving the clocks, but I can't make any promises... though I admit you've got me curious!
UPDATE: I've given this a quick go, and it does seem to work. Here's a demo of hosting an animation within Windows Forms (in this case using a plain ol' Windows Forms timer, but in XNA I guess the framework will provide a game timer for you -- didn't try that because I don't know XNA). Assume you have a vanilla Windows Form with a timer (timer1) and a label (label1), and that the project references the WPF assemblies.
First, my simplified version of your class:
[ContentProperty("Animation")]
public class Fie : DependencyObject
{
public double Test
{
get { return (double)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(double), typeof(Fie),
new FrameworkPropertyMetadata(0.0));
public Storyboard Animation { get; set; }
}
Now, the WPF code to load one of these babies from XAML and begin the animation:
private Fie _f;
private DateTime _startTime;
public Form1()
{
InitializeComponent();
string xaml =
#"<local:Fie xmlns:local=""clr-namespace:AnimationsOutsideWpf;assembly=AnimationsOutsideWpf""
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty=""Test""
From=""0""
To=""360""
Duration=""00:00:10.0""/>
</Storyboard>
</local:Fie>";
_f = (Fie)XamlReader.Load(XmlReader.Create(new StringReader(xaml)));
Storyboard.SetTarget(_f.Animation, _f);
_f.Animation.Begin();
_startTime = DateTime.Now;
timer1.Enabled = true;
}
Note that I had to set the storyboard's target to be the XAML object I'd just loaded. This doesn't happen automatically. I tried doing this with Storyboard.TargetName in the XAML, but that didn't seem to work -- you may have more luck.
The final lines are just setup for the timer callback:
private void timer1_Tick(object sender, EventArgs e)
{
TimeSpan sinceStart = DateTime.Now - _startTime;
_f.Animation.SeekAlignedToLastTick(sinceStart);
label1.Text = _f.Test.ToString();
}
I've stored the start time of the animation, and used that to calculate how far into the animation we are. WinForms timers are a bit crude, but this suffices for proof of concept; no doubt XNA will have something better. Then I call Storyboard.SeekAlignedToLastTick, which updates the animated values. Nothing displays automatically because my XAML object isn't hooked up for display, but I can check its Test property and verify that it is indeed animating. In reality, I'd use this to update the position or orientation of whatever XNA visual element the XAML object represented.
Just for reference, I will now document how I managed to make this work with XNA. Thanks to itowlson for providing the missing link: otherwise I had to create an empty Application with an invisible Window...
We define the class with its animation in XAML (notice the xmlns directives):
<l:Test
xmlns:l="clr-namespace:XAMLAndXNA;assembly=XAMLAndXNA"
xmlns:a1="clr-namespace:System.Windows.Media.Animation;assembly=PresentationFramework"
xmlns:a2="clr-namespace:System.Windows.Media.Animation;assembly=PresentationCore"
Text="Testo" Position="55,60" Color="0,255,255,255">
<a1:Storyboard>
<a2:DoubleAnimation a1:Storyboard.TargetProperty="Rotation"
From="0"
To="6.28"
Duration="00:00:2.0"
RepeatBehavior="Forever"/>
</a1:Storyboard>
</l:Test>
The "code-behind" class Test is the following:
[ContentPropertyAttribute("Animation")]
public class Test : DependencyObject
{
public string Text { get; set; }
public Vector2 Position { get; set; }
public Color Color { get; set; }
public Storyboard Animation { get; set; }
public static DependencyProperty RotationProperty =
DependencyProperty.Register("Rotation", typeof(double), typeof(Test), new PropertyMetadata(0.0));
public double Rotation { get { return (double)GetValue(RotationProperty); } set { SetValue(RotationProperty, value); } }
}
In the Initialize function of the XNA Game class we deserialize our xaml file and start the animation:
test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test;
Storyboard.SetTarget(test.Animation, test);
test.Animation.Begin();
The Update function takes as input a GameTime, which offers the TotalGameTime field that stores the TimeSpan of the amount of time passed since the app launch: that is exactly what a Storyboard needs to tick:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
test.Animation.SeekAlignedToLastTick(gameTime.TotalGameTime);
base.Update(gameTime);
}
In the draw method we can just draw some text using the Rotation property, which will now be correctly animated:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.DrawString(Content.Load<SpriteFont>("font"), test.Text, test.Position, test.Color, (float)test.Rotation, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
spriteBatch.End();
base.Draw(gameTime);
}
Outside of the normal loop of a WPF application, I doubt there is any way to drive the animation. There may be some class you can push or prod to drive them, but it is likely sealed.
You will probably wind up building your own animation execution engine running on another thread and ensuring the updates happen on your UI thread, which means either finding a way to reuse the Dispatcher or recreating something similar.
This MSDN article may provide some useful information in this endeavor
It's an interesting project... I'd be curious to hear if you succeed!
Wow, this is pretty awesome! Unfortunately, it will likely come down to some "update" type of call that is being made in some internal API. And if you don't call it, the animation won't animate ... much like if an XNA game doesn't have the Update method called.
I would very much like more info on how you're doing this and what level of success you're finding. You should write a blog post/article somewhere :-)

Can you animate a custom dependency property in Silverlight?

I might be missing something really obvious. I'm trying to write a custom Panel where the contents are laid out according to a couple of dependency properties (I'm assuming they have to be DPs because I want to be able to animate them.)
However, when I try to run a storyboard to animate both of these properties, Silverlight throws a Catastophic Error. But if I try to animate just one of them, it works fine. And if I try to animate one of my properties and a 'built-in' property (like Opacity) it also works. But if I try to animate both my custom properties I get the Catastrophic error.
Anyone else come across this?
edit:
The two DPs are ScaleX and ScaleY - both doubles. They scale the X and Y position of children in the panel. Here's how one of them is defined:
public double ScaleX
{
get { return (double)GetValue(ScaleXProperty); }
set { SetValue(ScaleXProperty, value); }
}
/// <summary>
/// Identifies the ScaleX dependency property.
/// </summary>
public static readonly DependencyProperty ScaleXProperty =
DependencyProperty.Register(
"ScaleX",
typeof(double),
typeof(MyPanel),
new PropertyMetadata(OnScaleXPropertyChanged));
/// <summary>
/// ScaleXProperty property changed handler.
/// </summary>
/// <param name="d">MyPanel that changed its ScaleX.</param>
/// <param name="e">DependencyPropertyChangedEventArgs.</param>
private static void OnScaleXPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyPanel _MyPanel = d as MyPanel;
if (_MyPanel != null)
{
_MyPanel.InvalidateArrange();
}
}
public static void SetScaleX(DependencyObject obj, double val)
{
obj.SetValue(ScaleXProperty, val);
}
public static double GetScaleX(DependencyObject obj)
{
return (double)obj.GetValue(ScaleXProperty);
}
Edit: I've tried it with and without the call to InvalidateArrange (which is absolutely necessary in any case) and the result is the same. The event handler doesn't even get called before the Catastrophic error kicks off.
It's a documented bug with Silverlight 2 Beta 2. You can't animate two custom dependancy properties on the same object.
I would try commenting out the InvalidateArrange in the OnPropertyChanged and see what happens.
I hope it's not bad form to answer my own question.
Silverlight 2 Release Candidate 0 was released today, I've tested this problem on it, and it appears to have been fixed. Both Custom DPs in my test panel can now be animated properly, so the app is behaving as expected. Which is nice.
Note that this RC is only a developer-based RC so the standard build of Silverlight hasn't been updated. I'd expect it to be fully released in the next month, though.

Resources