I'm trying to find my relative coordinate for a usercontrol inside my mainwindow. I tried using the "Control.PointToScreen()" method but with no luck. Everytime I do this i get an exception that says:
System.InvalidOperationException: This Visual is not connected to a PresentationSource
I think this has something to do with me calling pointToScreen before the visuals have rendered properly, since i'm already calling the method in my Mains Constructor.
Anyways, I would like to hear if anyone of you had a hint/Solution/Idea how I could perhaps work around this.
Just to clearify what i'm trying to do, my control contains a photocontrol which i need the exact location off inside my maincontrol, since i want to use these coordinates to create a duplicate of the control on top of it
Experimenting with PointToScreen.
In your code register for the Loaded event of the UserControl.
That should fix the bug that the visuals have not been rendered yet when you try to get the position.
YourControl.Loaded += ControlLoaded;
public void ControlLoaded(object sender, EventArgs e){
Console.WriteLine(YourControl.PointToScreen(new Point(0,0));
}
Edit
Since you want the position of your control relative to your window, better try that one .
YourControl.TransformToAncestor(YourWindow).Transform(new Point(0,0))
Since Contend rendered didn't work I found a solution for my problem.
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
ItemsControl ItemsControl = UCEnvironmentControl.GetItemsControlPhotos();
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => Control.PointToScreen(new Point(0,0));
}
This way, it fires in the LoadedEvent, but waits for the content to be rendered, and then finally it gives you your coordinate back and sets your control
The solution from Max Mazur is working for me:
public partial class MainWindow : Window
{
Point locationOfYourControl;
public MainWindow()
{
InitializeComponent();
this.ContentRendered += MainWindow_ContentRendered;
}
private void MainWindow_ContentRendered(object sender, EventArgs e)
{
locationOfYourControl = YourControl.PointToScreen(new Point(0, 0));
}
}
Related
I am new to WPF and want to build an application which will do serial communication with the my driver and from program i can set values to the driver.
I have managed to make a UI as shown in this figure here . If i press Blue View as pointed by the arrow at last, the view of my window is like this. If i press the Red View Option then the display is like this
Setting button is where the arrow pointing at top right corner(below the close button of window) and when pressed my window will look like this.
Basically i am changing the BIG RECTANGLE content according to the button i have pressed for example (rectangle is blue when Blue view is clicked, rectangle filled up with Red and one label and a button to change the label when Red View is clicked)
So now my problem is I cannot retain the value i had set in this BIG RECTANGLE after i change the content of this BIG RECTANGLE. For example when i pressed the setting button and change the setting like this I am ready for communication in COM5 and the option to close the port can be pressed. Now before closing the port if I change the view of the BIG RECTANGLE by pressing Red View or Blue View then after press the setting button then i don't have that option to close port anymore and since I had already opened the com5 port earlier so when i try to open the port it will also give me error.
Please Help me with this. My visual studio solution explorer looks like this and My code in the button clicked event are as follows:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void SerialPortOnOFFButton_Clicked(object sender, RoutedEventArgs e)
{
MessageBox.Show("ON OFF Clicked");
}
private void SerialPortSettingButton_Clicked(object sender, RoutedEventArgs e)
{
DataContext = new SerialPortSettingView();
}
private void RedViewButton_Clicked(object sender, RoutedEventArgs e)
{
DataContext = new Redview();
}
private void BlueViewButton_Clicked(object sender, RoutedEventArgs e)
{
DataContext = new Blueview();
}
}
And my Solution explorer looks like this
If you want to just close your port you can implement IDisposable interface in your SerialPortSettingView class like this. Each time you change DataContext from SerialPortSettingView your port will be closed.
public class SerialPortSettingView : IDisposable
{
private FileStream _fileStream;
public SerialPortSettingView()
{
_fileStream = new FileStream("somefile.txt", FileMode.Open);
}
public void Dispose()
{
_fileStream?.Close();
}
}
Each time you change the view you are creating a new object to set the DataContext to, if you kept the individual objects as private fields you could then simply set the DataContext to these:
private SerialPortSettingView _serialPortSettingView;
private RedView _redView;
private BlueView _blueView;
public MainWindow()
{
_serialPortSettingView = new SerialPortSettingView();
_redView = new RedView();
_blueView = new BlueView();
InitializeComponent();
}
private void SerialPortOnOFFButton_Clicked(object sender, RoutedEventArgs e)
{
MessageBox.Show("ON OFF Clicked");
}
private void SerialPortSettingButton_Clicked(object sender, RoutedEventArgs e)
{
DataContext = _serialPortSettingView;
}
private void RedViewButton_Clicked(object sender, RoutedEventArgs e)
{
DataContext = _redview;
}
private void BlueViewButton_Clicked(object sender, RoutedEventArgs e)
{
DataContext = _blueview;
}
This way when you switch between views you'll be using the stored version and when you change values they will be stored in that View.
If I were doing this solution I would change the ContentControl to a TabControl (hide the headers) then create each View, with an accompanying ViewModel, as tabs. Then as each click event is fired you simply set the .SelectedIndex property of the TabControl. I'd create a MainWindowViewModel and set the MainWindow's DataContext to this in the constructor:
private MainWindowViewModel = new MainWindowViewModel();
public MainWindow()
{
DataContext = _mainWindowViewModel;
}
And put all the logic in the MainWindowViewModel (you need to use commands). Using code behind isn't what WPF was meant for, you can read up on it all here with a good tutorial to follow - MVVM Tutorial
I don't want to over complicate things and stuff you with too much information in one go but if you start off doing things this way it will be better, hope this helps.
Hi I'm relatively new to C# and completely new to windows form and basically trying to create a subliminal messaging program that at timed intervals will quickly display a message for it to then be hidden again.
I've managed to by looking through various other posts created another form that will pop up and then hide very quickly using
msgObject.Activate();
that brings the form to the front. However it is stopping me from being able to type when I'm working and I basically wanting to know if it is possible to make some kind of message or form appear at the front of all my other programs without it interrupting my current work or opening or closing of other windows and tasks if that makes sense. As currently it brings the form to the front of everything but will also stop me from being able to type etc.
I'm not sure if this is possible with my current method of using a form but if there is a way of achieving the result I'm after I'd be very grateful to find out
Thanks.
Here is more of my code to clarify
public partial class FormHomePage : Form
{
private bool startSubliminal = false;
msg msgObject = new msg();
List<string> subliminalMessages = new List<string>();
public FormHomePage()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
if (startSubliminal)
{
msgObject.Show();
msgObject.BringToFront();
msgObject.Activate();
}
}
private void button1_Click(object sender, EventArgs e)
{
subliminalMessages.Add(txtBox1.Text);
msgObject.LabelText = txtBox1.Text;
txtBox1.Text = string.Empty;
startSubliminal = true;
msgObject.Show();
msgObject.BringToFront();
}
private void timer2_Tick(object sender, EventArgs e)
{
msgObject.Hide();
}
}
How are you showing the second form (the message form) in the first place? You're probably using .Show() (right?), which will make the form "steal" the focus anyway. The same applies to .Activate() and .BringToFront().
Instead, what you can do is to show the message form and make sure it stays on top the current form, and then activate the current/main form once again.
Something like this should work:
var frm = new YourMsgForm();
frm.Show(this);
this.Activate();
Here's a demonstration:
Note that I used .Show(this) instead of .Show(), that's in order to set the current form as the Owner of the new one, that way we guarantee that the new form will stay on top of the current one. This is equivalent to calling frm.Owner = this; then frm.Show();.
Another way to make sure the form stays on top is by setting the TopMost property instead of the Owner property. However, doing so will make the new form on top of the other windows as well (not just your application).
I've create a list of canvases in wpf, and I have a button click event. I want that when I press the button it will add to the list new canvas. but when I try to change the property of the canvas in another window, it says the index was out of bounds, which means the list didnt add the canvas. I've created a method to check that and indeed it says the index is 0.
I've this with an array also, same here, I change its value but its still wrote the value is 0. this is the code:
public partial class New_Paint : Window
{
public List<Canvas> paintsList = new List<Canvas>();
public Canvas painting = new Canvas();
private void ok_MouseUp(object sender, MouseButtonEventArgs e)
{
paintsList.Add(painting);
this.Close();
}
}
and this is the moethod to check its size:
public int getSize()
{
return paintsList.Count;
}
and here is the code in the main window:
private void button1_Click(object sender, RoutedEventArgs e)
{
textBox1.Text = paint.getSize() + "";
}
the methos return 0 although i click "ok". the list just wont add the items.
I take it you're new at this? Your list of canvases belong to your instance of New_Paint, and you only add one canvas to that list before closing the window (at least in the code you've shown). I don't see why you would expect more than one. You need to have a master list of canvases that is owned by whatever is managing your child windows.
This question is related to this my question. Now I have form in my class and when user click on button I show (or hide) form. That´s ok. But I want to hide form when I move with origin form or when I click somewhere in origin form. The new form is behind that origin form. I was trying events like lostfocus and others but It didn´t help. So I think I need some trick that check from my control if there was click in parrent form (origin form) or some other hack. I know the best would be that I put code but I have many lines so I think that best way will be if you help me in general way and then I try to applicate to my app.
You can do it with a global mouse and keyboard hook. In fact, its been wrapped up into well documented, well structured .NET API over at CodePlex
Go over there and download it. Then, set up a global mouse hook:
_mouseListener = new MouseHookListener(new GlobalHooker());
_mouseListener.MouseMove += HandleGlobalHookMouseMove;
_mouseListener.Start();
The key here is that you will receive the MouseMove event ANY time the mouse moves ANYWHERE on the desktop, not just within the bounds of your window.
private void HandleAppHookMouseMove(object sender, MouseEventArgs e)
{
if (this.Bounds.Contains(e.Location))
{
HandleEnter();
}
else
{
HandleLeave();
}
}
You can also setup one for MouseClick. The combination of the two will enable you to determine any time the mouse moves over your origin form, or the mouse is clicked when its over it. Unlike the LostFocus and other events you tried, focus is irrelevant.
Does below help?
public partial class Form1 : Form
{
Form f2 = new Form2();
public Form1()
{
InitializeComponent();
f2.Show();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (this.ClientRectangle.Contains(e.Location) && f2.Visible) { f2.Hide(); }
}
private void button1_Click(object sender, EventArgs e)
{
f2.Visible = !f2.Visible ? true : false;
}
}
I hard to work for my own transition animation in Frame. But following mysterious problem hit me with deadly deadly damage.
First, here is a sample window. It consists of one frame and one button. Of course it differs to my trunk project, nevertheless, it still showed same problem.
When I clicked the button, the frame navigates to Page1.
EDITED : here is source state of Page1. It was taken in VS2010 IDE.
So, what is problem? - problem is occurring when I call RenderToBitmap() to getting the visual of the destination page. (In this case, destination is the Page1.)
I call RenderToBitmap() with the following code. Here is all of MainWindow's code behind.
public partial class MainWindow : Window
{
public MainWindow() { InitializeComponent(); }
Page1 pg1 = new Page1();
private void Button_Click(object sender, RoutedEventArgs e)
{
this.frame.Navigate(pg1); //start to navigate.
}
private void frame_Navigated(object sender, NavigationEventArgs e)
{
//SaveVisualToPng is my own static method.
WPFHelper.SaveVisualToPng("d:\\a.png", pg1);
}
}
And finally, here is a state of visual when frame_Navigated is called. The TextBox and the TextBlock was rendered, and CheckBox and RadioButton also Rendered. Mysteriously, but, CheckBox and RadioButtons' checked state (notching image and ellipse image) isn't rendered yet.
How can I deal this hell forged problem? Of cause this is a very bit things. But I think this part is a basement of my application, so I want to make flawlessly.
EDITED(2) here is a source of SaveVisualToPng(). Originally it contains a some methods to help work, like GetDPI, but i omitted that. Instead following code make a same result.
public static class WPFHelper
{
public static void SaveVisualToPng(string path, Visual v)
{
int width = Convert.ToInt32(((FrameworkElement)v).ActualWidth);
int height = Convert.ToInt32(((FrameworkElement)v).ActualHeight);
RenderTargetBitmap myBmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
myBmp.Render(v);
if (myBmp != null)
{
PngBitmapEncoder png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(myBmp));
using (Stream stm = System.IO.File.Create(path))
{
png.Save(stm);
}
}
}
}
See if queuing your work on the dispatcher (to give WPF time to render the controls) helps:
private void frame_Navigated(object sender, NavigationEventArgs e)
{
Action save = () => WPFHelper.SaveVisualToPng("d:\\a.png", pg1);
Dispatcher.BeginInvoke(DispatcherPriority.Background, save);
}
Without your WPFHelper implementation I can't test it, but it's worth a try.