Bounds.Intersect for WPF - c#

I have a Winforms app that allows the user to drag and drop some labels around the screen.
The objective being to put the matching labels on top of each other.
I keep a reference to these labels in a list, and at the moment i'm checking to see if they're overlapping by doing the following.
foreach (List<Label> labels in LabelsList)
{
var border = labels[1].Bounds;
border.Offset(pnl_content.Location);
if (border.IntersectsWith(labels[0].Bounds))
{
labels[1].ForeColor = Color.Green;
}
else
{
labels[1].ForeColor = Color.Red;
}
}
The problem being that this is only good for Winforms (Bounds.Intersect). What can I do in WPF to achieve the same result?
If it makes a difference, i'm currently adding both labels to different <ItemsControl> in my view.

So thanks to the comments I was able to do what I needed.
The WPF code now looks like this for all those playing at home:
public void Compare()
{
foreach (List<Label> labels in LabelsList)
{
Rect position1 = new Rect();
position1.Location = labels[1].PointToScreen(new Point(0, 0));
position1.Height = labels[1].ActualHeight;
position1.Width = labels[1].ActualWidth;
Rect position2 = new Rect();
position2.Location = labels[0].PointToScreen(new Point(0, 0));
position2.Height = labels[0].ActualHeight;
position2.Width = labels[0].ActualWidth;
if (position1.IntersectsWith(position2))
{
labels[1].Foreground = new SolidColorBrush(Colors.Green);
continue;
}
labels[1].Foreground = new SolidColorBrush(Colors.Red);
}
}

Related

Trying to make a radio button group with BEMCheckBoxes

I'd like to make a radio button group that will be like this when nothing is checked already using BEMCheckBoxes:
It appears to me that I can't simply add the number in the button.
So I decided to make a view with a label and a checkbox centered in it.
Here is the code I have so far:
// Add An horizontal stackView with check group
UIStackView uIStackView = new UIStackView();
uIStackView.TranslatesAutoresizingMaskIntoConstraints = false;
uIStackView.Axis = UILayoutConstraintAxis.Horizontal;
uIStackView.Alignment = UIStackViewAlignment.Center;
qolEvaluationCard.AddSubview(uIStackView);
uIStackView.Anchor(top: criteria.BottomAnchor, leading: criteria.LeadingAnchor, trailing: criteria.TrailingAnchor, size: new CGSize(0, 32));
BEMCheckBoxGroup bEMCheckBoxGroup = new BEMCheckBoxGroup();
bEMCheckBoxGroups.Add(bEMCheckBoxGroup);
for (int score= 1; score <= 10; score++)
{
var container = new UIView(new CGRect(0, 0, 32, 32));
var label = new UILabel();
label.Text = $#"{score}";
label.TintColor = UIColor.Black;
container.AddSubview(label);
var checkbox = new BEMCheckBox(new CGRect(0, 0, 32, 32));
container.AddSubview(checkbox);
checkbox.BoxType = BEMBoxType.Circle;
checkbox.OnAnimationType = BEMAnimationType.Stroke;
checkbox.Center = label.Center = new CGPoint(container.Frame.Size.Width / 2, container.Frame.Size.Height / 2);
// Transparent BackgroundColor
checkbox.BackgroundColor = null;
checkbox.TintColor = UIColor.Gray;
checkbox.OnTintColor = optimistic_orange;
bEMCheckBoxGroup.AddCheckBoxToGroup(checkbox);
uIStackView.AddArrangedSubview(container);
}
The result is not what I expect but I can't figure out what is wrong:
Why are my checkboxes not transparent to let appear the label?
There is also a problem of distribution within the UIStackView obviously.
Any help appreciated.
The Anchor extension method is:
internal static void Anchor(this UIView uIView, NSLayoutYAxisAnchor top = null, NSLayoutXAxisAnchor leading = null, NSLayoutYAxisAnchor bottom = null, NSLayoutXAxisAnchor trailing = null, UIEdgeInsets padding = default, CGSize size = default)
{
uIView.TranslatesAutoresizingMaskIntoConstraints = false;
if (top != null)
{
uIView.TopAnchor.ConstraintEqualTo(top, padding.Top).Active = true;
}
if (leading != null)
{
uIView.LeadingAnchor.ConstraintEqualTo(leading, padding.Left).Active = true;
}
if (bottom != null)
{
uIView.BottomAnchor.ConstraintEqualTo(bottom, -padding.Bottom).Active = true;
}
if (trailing != null)
{
uIView.TrailingAnchor.ConstraintEqualTo(trailing, -padding.Right).Active = true;
}
if (size.Width != 0)
{
uIView.WidthAnchor.ConstraintEqualTo(size.Width).Active = true;
}
if (size.Height != 0)
{
uIView.HeightAnchor.ConstraintEqualTo(size.Height).Active = true;
}
}
EDIT 1: Just found out with the help of the Reveal tool that My labels size was ambiguous.
var label = new UILabel();
becomes
var label = new UILabel(new CGRect(0, 0, 32, 32));
This solves the 'invisible label' issue.
my answer is Swift codes, but give You concept of works.
I suggest You to break down problem to simple steps.
just try to layout checkboxes (BEMCheckBox) correctly on UIStackView, then create custom View that contain UILabel + BEMCheckBox and now add them to UIStackView and review layout.
Why label not appear on checkbox?
because you add label first, then you put checkbox on it.
container.addSubview(checkbox)
container.addSubview(label)
Setup StackView:
to achive checkboxes horizontal layout
let stackView: UIStackView = {
let stack = UIStackView(arrangedSubviews: customCheckboxes)
stack.spacing = 8
stack.distribution = .fillEqually
stack.axis = .horizontal
stack.alignment = .fill
return stack
}()
then snap stackView to corners using autoLayout or whatever
I think using UIStackView is the best choice, don't use UICollectionView for this simple condition.
How to update label state when checkbox selected?
I didn't use BEMCheckBoxGroup before, but just reviewed source codes and there is a function notifyCheckBoxSelectionChanged trigger when checkbox selection change.
func notifyCheckBoxSelectionChanged(_ checkBox: BEMCheckBox) {
if checkBox.on {
// Change selected checkbox to this one
selectedCheckBox = checkBox
} else if checkBox == selectedCheckBox {
// Selected checkbox was this one, clear it
selectedCheckBox = nil
}
}
but it's not pubic, selectedCheckBox is what you need to know about this group. I think you should add target on valueChanged to this group, I don't see any public API to delegate user selection of checkboxes!

Buttons are two pixels too small

I have been working with windows forms for a short while and have noticed that button controls always appear one pixels smaller in each direction than I am trying to make them.
To illustrate, the TextBoxes and Button in the image bellow are set to the exact same size but are different sizes.
wrong size buttons
Here is the code that I used to generate the buttons:
public Form1() {
InitializeComponent();
this.Size = new Size(216, 239)
TB1 = new TextBox();
TB1.Multiline = true;
TB1.Size = new Size(100, 100);
TB1.Location = new Point(100, 0);
Controls.Add(TB1);
TB2 = new TextBox();
TB2.Multiline = true;
TB2.Size = new Size(100, 100);
TB2.Location = new Point(0, 100);
Controls.Add(TB2);
TestButton = new Button();
TestButton.Text = "sdfsdf";
TestButton.Size = new Size(100, 100);
TestButton.Location = new Point(100, 100);
Controls.Add(TestButton);
}
From the Image you can see that there is white space around the button. I have tried changing the Control.Margin and Control.Padding but this extra space around the button is unaffected by those.
In order to make the button appear 100x100 (the way I want it) you have to move it one pixel up and to the left and make it two pixels wider and taller. (TextButton.Size = new Size(102, 102); TextButton.Location = new Point(99, 99);)
What I would like to do is make the buttons actually the size I set them to be. Because of the number of buttons in my program, it is undesirable to manually increase the size of each button and I am looking for a more elegant long term solution that I can use going forwards.
I have tried to create a wrapper class around the button class called MyButton but it doesn't work with polymorphism (explained bellow):
class MyButton : Button {
public MyButton() : base() {}
public new Size Size {
get;
set {
int width = value.Width + 2; // make it two wider
int height = value.Height + 2; // make it two taller
Size size = new Size(width, height);
base.Size = size;
}
}
public new Point Location {
get;
set {
Console.WriteLine("running"); // used to make sure this is actually being run
int x = value.X - 1; // move it one left
int y = value.Y - 1; // move it one up
Point point = new Point(x, y);
base.Location = point;
}
}
}
When I create a MyButton object and use myButtonObject.Size = ... it works perfectly and the button sizing and location works out. However, at another place in my code I have a function that takes a Control object as input and here my code from the MyButton class is not being used.
MyButton btn1 = new MyButton();
btn1.Size = new Size(100, 100);
btn.Location = new Point(100, 100);
// ^ this works great and the button is the right size
public void ControlFormatter(Control control) {
control.Size = new Size(100, 100);
control.Location = new Point(100, 100);
}
MyButton btn2 = new MyButton();
ControlFormatter(btn2);
// ^ this doesn't work
Using the Console.WriteLine("running") print statement that I put in MyButton.Location.Set, I can tell that when control.Location is called inside ControlFormatter() the code that I wrote is not run (I can only assume that it is using the default Control.Location property and thus making the buttons the wrong size.
I guess I'm asking two things
Is there an easier/better/cleaner way to make the buttons the right size?
How can I make it so that ControlFormatter() uses MyButton.Size when it can and not Control.Size?
Thanks, also I'm fairly new to C# so grace is appreciated.
I opted for the quicker and dirtier fix of testing whether or not the Control was a Button in my ControlFormatter() function.
public void ControlFormatter(Control control) {
int width = 100;
int height = 100;
if (control is Button) {
width -= 2;
height -= 2;
}
control.Size = new Size(width, height);
control.Position = new Point(); // you get the jist
}

Dynamic panel element adding and scrollbars

I wrote a function to dynamically add elements to the "Panel".
public int State;
public Point Point = new Point(0, 0);
public void DialogAdd(string message, string author)
{
var d = new DialogMessage();
if(State == 0)
{
d.BackColor = Color.FromArgb(255, 237, 241, 245);
State = 1;
}
else
{
State = 0;
}
d.Controls["name"].Text = author;
d.Location = new Point(0, Point.Y);
d.Controls["msg"].Text = message;
Point.Y += d.Size.Height;
Controls["panel1"].Controls.Add(d);
}
DialogMessage is UserControl, that haves property "AutoSize=true" on all components.
This panel has got the AutoScroll property, so has got scrollbars.
The problem is that the elements are added in different ways, depending on the position of the scrollbar. If the scrollbar is at the top, then all added as needed.
but if at the time of adding the scrollbar at the bottom, then add items going wrong
please tell me what I'm doing wrong and how to fix it? Thank you. sorry for bad english
When placing the controls inside the panel, you have to compensate for the scroll position:
Basically, try using this line:
d.Location = new Point(0, panel1.AutoScrollPosition.Y + Point.Y);

(Composite) Geometry confusion in c#

I'm trying to create 1 complex composite shape on an InkCanvas, but I must be doing something wrong, as what I was expecting to happen, is not. I've tried several different incarnations of accomplishing this.
So I have this method.
private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
Stroke stroke = e.Stroke;
// Close the "shape".
StylusPoint firstPoint = stroke.StylusPoints[0];
stroke.StylusPoints.Add(new StylusPoint() { X = firstPoint.X, Y = firstPoint.Y });
// Hide the drawn shape on the InkCanvas.
stroke.DrawingAttributes.Height = DrawingAttributes.MinHeight;
stroke.DrawingAttributes.Width = DrawingAttributes.MinWidth;
// Add to GeometryGroup. According to http://msdn.microsoft.com/en-us/library/system.windows.media.combinedgeometry.aspx
// a GeometryGroup should work better at Unions.
_revealShapes.Children.Add(stroke.GetGeometry());
Path p = new Path();
p.Stroke = Brushes.Green;
p.StrokeThickness = 1;
p.Fill = Brushes.Yellow;
p.Data = _revealShapes.GetOutlinedPathGeometry();
selectionInkCanvas.Children.Clear();
selectionInkCanvas.Children.Add(p);
}
But this is what I get:
http://img72.imageshack.us/img72/1286/actual.png
So where am I going wrong?
TIA,
Ed
The problem is that the Geometry returned by stroke.GetGeometry() is a path around the stroke, so the area you're filling with yellow is just the middle of the stroke. You can see this more clearly if you make the lines thicker:
_revealShapes.Children.Add(stroke.GetGeometry(new DrawingAttributes() { Width = 10, Height = 10 }));
You can do what you want if you convert the list of stylus points to a StreamGeometry yourself:
var geometry = new StreamGeometry();
using (var geometryContext = geometry.Open())
{
var lastPoint = stroke.StylusPoints.Last();
geometryContext.BeginFigure(new Point(lastPoint.X, lastPoint.Y), true, true);
foreach (var point in stroke.StylusPoints)
{
geometryContext.LineTo(new Point(point.X, point.Y), true, true);
}
}
geometry.Freeze();
_revealShapes.Children.Add(geometry);

listview item cut style in .NET?

How do I achieve the equivalent of the LVIS_CUT style for a listview item? It looks like it's not exposed by the framework? Should I P/Invoke?
Edit: LVIS_CUT is a Win32 style that affects the look of the item: It grays the item image. You can see it in action in Windows Explorer: Select a file and type Ctrl+X.
TIA.
Well, one way to "achieve the equivalent of the LVIS_CUT style" would be the following:
Use a function along the lines of
private void MakeCutList(ImageList sourceList, Color background)
{
Brush overlay = new SolidBrush(Color.FromArgb(128, BackColor));
Rectangle rect = new Rectangle(new Point(0, 0), sourceList.ImageSize);
foreach (Image img in sourceList.Images)
{
Bitmap cutBmp = new Bitmap(img.Width, img.Height);
using (Graphics g = Graphics.FromImage(cutBmp))
{
g.DrawImage(img, 0, 0);
g.FillRectangle(overlay, rect);
}
sourceList.Images.Add(cutBmp);
}
}
to take the image list used by your ListView (i.e. listView1.ImageList) and add the "cut" versions of all the icons. You might call this immediately after InitializeComponent in your form, like
public Form1()
{
InitializeComponent();
MakeCutList(listView1.LargeImageList, listView1.BackColor);
}
Then you could use code like this
private void SetCutState(ListViewItem lvi, Boolean isItemCut)
{
int originalListSize = lvi.ImageList.Images.Count / 2;
int baseIndex = lvi.ImageIndex % originalListSize;
int cutImagesOffset = originalListSize;
if (isItemCut)
{
lvi.ImageIndex = cutImagesOffset + baseIndex;
lvi.ForeColor = SystemColors.GrayText;
}
else
{
lvi.ImageIndex = baseIndex;
lvi.ForeColor = SystemColors.WindowText;
}
}
to change the state of an item to being cut or not.
Once you get that working, you could try to put similar code into a subclassed version of the ListView control.
Are you referring to when it's grayed out? Like when you do a "cut" on it? If so, I would just set the forecolor to Inactive or something along those lines. Not sure that you need to pinvoke for something like that.
I used this for my file explorer application ..
private void MakeCutItem()
{
foreach (ListViewItem item in listView1.SelectedItems)
{
Image img = item.ImageList.Images[item.ImageIndex];
Brush overlay = new SolidBrush(Color.FromArgb(128, BackColor));
Rectangle rect = new Rectangle(new Point(0, 0), item.ImageList.ImageSize);
using (Graphics g = Graphics.FromImage(img))
{
g.FillRectangle(overlay, rect);
}
item.ImageIndex = item.ImageList.Images.Add(img,Color.Empty);
}
}

Categories

Resources