Dynamic Border configuration in WPF - c#

I am using drag and drop functionality in an application and I need to change the look of a Grid based on the location of the drag point.
For example, I would like to be able to call something like the following that would change the border to only show the bottom, or the top,etc. This example would be that when there is a drag operation performed over Grid, the top border of the grid would be the only one set to a thickness of 5 and would be black.
private void Grid_DragOver(object sender,DragEventArgs e)
{
Grid grid = (Grid)sender;
Border border = new Border();
border.BorderBrush = Brushes.Black;
border.BorderThickness = new Thickness(0,5,0,0);
border.Child = grid;
}

http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.margin.aspx
Edit: Border color http://msdn.microsoft.com/en-us/library/system.windows.controls.border.borderbrush.aspx

Related

WPF - Setting corner radius in code behind

I want to bring a some rectangles to my WPF-Pages, these Rectangles should have rounded corners. To bring a few of the rectangles to the page without having to write every single one in xaml I decided to do it with a loop in the code.
I tried this one:
for (int i = 0; i < 5; i++)
{
Rectangle rect = new Rectangle();
rect.Fill = System.Windows.Media.Brushes.Green;
var style = new Style(typeof(Border));
style.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(12.0, 0, 0 , 0)));
rect.Resources.Add(typeof(Border), style);
Grid.SetColumn(rect, 1);
Grid.SetRow(rect, 1);
mainGrid.Children.Add(rect);
}
but the corner radius of my rectangles won´t change. Do you have any suggestion?
Thanks for your help in advance!
To bring a few of the rectangles to the page without having to write every single one in xaml
Good problem to solve.
I decided to do it with a loop in the code
Absolutely bad solution. Use proper MVVM with an <ItemsControl> bound to your list of objects you're trying to display, stored in your view model. And then create a global style sheet and apply it to this either automatically or manually.
Anyway to answer your question, you're creating an unnamed style on Border and applying it to a Rectangle. That will never auto-apply, and good thing, because you reference Border.CornerRadiusProperty which doesn't exist on a Rectangle.
You want to either make your style override the Rectangle's template and add a Border around it, then set its corner border radius, or manually add the border above the rectangle and set its corner radius in your setter (only add the style to the Border's resources).
Your code doesn't really make sense to me though, Rectangle also has corner radius properties, RadiusX and RadiusY, you could just set those if that's what you want.
The rectangle is overflowing. If you do the same thing with a border it will work. When you add the rectangle inside the border you can see what its doing
Rectangle rect = new Rectangle();
rect.Fill = System.Windows.Media.Brushes.Green;
Border b = new Border();
b.Width = 100;
b.Height = 100;
b.Background = Brushes.White;
b.CornerRadius= new CornerRadius(12, 0, 0, 0);
b.BorderThickness = new Thickness(2);
b.BorderBrush = Brushes.Red;
b.Child = rect;//adding this rectangle will show you how the corner is overflowing
grid_Main.Children.Add(b);

Recoloring TabControl

I have a tab control which I want to customize. To be more specific, I want to change the color of the tab page header, as well as the color of that white line around the tab page (check first picture).
I thought of using a custom renderer to do this (similar to recoloring a menu strip, for example), but I'm not sure how to do this. I've also read that setting the DrawMode to OwnerDrawFixed may do this, but using this option makes the the tab control look as if my program was made in the '90s (check second picture).
What I really want to do is to keep the tabs simple and flat and change their color. Check the way tabs are in Visual Studio as an example (check third picture).
Any ideas?
Edit: Another picture of the tab page so that it's more clear what this "white line" is.
When you use OwnerDrawFixed it means you will supply the drawing code. If you did not hook up and use the DrawItem event, nothing gets drawn. This will look much the same as yours at design time, because the event is not firing. For design time painting, you'd have to subclass the control and use OnDrawItem.
// colors to use
private Color[] TColors = {Color.Salmon, Color.White, Color.LightBlue};
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
// get ref to this page
TabPage tp = ((TabControl)sender).TabPages[e.Index];
using (Brush br = new SolidBrush(TColors[e.Index]))
{
Rectangle rect = e.Bounds;
e.Graphics.FillRectangle(br, e.Bounds);
rect.Offset(1, 1);
TextRenderer.DrawText(e.Graphics, tp.Text,
tp.Font, rect, tp.ForeColor);
// draw the border
rect = e.Bounds;
rect.Offset(0, 1);
rect.Inflate(0, -1);
// ControlDark looks right for the border
using (Pen p = new Pen(SystemColors.ControlDark))
{
e.Graphics.DrawRectangle(p, rect);
}
if (e.State == DrawItemState.Selected) e.DrawFocusRectangle();
}
}
basic result:
The tab thumb looks a bit cramped to me and not as tall as the default. So, I added a TFontSize to draw the text at a different size than the Font.
Set the TabControl.Font to 10 (which seems to be plenty), so that Windows draws a slightly larger thumb/header. If you still draw the text at the default 8.25, there is more room:
private float TFontSize = 8.25F; // font drawing size
...
using (Font f = new Font(tp.Font.FontFamily,TFontSize))
{
// shift for a gutter/padding
rect.Offset(1, 1);
TextRenderer.DrawText(e.Graphics, tp.Text,
f, rect, tp.ForeColor);
}
One thing you will loose this way is the VisualStyles effect, but they would seem to clash with colored tabs anyway.

ListView with background image and custom cell colors

I have a listview that uses custom cell colors, but when I set a background image in the listview, the custom cell colors will not appear anymore. I tried to remove the background image temporarily (when assembling the list) and restore it after applying cell colors. This results in no custom colors but shows the background. I would like to combine these 2 listview properties if possible.
My code for setting/removing background image:
list.BackgroundImage = Properties.Resources.bgalpha;
list.BackgroundImage = null;
A part of my code for setting custom cell colors:
for (int i = 0; i < kavels.Count(); i++ )
{
if (list.Items[i].SubItems[1].Text != "0")
{
list.Items[i].UseItemStyleForSubItems = false;
list.Items[i].SubItems[1].BackColor = Color.LightGreen;
}
}
Here are two screenshots:
List view with background: http://i.imgur.com/aHUXAVh.png
List view without background: http://i.imgur.com/sO83wTP.png
I also tried making a PictureBox with a transparent background along with a png image with transparency on top of the ListView, but that also didn't work obviously.
You have two options:
You could overlay a Panel or a PictureBox with a semi-transprent Image. For this to work you would have to make it sit inside the ListView, so that it is the Parent of the overlay.
But that will make the Listview non-clickable. - Another problem with this is that it will slightly color the text, so it won't look quite right.
Or you can set the ListView to OwnerDraw = true and add code to do the drawing yourself.
Here is an example, non-scrolled and scrolled:
Note that the original BackgroundImage shines through the emtpy space to the right.
If you owner-draw a ListView in Details mode you need to code events to draw subitems and headers; note the class level variable to hold the itemHeight; this assumes they all have the same Height .. The other one is need for horizontal scrolling.
int itemHeight = 0; // we need this number!
int itemLeft = 0; // we need this number, too
private void listView1_DrawColumnHeader(object sender,
DrawListViewColumnHeaderEventArgs e)
{
Rectangle R0 = listView1.GetItemRect(0);
itemHeight = R0.Height; // we need this number!
itemLeft = R0.Left; // we need this number too
e.DrawBackground();
e.DrawText();
}
private void listView1_DrawSubItem(object sender,
DrawListViewSubItemEventArgs e)
{
Rectangle rrr = listView1.GetItemRect(e.ItemIndex);
Rectangle rect = e.Bounds;
Rectangle rect0 = new Rectangle(rect.X - itemLeft , itemHeight * e.ItemIndex,
rect.Width, rect.Height);
Image img = listView1.BackgroundImage;
e.Graphics.DrawImage(img, rect, rect0, GraphicsUnit.Pixel);
using (SolidBrush brush = new SolidBrush(e.SubItem.BackColor))
e.Graphics.FillRectangle(brush, rect);
e.DrawText();
}
Here is the code to set the colors in the ListViewItem lvi for the example:
lvi.UseItemStyleForSubItems = false;
lvi.BackColor = Color.FromArgb(66, Color.LightBlue);
lvi.SubItems[1].BackColor = Color.FromArgb(77, Color.LightGreen);
lvi.SubItems[2].BackColor = Color.FromArgb(88, Color.LightPink);
Note that the code assumes your background is one large image and no tiling is involved! Also the code works only if you don't have groups!
ObjectListView -- an open source wrapper around a standard .NET ListView -- provides ImageOverlays and true background images too. They both work with colour cells.

Program crashes after adding a Border to a Textblock

I have a little problem. I am enabling the user to choose the size of a textblock in which he is able to display text by doing some other stuff.
My problem here is that I have to add a border to the textblock to show the user how big it became.
When I applied the following code, my program just crashes in that scenario:
//create a TextBlock at desired position
TextBlock tmpTextBlock = new TextBlock
{
Width = 166,
Height = Math.Max(tmpY1, tmpY2) - Math.Min(tmpY1, tmpY2),
VerticalAlignment = VerticalAlignment.Top,
Margin = new Thickness(0, Math.Min(tmpY1, tmpY2) - 50, 0, (int)WeekGrid.ActualHeight - Math.Max(tmpY1, tmpY2)),
Text = "Type stuff here"
};
tmpTextBlock.Holding += tmpTextBox_Holding;
tmpTextBlock.RightTapped += tmpTextBox_RightTapped;
WeekGrid.Children.Add(tmpTextBlock);
Grid.SetRow(tmpTextBlock, 1);
//add the border - these lines produce the problem
Border border = new Border
{
Child = tmpTextBlock,
Background = this.Resources["ApplicationPageBackgroundThemeBrush"] as SolidColorBrush,
BorderBrush = this.Resources["ApplicationForegroundThemeBrush"] as SolidColorBrush,
BorderThickness = new Thickness(1),
};
The Exception that follows is an argument exception:
Value does not fall within the expected range.
EDIT
Whoops I've solved that problem. I had to remove adding the Textblock into the grid.
The problem I have now is that the border appears around the grid - not around the textblock!
The following code made that possible:
Border border = new Border
{
Child = tmpTextBlock,
Background = this.Resources["ApplicationPageBackgroundThemeBrush"] as SolidColorBrush,
BorderBrush = this.Resources["ApplicationForegroundThemeBrush"] as SolidColorBrush,
BorderThickness = new Thickness(1),
Padding = new Thickness(24)
};
WeekGrid.Children.Add(border);
Grid.SetRow(border, 1);
EDIT 2
Problem solved again.
I of course had to remove the margin setting of the textblock!
Thank you very much!
Greetings,
FunkyPeanut
Could you post the exception?
clearly there is an error in your code here:
WeekGrid.Children.Add(tmpTextBlock);
Grid.SetRow(tmpTextBlock, 1);
//add the border - these lines produce the problem
Border border = new Border
{
Child = tmpTextBlock,
Background = this.Resources["ApplicationPageBackgroundThemeBrush"] as SolidColorBrush,
BorderBrush = this.Resources["ApplicationForegroundThemeBrush"] as SolidColorBrush,
BorderThickness = new Thickness(1),
};
The component Border it is like a "container", which accepts a single element, you should switch to:
Border border = new Border
{
Child = tmpTextBlock,
Background = this.Resources["ApplicationPageBackgroundThemeBrush"] as SolidColorBrush,
BorderBrush = this.Resources["ApplicationForegroundThemeBrush"] as SolidColorBrush,
BorderThickness = new Thickness(1),
};
WeekGrid.Children.Add(border);
Grid.SetRow(border, 1);
You should also check if the resources are "available" for your access.

Setting an overlay background panel on a dynamic Grid

Right, so I'm drawing what looks like a DataGrid on a standard WPF Grid panel.
The content controls are essentially TextBlock controls inside Border controls at Grid row and column references to create the overall layout, added at runtime and using the usual Grid.SetRow() and Grid.SetColumn() methods
Not every X and Y grid reference has a content control - this is determined by a runtime definition of the data for the grid. I use offset values to mark whether an XY pair is part of the "headers" of the rows/columns or whether the grid reference is part of the "data" section.
I am trying to put a gradient background across the whole of the "data" section. I was using a Grid control with the gradient brush set as follows:
//Grey background to show for "grey cells"
Grid greyBackground = new Grid()
{
Background = (Brush)this.Resources["BackgroundBrush"],
VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
Width = double.NaN,
Height = double.NaN,
};
greyBackground.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
greyBackground.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
Grid.SetColumn(greyBackground, _vm.Definition.ColumnOffset);
Grid.SetRow(greyBackground, _vm.Definition.RowOffset);
Grid.SetColumnSpan(greyBackground, _vm.Definition.Columns - _vm.Definition.ColumnOffset);
Grid.SetRowSpan(greyBackground, _vm.Definition.Rows - _vm.Definition.RowOffset);
cellGrid.Children.Add(greyBackground);
This however is not visible at all. And I have no idea why.
Any idea how I can display a gradient background painted control over these row/column locations, underneath the other "data" controls?

Categories

Resources