I have a Winforms project with a bunch of User controls. I'd like the user control to move itself to be at the 1,1 position relative to its container (whether it's a form or a Panel control). And resize itself to be able to fit half the container.
What event can I respond to in the UserControl to be able to do this without any code having to be written in the container (e.g. the form or panel).
You could use the basic Load event.
The code could be like this:
private void UserControl1_Load(object sender, EventArgs e)
{
Control parent = this.Parent;
if (parent != null)
{
this.Location = new Point(1, 1);
this.Width = (parent.Width / 2);
this.Height = (parent.Height / 2);
}
}
The Paint event should work, unless I'm missing something.
Related
So i'am working with tabControl in windows forms application and i want to make the tabs get full width regardless whether the application window is maximized or not.
When the window isn't maximized everything appears great:
But when the window gets maximized the tabs doesn't get the full width:
Is there any known way to fix this problem?
Thanks in advance
You can achieve this in some way by modifying the ItemSize property as described bellow, else you'd have to draw the tab page selectors yourself.
public Form1()
{
InitializeComponent();
tabControl1.SizeMode = TabSizeMode.Fixed;
tabControl1.ItemSize = new Size((tabControl1.Width / tabControl1.TabPages.Count) - 1, tabControl1.ItemSize.Height);
}
//Hook to form or parent container Resize event, either Resize or ResizeEnd.
private void Form1_ResizeEnd(object sender, EventArgs e)
{
tabControl1.ItemSize = new Size((tabControl1.Width / tabControl1.TabPages.Count) - 1, tabControl1.ItemSize.Height);
}
I have a WPF Application that receive FrameworkElement objects from 3rd party API.
I would like to register events on those objects.
Is this possible? This not working:
public void DisplayControl(FrameworkElement control)
{
control.MouseEnter += new MouseEventHandler(Control_MouseEnter);
control.MouseDown += new MouseButtonEventHandler(Control_MouseDownFromElement);
VideoGrid.Children.Add(control);
}
void Control_MouseDownFromElement(object sender, EventArgs e)
{
lblOutput.Content = string.Format("Sender is: " + sender.ToString());
}
void Control_MouseEnter(object sender, EventArgs e)
{
(sender as FrameworkElement).Focus();
}
One possible reason is the control provider is intentionally blocking that event... you can try adding a control(say grid) on the top of the original control with 0.01 opacity means virtually the control we have added is not visible to the user and we can write all the events on the invisible control...
Update
Something like this... create a grid with opacity 0.01 add events to that grid and add the grid to the video grid after adding your control... so in the video grid there will be control and on the top of the control there will be grid which is invisible because of its opacity and your events will work on the grid... make sure to give same height and width to the grid that match with your control height and width....
Grid grd = new Grid();
grd.Opacity = 0.01;
grd.MouseDown += new MouseButtonEventHandler(Grid_MouseDown_1);
VideoGrid.Children.Add(control);
VideoGrid.Children.Add(grd)
An Adorner is defined over part of an Image. The required behavior is as follows:
When the mouse is over the image area, including the Adorner area, the Adorner appears.
When the mouse leaves the image and Adorner area, the Adorner dissapears.
Adorner appearing and disappearing is to be through a fade in / out animation, accordingly.
A click on the Adorner area must raise event AdornerClicked
A click on the area over the Image which is not hidden by the adorner, must rais ImageClicked.
A naive implementation
Attach an animation on the Adorner opacity on the Image's MouseEnter and MouseLeave events, and attach Click events for each. This however causes the Adorner to disappear when the mouse is directly above it (as a MouseLeave is triggered on the Image below), violating requirement number 1.
A possible amendment to the naive implementation is to set IsHitTestVisible=false on the Adorner. However, no clicks are then captured by the Adorner, violating requirement number 4.
What is the correct pattern which will fulfill the requirements?
A bit old question but I've just had the same problem and could not find an answer so here's what I've come up with.
So the problem is that the control and its adorner are overlapping and setting the adorner to visible triggers a MouseLeave on the adorned control because it is now covered by the adorner.
The solution is to react on every MouseEnter and MouseLeave on both the adorned control and its adorner(s) and do a hit test manually. If any of them are hit then the adorner(s) should be visible otherwise collapsed.
So you need to be able to get the adorners from the adorned control and vica versa. Getting the adorned control from the adorner is no problem (use the AdornedElement property) but getting the adorners for a control is not provided by the framework (AFAIK) so I use a dictionary that maps my controls to a list of their adorners.
Here's the code inside my Panel-derived class (that contains and arranges my controls and their adorners):
private readonly Dictionary<Control, List<Adorner>> _controlToAdornersMap;
...
private void CreateMyControl()
{
var control = new MyControl();
control.MouseEnter += OnMyControlMouseEnterOrLeave;
control.MouseLeave += OnMyControlMouseEnterOrLeave;
Children.Add(control);
AddAdorners(control);
}
private void AddAdorners(Control control)
{
var myAdorner = new MyAdorner(control);
myAdorner.MouseEnter += OnMyAdornerMouseEnterOrLeave;
myAdorner.MouseLeave += OnMyAdornerMouseEnterOrLeave;
var adornerLayer = AdornerLayer.GetAdornerLayer(control);
adornerLayer.Add(myAdorner);
_controlToAdornersMap[control] = new List<Adorner> {myAdorner};
}
private void OnMyControlMouseEnterOrLeave(object sender, MouseEventArgs e)
{
HitTestAndSetAdornersVisibility((MyControl)sender, e);
}
private void OnMyAdornerMouseEnterOrLeave(object sender, MouseEventArgs e)
{
var adorner = (Adorner)sender;
HitTestAndSetAdornersVisibility((MyControl)adorner.AdornedElement, e);
}
private void HitTestAndSetAdornersVisibility(MyControl control, MouseEventArgs e)
{
var adorners = _controlToAdornersMap[control];
var hitTestSubjects = new List<UIElement> { control }.Concat(adorners);
var hit = hitTestSubjects.Any(i => VisualTreeHelper.HitTest(i, e.GetPosition(i)) != null);
SetAdornersVisibility(adorners, hit ? Visibility.Visible : Visibility.Collapsed);
}
private static void SetAdornersVisibility(IEnumerable<Adorner> adorners, Visibility visibility)
{
if (adorners != null)
foreach (var adorner in adorners)
adorner.Visibility = visibility;
}
I have a windows forms window application. Inside the application we want to open a WPF window that is positioned at a location relative to the mouse position. Let's say, that the window center may be displayed at the mouse coordinates, or another case, that the top left corner of the window may be set as being the mouse coordinates.
I've looked at posts like http://www.formatexception.com/2008/09/wpf-and-mouseposition/
but this does not help me, as I don't have a WPF control open before my window. I only have the windows forms, so the folllowing line is not usable in my case
Point mousePoint = Mouse.GetPosition(this);
since you have a winforms control available, you can use Control.MousePosition
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.mouseposition.aspx
Are you showing the wpf window from a winforms form? I wrote a quick test that had a Form with a button. When clicking the button it opened a wpf window at the cursor location. This worked fine and i did not create or show any WPF controls before the button click.
I tried with and without setting WindowStartupLocation and they both worked, but it might be worth a try for you to add it. Here's an example:
private void button1_Click(object sender, EventArgs e)
{
Window w = new Window();
w.WindowStartupLocation = WindowStartupLocation.Manual;
w.Left = Control.MousePosition.X;
w.Top = Control.MousePosition.Y;
w.Show();
}
Though, if the above code sample doesn't work for you then perhaps you could describe your scenario a little bit further and include some code examples?
Building on Bill Tarbell's answer, you may need to account for DPI scaling:
private Point GetScalingFactor(Window window)
{
var zeroPoint = window.PointToScreen(new Point(0, 0));
var hundredPoint = window.PointToScreen(new Point(100, 100));
return new Point(
100.0 / (hundredPoint.X - zeroPoint.X),
100.0 / (hundredPoint.Y - zeroPoint.Y));
}
private void ShowAtCursor(Window parent, Window toShow)
{
var point = parent.PointToScreen(System.Windows.Input.Mouse.GetPosition(parent));
var scaling = GetScalingFactor(parent);
toShow.Left = point.X * scaling.X;
toShow.Top = point.Y * scaling.Y;
toShow.WindowStartupLocation = WindowStartupLocation.Manual;
toShow.Show();
}
Bill Tarbell's answer was not working on my WPF program.
I could not include "using System.Windows.Forms;" somehow...
Could be different project type..
But his answer was very helpful so I put one up vote to him.
and below is the modified code that worked for me.
private void button1_Click(object sender, EventArgs e)
{
Point pointToScreen = PointToScreen(Mouse.GetPosition(this));
Window w = new Window();
w.WindowStartupLocation = WindowStartupLocation.Manual;
w.Left = pointToScreen.X;
w.Top = pointToScreen.Y;
w.Show();
}
I had created a drag and drop control in wpf to drag and drop data between two list boxes which worked as a charm until I moved it to another project.
The difference being It was initially a wpf window and used the window object to get the mouse position and the position of the controls inside.
this.topWindow = Window.GetWindow(this.sourceItemsControl); //Source items control is instance of ItemsControl
bool previousAllowDrop = this.topWindow.AllowDrop;
this.topWindow.AllowDrop = true;
and now I had to change it to a user control instead, since its a part of a bigger project which is a Windows forms project and the views are linked as a Smart Part from the main project. So now the Window object is null.
I looked for a similar functionality for User Control but could not find it..What is it that I am missing out?? I know there should be something..Would appreciate any help on the same..
P.S. : I am using the MVVM architecture
Found the way to find the base User control using recursion, Thanks to ekholm for the heads up..
public static UserControl FindParentControl(DependencyObject child)
{
DependencyObject parent = VisualTreeHelper.GetParent(child);
//CHeck if this is the end of the tree
if (parent == null) return null;
UserControl parentControl = parent as UserControl;
if (parentControl != null)
{
return parentControl;
}
else
{
//use recursion until it reaches a Window
return FindParentControl(parent);
}
}
Now this base user control can be used to find the coordinates (reference) as well as setting other properties like AllowDrop, DragEnter, DragOver etc.
If you need MVVM, than you may examine this solution:
in your .xaml file add:
<ContentControl Content="{Binding Content, Mode=TwoWay}" AllowDrop="True" Name="myDesignerContentControl" />
Than in your ViewModel add the following:
private Panel _content;
public Panel Content {
get { return _content; }
set {
_content = value;
if (_content != null) {
RegisterDragAndDrop();
}
base.RaisePropertyChanged("Content");
}
}
private void RegisterDragAndDrop() {
Content.Drop += OnDrop;
Content.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
Content.PreviewDragOver += OnDragOver;
}
private void OnDesignerDrop(object sender, DragEventArgs e) {
//some custom logic handling
}
private void OnDesignerMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
var control = (FrameworkElement)e.Source;
//some custom logic handling for doing drag & drop
}
private void OnDesignerDragOver(object sender, DragEventArgs e) {
//some custom logic handling for doing drag over
}
The idea is that you should use controls instead of mouse positions, it will be more simple and logical approach. The code above is an example of approach to use in MVVM for having an content area on which you may perform drag and drop of some controls. The idea behind is also suitable for drag and drop data between two list boxes, that you may have on the same content area.
Hope this helps.