Wpf canvas refresh - wpf

I'm wondering if there is a way to refresh canvas before adding a child item to it?
I have this code, it draw me a black ellipse with light blue stroke. Now I want to change StrokeThickness when program is launched (I have a slider to define StrokeThickness). The problem is that StrokeThickness is changed but only if I redraw ellipse, but I want that change is made when I move my slider. Any ideas? Thanks!
//this code is in canvas_MouseDown
double smt = sliderThickness.Value;
//krog
elip = new Ellipse
{
Width = 100,
Height = 100,
Fill = Brushes.Black,
Stroke = Brushes.LightBlue,
StrokeThickness = smt,
};
Canvas.SetLeft(elip, mouseX - 50);
Canvas.SetTop(elip, mouseY - 50);
canvas1.Children.Add(elip);

in slider value Changedevent u have to put following code
private void sliderThickness_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
foreach (var item in canvas1.Children)
{
if (item is Ellipse)
{
var elip = item as Ellipse;
elip.StrokeThickness = sliderThickness.Value;
}
}
}

Or shorter
// using System.Linq;
foreach (var ellipse in canvas1.Children.OfType<Ellipse>())
{
ellipse.StrokeThickness = sliderThickness.Value;
}

Related

Layout Transform changing layout of the controls

I have a LayoutTransformControl in which I have a Grid which contains an image and a Canvas. At some point in the application, on button click I am adding some Thumb controls dynamically inside the Canvas to implement drag and drop. Problem is on click of the same button if I set the Angle for the LayoutTransformControl, I would assume it draws all the Thumb controls first and then flip the Layout control as I am creating my Canvas and Thumbs first, but it seems like it is updating the entire layout and the Thumb controls are moving somewhere beyond the Canvas. Is there a way to first render all my Thumbs first and then change the angle so it just rotates the entire control to that angle.
If the angle is 0 i.e. if I don't apply a transform the Thumb controls appears one below the other as below which is fine.
Here is my problem when I say angle is 270, the Thumb controls move away from canvas.
xaml.cs
private void BtnCapture_Click(object sender, RoutedEventArgs e)
{
BarCodeImage.Height = cnvBarCodeImage.Height = MainLayoutControl.Height=480;
BarCodeImage.Width = cnvBarCodeImage.Width = MainLayoutControl.Width;
//This code will create the canvas.
for (int i = 0; i < 2; i++)
{
var item = Selected.WindowLocations[i];
var dimensionsItem = new Dimensions();
dimensions.Add(new Dimensions()
{
Height = 262,
Width = 142,
Left = 395,
Top = 44,
Text = string.Empty,
});
dimensions.Add(new Dimensions()
{
Height = 106,
Width = 147,
Left = 395,
Top = 342,
Text = string.Empty,
}
CreateThumbs(2, dimensions); //This will create the Thumbs and add to the Canvas
RotateImage(270);
}
private void RotateImage(int Angle)
{
MainLayoutControl.Transform = new RotateTransform()
{
Angle = Angle
};
}
private void CreateThumbs(int numberOfWindows, List<Dimensions> dimensions)
{
ClearOrRemoveAllChildren();
Thumb th = null;
for (int i = 0; i < numberOfWindows; i++)
{
th = new Thumb();
th.Name = i.ToString();
var item = dimensions[i];
th.Width = item.Width;
th.Height = item.Height;
th.Foreground = new SolidColorBrush(Windows.UI.Colors.Transparent);
th.BorderBrush = item.BorderColor;
th.BorderThickness = new Thickness(3);
th.Template = GetThumbTemplate(item.Text);
th.DragDelta += (sender, e) => Th_DragDelta(sender, e, dimensions);
th.DragCompleted += (sender, e) => Th_DragCompleted(sender, e, item.IsImageRotated);
Canvas.SetLeft(th, item.Left);
Canvas.SetTop(th, item.Top);
cnvBarCodeImage.Children.Add(th);
}
}
Here is my xaml
<uwpControls:LayoutTransformControl x:Name="MainLayoutControl" Grid.Row="4" HorizontalAlignment="Center" VerticalAlignment="Center" Width="640">
<Grid x:Name="gridBarImagePanel">
<Image x:Name="BarCodeImage"
RenderTransformOrigin="0.5,0.5"></Image>
<Canvas x:Name="cnvBarCodeImage" AllowDrop="True">
</Canvas>
</Grid>
</uwpControls:LayoutTransformControl>
For canvas, child content is not visually clipped if larger than the panel and is not constrained by the bounds of the panel, so it will be such an effect. You set the height of canvas as 480 and width as 640, when you rotate the content of LayoutTransformControl 270 degrees, the height of LayoutTransformControl is still 480 and the width is 640, but the height of canvas becomes 640, the canvas is beyond the scope of LayoutTransformControl, so the thumbs displays like that.
You can set the height and width of canvas and your image both as 480, in that case, no matter how you rotate the canvas you rotate the canvas, it always in the scope of LayoutTransformControl. Then re-layout the two thumbs.
BarCodeImage.Height = cnvBarCodeImage.Height = MainLayoutControl.Height = 480;
BarCodeImage.Width = cnvBarCodeImage.Width = MainLayoutControl.Width = 480;
Or if you still want to keep the width of 640 and the height of 480, you can re-size the LayoutTransformControl after rotating it.
private void RotateImage(int Angle)
{
MainLayoutControl.Transform = new RotateTransform()
{
Angle = Angle
};
MainLayoutControl.Height = 640;
MainLayoutControl.Width = 480;
}

GridView Docking Issue

I have a gridview and textbox control in my form. Textbox is on left top and under gridview anchored left, right and bottom. I want it saves the distance with textbox above it. This is my code below and it doesn't save the distance between textbox. when i make the window full screen there are so much distance between them as image.
dataGridView1.Anchor = (AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom);
this is what you need
private void Form2_Load(object sender, EventArgs e)
{
//just setting panel color to red. so you can see the panel.
var panel = new Panel() { BackColor= Color.Red};
this.Controls.Add(panel);
panel.Dock = DockStyle.Top;
var textBox = new TextBox() { Top = 20, Left = 20, Height=10, Width=330};
panel.Controls.Add(textBox);
var dataGridView = new DataGridView() ;
dataGridView.Columns.Add("Name","Text");
this.Controls.Add(dataGridView);
dataGridView.AutoGenerateColumns = true;
dataGridView.DataSource = Enumerable.Range(0, 10).ToList();
dataGridView.BringToFront();
dataGridView.Dock = DockStyle.Fill;
}

How to use the slider in WPF to Zoom in and out of an image?

I am trying to use slider to control the Zoom in and Zoom out of any image.
I have written a code:
private void image1_MouseMove(object sender, MouseEventArgs e)
{
if (!image1.IsMouseCaptured) return;
var tt = (TranslateTransform)((TransformGroup)
image1.RenderTransform).Children.First(tr => tr is TranslateTransform);
Vector v = start - e.GetPosition(border1);
tt.X = origin.X - v.X;
tt.Y = origin.Y - v.Y;
}
Here it is working fine. using mouse scroll. But I want to use the slider for the same functioning.
But unable to put the same behaviour like mouse scroll using slider.
I am very new to WPF and its control, so any help with details is highly appreciated.
How can i implement the same finctionality of Zoom in - out using the slider?
After a lot of research and coding I found that its a very simple application and very simple coding too, to Zoomin and Zoomout the image using a slider. what you need is to put a slider in the area of your choice. and put the following code.
private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
TransformGroup transformGroup = (TransformGroup)image1.RenderTransform;
ScaleTransform transform = (ScaleTransform)transformGroup.Children[0];
double zoom = e.NewValue;
transform.ScaleX = zoom;
transform.ScaleY = zoom;
}
Now I already have the code so that the image will Zoomin and Zoomin using the mousewheel.
private void image1_MouseWheel(object sender, MouseWheelEventArgs e)
{
TransformGroup transformGroup = (TransformGroup)image1.RenderTransform;
ScaleTransform transform = (ScaleTransform)transformGroup.Children[0];
double zoom = e.Delta > 0 ? .2 : -.2;
transform.ScaleX += zoom;
transform.ScaleY += zoom;
slider1.Value += zoom;
}
Now when you put
slider1.value += zoom;
Then changes in the mousewheel and in the changes in the slider change the zoom of the picture.
Remember the difference of implementation between mouse wheel and slider. In mouse wheel MouseWheelEventsArgs "e" and e.Delte value is positive and negative depends on the mousewheel up or mousewheel down. But in Slider RoutedPropertyChangesEventsArgs value is positive or negative according to the sldier up and down. You don't need to specify here. Just
zoom = e.NewValue;
I hope it will help.
You have to code a ScaleTransform in your code. This is a part of my code that do this, I don't put everything but it's a base for you.
For the slider, you have to bind the Zoom property to the Value of the Slider.
private double m_dCurZoom = 1.0;
private ScaleTransform m_transZoom;
public ScaleTransform TransZoom
{
get { return m_transZoom; }
}
private TranslateTransform m_transPan;
public double Zoom
{
get { return m_dCurZoom; }
set
{
double oldzoom = m_dCurZoom;
if (m_dCurZoom != value)
{
m_dCurZoom = value;
OnPropertyChanged("Zoom");
UpdateZoom(oldzoom);
}
}
}
public void UpdateZoom(double oldzoom)
{
// Are we visible?
if (m_root == null)
return;
// Get parent
FrameworkElement parent = GetRootParent();
if (parent == null)
return;
// Center point of the window
Point ptCenter = new Point(parent.RenderSize.Width / 2, parent.RenderSize.Height / 2);
// Translate into canvas coordinates
ptCenter = m_root.TranslatePoint(ptCenter, m_canvas);
// Update the zoom
m_transZoom.ScaleX = m_dCurZoom;
m_transZoom.ScaleY = m_dCurZoom;
m_transPan.X -= ptCenter.X * m_dCurZoom - ptCenter.X * oldzoom;
m_transPan.Y -= ptCenter.Y * m_dCurZoom - ptCenter.Y * oldzoom;
ResizeElementContents();
OnPropertyChanged("Zoom");
}

Clear pixels in WPF Canvas

I have a transparent canvas on which I can draw arbitrary polylines with the mouse.
Most of the lines are semi-transparent.
Now I need some kind of an eraser tool, i.e. a polyline with an eraser brush, which allows to clear pixels along the mouse movement.
With an opaque canvas I would simply use the background brush but in this case it is Color.FromArgb(0,0,0,0) and drawing with that has no effect.
The canvas seems to be in some kind of alpha blend mode which blends anything I draw on it with what already exists, unless I set the alpha channel to 255 in which case whatever is on the canvas will be overwritten. That does not help me, as I simply want to clear the pixels, i.e. make them fully transparent.
Any ideas?
Here's the main part of the code I'm using:
public class WPFWindow : Window
{
private Canvas canvas = new Canvas();
private bool LDown = false;
private Polyline lines;
private PointCollection points;
public WPFWindow()
{
this.AllowsTransparency = true;
this.WindowStyle = WindowStyle.None;
this.Background = new SolidColorBrush( Color.FromArgb(50,0,0,0) );
this.Width = 500;
this.Height = 400;
this.Top = this.Left = 0;
canvas.Width = this.Width;
canvas.Height = this.Height;
canvas.Background = new SolidColorBrush( Color.FromArgb(0,0,0,0) );
this.Content = canvas;
this.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler( WPFWindow_MouseLeftButtonDown );
this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler( WPFWindow_MouseLeftButtonUp );
this.MouseMove += new System.Windows.Input.MouseEventHandler( WPFWindow_MouseMove );
}
void WPFWindow_MouseMove( object sender, System.Windows.Input.MouseEventArgs e )
{
if( LDown )
{
points.Add( e.GetPosition(null) );
}
}
void WPFWindow_MouseLeftButtonUp( object sender, System.Windows.Input.MouseButtonEventArgs e )
{
LDown = false;
}
void WPFWindow_MouseLeftButtonDown( object sender, System.Windows.Input.MouseButtonEventArgs e )
{
LDown = true;
lines = new Polyline();
points = new PointCollection();
lines.Stroke = new SolidColorBrush( Color.FromArgb( 128, 180, 80, 80 ) );
lines.StrokeThickness = 20;
lines.Points = points;
points.Add( e.GetPosition(null) );
canvas.Children.Add( lines );
}
}
The WPF Canvas control is not a drawing surface, it's a "Panel", a container that arranges multiple other controls.
Each Polyline you add to the Canvas is actually a FrameworkElement (a kind of lightweight control) and they are all drawn in order (it's like adding multiple labels or edit controls, there is no way a control can change the visual representation of another control on the window except for covering it up).
You may want to create an actual image draw the polylines on the image and display that image, then you can talk about clearing pixels.
Use an InkCanvas instead of polylines. It has an eraser already implemented

C# Winform: How to set the Base Color of a TabControl (not the tabpage)

It seems like a simple question but how do I set the bacground color of the 'tab control', it seems to be derived from the standard window theme color. Is it Possible to create a black tab control with white text written on the tabs themselves (not the tab page)?
Help, I,m a little familiar with custom controls extending existing controls but I don't know what properties (if they exist) to set.
http://dotnetrix.co.uk/tabcontrol.htm
private void tabControl1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
TabPage CurrentTab = tabControl1.TabPages[e.Index];
Rectangle ItemRect = tabControl1.GetTabRect(e.Index);
SolidBrush FillBrush = new SolidBrush(Color.Red);
SolidBrush TextBrush = new SolidBrush(Color.White);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
//If we are currently painting the Selected TabItem we'll
//change the brush colors and inflate the rectangle.
if (System.Convert.ToBoolean(e.State & DrawItemState.Selected))
{
FillBrush.Color = Color.White;
TextBrush.Color = Color.Red;
ItemRect.Inflate(2, 2);
}
//Set up rotation for left and right aligned tabs
if (tabControl1.Alignment == TabAlignment.Left || tabControl1.Alignment == TabAlignment.Right)
{
float RotateAngle = 90;
if (tabControl1.Alignment == TabAlignment.Left)
RotateAngle = 270;
PointF cp = new PointF(ItemRect.Left + (ItemRect.Width / 2), ItemRect.Top + (ItemRect.Height / 2));
e.Graphics.TranslateTransform(cp.X, cp.Y);
e.Graphics.RotateTransform(RotateAngle);
ItemRect = new Rectangle(-(ItemRect.Height / 2), -(ItemRect.Width / 2), ItemRect.Height, ItemRect.Width);
}
//Next we'll paint the TabItem with our Fill Brush
e.Graphics.FillRectangle(FillBrush, ItemRect);
//Now draw the text.
e.Graphics.DrawString(CurrentTab.Text, e.Font, TextBrush, (RectangleF)ItemRect, sf);
//Reset any Graphics rotation
e.Graphics.ResetTransform();
//Finally, we should Dispose of our brushes.
FillBrush.Dispose();
TextBrush.Dispose();
}
I use something like this in mu TabControl derived class (and it will do gradients too):
protected override void OnDrawItem(DrawItemEventArgs e)
{
// fill in the whole rect
using (SolidBrush br = new SolidBrush(Theme.FormBackColor))
{
e.Graphics.FillRectangle(br, ClientRectangle);
}
// draw the tabs
for (int i = 0; i < TabPages.Count; ++i)
{
TabPage tab = TabPages[i];
// Get the text area of the current tab
RectangleF tabTextArea = (RectangleF)GetTabRect(i);
// determine how to draw the tab based on which type of tab it is
Color tabTopBackColor = GetTopBackColor();
Color tabBottomBackColor = GetBottomBackColor();
Color tabTextColor = GetTextColor();
// draw the background
using (LinearGradientBrush br = new LinearGradientBrush(tabTextArea, tabTopBackColor, tabBottomBackColor, LinearGradientMode.Vertical))
{
e.Graphics.FillRectangle(br, tabTextArea);
}
// draw the tab header text
using (SolidBrush brush = new SolidBrush(tabTextColor))
{
e.Graphics.DrawString(tab.Text, Font, brush, CreateTabHeaderTextRect(tabTextArea));
}
}
}
private RectangleF CreateTabHeaderTextRect(RectangleF tabTextArea)
{
tabTextArea.X += 3;
tabTextArea.Y += 1;
tabTextArea.Height -= 1;
return tabTextArea;
}

Resources