How to paint a specific cell of a stackpanel? - wpf

In order to draw the matrix of cells , I used a Stackpanel, defined by this code:
int columns = Convert.ToInt32(columnasText.Text);
int rows = Convert.ToInt32(filasText.Text);
SolidColorBrush selected1 = new SolidColorBrush(Colors.Aquamarine);
SolidColorBrush released = new SolidColorBrush(Colors.White);
for (int i = 0; i < rows; i++)
{
StackPanel stkPanel = new StackPanel();
stkPanel.Orientation = Orientation.Horizontal;
for (int j = 0; j < columns; j++)
{
Label lbl = new Label();
lbl.Height = rejilla.Height / rows;
lbl.Width = rejilla.Width / columns;
lbl.Tag = new Point(i, j);
lbl.BorderBrush = new SolidColorBrush(Colors.Black);
lbl.BorderThickness = new Thickness(1);
lbl.Background = released;
stkPanel.Children.Add(lbl);
}
rejilla.Children.Add(stkPanel);
Once is defined, I need to change the colours of each cell depending on the values of each, and I'm not able to do it.

I used your variable rejilla (I am assuming it is either StackPanel or Grid). Either way, it will work.
Method 1:
The key is using .Children.OfType()
//Get your cell location
int rowIndex = 2;
int columnIndex = 8;
//Get your desired new color
SolidColorBrush selected1 = new SolidColorBrush(Colors.Aquamarine);
//Get list of your row panels
var stackPanels = rejilla.Children.OfType<StackPanel>().ToList();
//Check if desired row panel exist
if (rowIndex < stackPanels.Count && rowIndex >= 0)
{
//Get list of your labels in the desired row panel
var labels = stackPanels[rowIndex].Children.OfType<Label>().ToList();
//Check if desired cell exist or not then change background
if (columnIndex < labels.Count && columnIndex >= 0)
labels[columnIndex].Background = selected1;
}
Method 2: Using your Tag that you set (Point)
Not recommended, this method would have been useful if you placed all your labels in one stack panel instead of placing them in multiple stack panels (one stack panel for each row).
//Get your cell location
int rowIndex = 2;
int columnIndex = 8;
//Get your desired new color
SolidColorBrush selected1 = new SolidColorBrush(Colors.Aquamarine);
//Get list of your row panels
var stackPanels = rejilla.Children.OfType<StackPanel>().ToList();
//Check if desired row panel exist
if (rowIndex < stackPanels.Count && rowIndex >= 0)
{
//Get list of your labels in the desired row panel
var label = stackPanels[rowIndex].Children.OfType<Label>()
.Where(Item => (int)(Item.Tag as Nullable<Point>).GetValueOrDefault().X == rowIndex
&& (int)(Item.Tag as Nullable<Point>).GetValueOrDefault().Y == columnIndex).FirstOrDefault();
if(label != null)
label.Background = selected1;
}
You can place the code inside a method and pass your stackPanel, color, rowIndex, columnIndex:
private void SetCellColor(StackPanel stackPanel, SolidColorBrush color, int rowIndex, int columnIndex)
{
//Get list of your row panels
var stackPanels = stackPanel.Children.OfType<StackPanel>().ToList();
//Check if desired row panel exist
if (rowIndex < stackPanels.Count && rowIndex >= 0)
{
//Get list of your labels in the desired row panel
var labels = stackPanels[rowIndex].Children.OfType<Label>().ToList();
//Check if desired cell exist or not then change background
if (columnIndex < labels.Count && columnIndex >= 0)
labels[columnIndex].Background = color;
}
}
Then call it:
SetCellColor(rejilla, new SolidColorBrush(Colors.Aquamarine), rowIndex, columnIndex);
Good Luck!

Related

In WPF, How can I use different style of series in one cartesian chart?

For information, I'm using Live charts library.
What I want to make is a chart column chart with reference information.
The result is going to be like below.
What I planned to do is using column chart and step line chart.
And when I run, the result is only showing column charts.
Even Step line series data is also shown as column.
How can I show different styles in one chart?
This is my Xaml Code.
<ScrollViewer HorizontalScrollBarVisibility="Visible" Width="1200" >
<lvc:CartesianChart Name="MainChart" Series="{Binding Path=MainData}" Width="{Binding Path=MainChartWidth}">
<lvc:CartesianChart.DataTooltip>
<lvc:DefaultTooltip SelectionMode="OnlySender"/>
</lvc:CartesianChart.DataTooltip>
<lvc:CartesianChart.AxisX>
<lvc:Axis Name="XAxis" Labels="{Binding Path=MainDataLabel}" ></lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</ScrollViewer>
And this is code behind related to question.
for (int idx = 0; idx < MainDataTable.Columns.Count; idx++)
{
List<string[]> tmpList = new List<string[]>();
else if (idx == 1)
{
string[] tmpArray = new string[3];
StepLineSeries tmpLineSeries = new StepLineSeries();
List<int> tmpDataList = new List<int>();
tmpLineSeries.Title = MainDataTable.Columns[idx].ColumnName;
tmpLineSeries.Fill = Brushes.Transparent;
tmpLineSeries.PointGeometry = null;
tmpLineSeries.Width = 10;
tmpLineSeries.StrokeThickness = 10;
for (int rowCnt = 0; rowCnt < MainDataTable.Rows.Count; rowCnt++)
{
tmpDataList.Add(Int32.Parse(MainDataTable.Rows[rowCnt][idx].ToString()));
}
tmpLineSeries.Values = new ChartValues<int>(tmpDataList);
MainData.Add(tmpLineSeries);
}
else if (idx > 1) // (idx > 0)
{
string[] tmpArray = new string[3];
ColumnSeries tmpLineSeries = new ColumnSeries();
List<int> tmpDataList = new List<int>();
tmpLineSeries.Title = MainDataTable.Columns[idx].ColumnName;
tmpLineSeries.Stroke = new SolidColorBrush(searchCondition.getConditionColor(MainDataTable.Columns[idx].ColumnName));
tmpLineSeries.Width = 15;
for (int rowCnt = 0; rowCnt < MainDataTable.Rows.Count; rowCnt++)
{
tmpDataList.Add(Int32.Parse(MainDataTable.Rows[rowCnt][idx].ToString()));
}
tmpLineSeries.Values = new ChartValues<int>(tmpDataList);
MainData.Add(tmpLineSeries);
}
}
Thank you.

FinalSize in ArrangeOverride is coming wrong

I'm doing a custom panel, based(heriting) the WrapPanel.
I'm doing this because some UserControls I'm using in the WrapPanel don't wrap because they are able to use an "infinite" width, so a WrapPanel with a vertical orientation will never wrap.
I wanted to do one WrapPanel that ignore the width of the elements when having orientation = Vertical, and ignore the height of the elements when having an orientation = Horizontal.
Currently I've the following code:
protected override Size ArrangeOverride(Size finalSize)
{
int numberOfColumns, numberOfRows;
UIElement uiElement = InternalChildren.OfType<UIElement>().First();
if (Orientation == Orientation.Horizontal)
{
double desiredWidth = uiElement.DesiredSize.Width;
numberOfColumns = (int)Math.Round(finalSize.Width / desiredWidth);
numberOfRows = (int)Math.Ceiling(InternalChildren.Count / (double)numberOfColumns);
}
else
{
double desiredHeight = uiElement.DesiredSize.Height;
numberOfRows = (int)Math.Round(finalSize.Height / desiredHeight);
numberOfColumns = (int)Math.Ceiling(InternalChildren.Count / (double)numberOfRows);
}
int row = 0, column = 0;
Size elementSize = new Size(Math.Floor(finalSize.Width / numberOfColumns), Math.Floor(finalSize.Height / numberOfRows));
foreach (UIElement child in InternalChildren)
{
child.Arrange(new Rect(new Point(row * elementSize.Width, column * elementSize.Height), elementSize));
if (Orientation == Orientation.Horizontal)
{
column++;
if (column >= numberOfColumns)
{
column = 0;
row++;
}
}
else
{
row++;
if (row >= numberOfRows)
{
row = 0;
column++;
}
}
}
return finalSize;
}
The issue is that the finalSize that I receives is bigger than the "ActualSize" of the component(Width 2x the actualSize in fact).
What did I miss?

How can i capture screen region while not focusing wpf app?

I have a WPf application that monitors a certain region on screen keeping track of the count of pixels with certain colors.
What i want is the actual capturing of the region and reading of values to happen in another thread, but i cant seem to wrap my head around how to actuale grab the region while i focus another window.
Here is some code:
// Colors to keep track of
var fooColor = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString("#FF6ebfe2");
var barColor = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString("#FFe67e6e");
// previewWindow : Rectangle Control
var X = (int)previewWindow.PointToScreen(new System.Windows.Point(0, 0)).X;
var Y = (int)previewWindow.PointToScreen(new System.Windows.Point(0, 0)).Y;
Rectangle rect = new Rectangle(X, Y, (int)previewWindow.ActualWidth, (int)previewWindow.ActualHeight);
Bitmap bmp = new Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (var screenBmp = new Bitmap(
rect.Width,
rect.Height,
System.Drawing.Imaging.PixelFormat.Format32bppArgb)
)
{
using (var bmpGraphics = Graphics.FromImage(screenBmp))
{
bmpGraphics.CopyFromScreen(X, Y, 0, 0, screenBmp.Size);
BitmapSource bmpSource = Imaging.CreateBitmapSourceFromHBitmap(
screenBmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
var red = 0;
var blue = 0;
for (int i = 0; i < rect.Width; i++)
{
for (int x = 0; x < rect.Height; x++)
{
System.Windows.Media.Color color = GetPixelColor(bmpSource, i, x);
if (color == fooColor)
{
blue++;
}
else if (color == barColor)
{
red++;
}
}
}
txtbar.Text = red.ToString();
txtfoo.Text = blue.ToString();
if (red < 150)
{
ProcessBar();
}
if (blue < 150)
{
ProcessFoo();
}
}
}

How to implement ScintillaNET column edit mode

I need a text editor control for column edit in my application.
Like notepad++ alt+mouse drag to select a text block , or pull down a long vertical cursor and press a key to insert a char to every lines over cursor.
I tried ScintillaNET but it not suppor the column-modet for insert, just can remove selected text block
I need below effect(notepad++), But ScintillaNET got:
I found a way to solve. Still using ScintillaNET.
But coding not enough beauty :)
class SelWrap
{
public int Begin { get; set; }
public int Length { get; set; }
}
//...
editor.KeyDown += (s, e) =>
{
// filter alt we will hold down alt to make vertical selection
if (e.Alt) return;
var tb = editor;
if (tb.Selections.Count < 2) return; // no in column mode
e.SuppressKeyPress = true; //block input, handle by below code
//refered from post #5825820
var input = Utility.GetCharFromKey(e.KeyCode).ToString();
if (input == "\0")
{
//SystemSounds.Beep.Play();
return;
}
var array = tb.Selections
.OrderBy(p => p.Start)
.Select(p => new SelWrap{Begin=p.Start, Length=p.End - p.Start })
.ToArray();
//do process every caret(or selection)
for (var i = 0; i < array.Length; i++)
{
var item = array[i];
if (item.Length > 0)
{
//if has selected text, just clean
tb.DeleteRange(item.Begin, item.Length);
for (var j = i + 1; j < array.Length; j++)
{
array[j].Begin -= item.Length;
}
}
if (input == "\b") //backspace
{
if (item.Length != 0) continue;
//delete a char before caret
tb.DeleteRange(item.Begin - 1, 1);
for (var j = i; j < array.Length; j++)
{
array[j].Begin--;
}
}
else //just insert that
{
tb.InsertText(item.Begin, input);
for (var j = i; j < array.Length; j++)
{
array[j].Begin++;
}
}
}
//restore caret status to keep column mode
tb.ClearSelections();
tb.SetSelection(array[0].Begin, array[0].Begin);
for (var i = 1; i < array.Length; i++)
{
var item = array[i];
tb.AddSelection(item.Begin, item.Begin);
}
};
//...
You need to turn on Scintilla rectangular selection by sending required messages to initialize rectangular selection. Example,
CallScintilla(SCI_SETSELECTIONMODE, SC_SEL_STREAM);
CallScintilla(SCI_SETMOUSESELECTIONRECTANGULARSWITCH, true);
CallScintilla(SCI_SETADDITIONALSELECTIONTYPING, true); // so you can type in the selection
CallScintilla(SCI_SETMULTIPLESELECTION, false);
// on paste, paste into rectangular selection
CallScintilla(SCI_SETMULTIPASTE, SC_MULTIPASTE_EACH);
After that, it works like Visual Studio, you hold down the Alt key and drag with the mouse to start a rectangular selection.

Getting new line in wpf

i am having arraylist.let say it contains 15 elements. I am adding these to stack panel. I need to add 3 elements per line. my code is below. I am getting either horizontal or verrtical.Let me know how to do this.
MainWindow w;
public ShopCart(MainWindow m,ArrayList _list)
{
InitializeComponent();
w = m;
int i = 1;
foreach (string cartitems in _list)
{
mystackpanel.Orientation = Orientation.Horizontal;
mystackpanel.Margin.Left.Equals(150);
Label lbl = new Label();
lbl.Name = "Label" + i;
lbl.Height = 30;
lbl.Width = 200;
lbl.Margin.Left.Equals(150);
//lbl.Margin.Top.Equals(150);
lbl.Content = cartitems.ToString();
mystackpanel.Children.Add(lbl);
i++;
int str = mystackpanel.Children.Count;
MessageBox.Show(Convert.ToString(str));
if (str%3 == 0)
{
Button btndelete = new Button();
btndelete.Content = "Delete";
btndelete.Width = 120;
btndelete.Height = 35;
mystackpanel.Children.Add(btndelete);
mystackpanel.Margin.Top.Equals(500);
}
}
Here is some sample code(assuming you already have a list of buttons, and will add outer stack panel to your main control) you can try, you may need to change few things as per your need:
List<Button> buttons = new List<Button>();
StackPanel panel = new StackPanel();
panel.Orientation = Orientation.Horizontal;
int count = 0;
StackPanel innerPanel = new StackPanel();
innerPanel.Orientation = Orientation.Vertical;
foreach (Button button in buttons)
{
innerPanel.Children.Add(button);
++count;
if (count % 3 == 0 && count != 0)
{
panel.Children.Add(innerPanel);
innerPanel = new StackPanel();
innerPanel.Orientation = Orientation.Vertical;
}
}
if (panel.Children.Contains(innerPanel) == false)
{
panel.Children.Add(innerPanel);
}
Although in my opinion the best way will be to have a Grid with n*n row and columns and add your buttons to respective row, columns.

Resources