datagridview ,CurrentCellChanged,AllowUserToAddRows,textbox.keydown event - vb.net

my question is why add a textbox controls to datagridview ,then press keyboard to add a blank row to datagridview . but i find the cursor always jump to above row's cell,not position where i press keyboard's cell.so i get confused .
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Visible = false;
textBox1.Width = 0;
dataGridView1.Controls.Add(textBoxenter code here1);
System.Data.DataTable dt = new DataTable();
dt.Columns.Add("Name");`enter code here`
dt.Columns.Add("Sex");
System.Data.DataRow dr;
for (int i = 0; i < 10; i++)
{
dr = dt.NewRow();
dr["Name"] = string.Format("Name{0}", i);
dr["Sex"] = string.Format("Sex{0}", i);
dt.Rows.Add(dr);
}
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = dt;
}
private void dataGridView1_CurrentCellChanged(object sender, EventArgs e)
{
this.textBox1.Visible = false;
this.textBox1.Width = 0;
try
{
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].HeaderText == "Name")
{
this.textBox1.Left = dataGridView1.GetCellDisplayRectangle(dataGridView1.CurrentCell.ColumnIndex, dataGridView1.CurrentCell.RowIndex, true).Left;`</i>`
this.textBox1.Top = dataGridView1.GetCellDisplayRectangle(dataGridView1.CurrentCell.ColumnIndex, dataGridView1.CurrentCell.RowIndex, true).Top;`</i>`
this.textBox1.Width = dataGridView1.GetCellDisplayRectangle(dataGridView1.CurrentCell.ColumnIndex, dataGridView1.CurrentCell.RowIndex, true).Width - 2;`</i>enter code here`
this.textBox1.Height = `</i>`dataGridView1.GetCellDisplayRectangle(dataGridView1.CurrentCell.ColumnIndex, dataGridView1.CurrentCell.RowIndex, true).Height - 2;
`</i>`
string str = Convert.ToString(this.dataGridView1.CurrentCell.Value); this.textBox1.Text = str;
this.textBox1.Visible = true;
}
}
catch
{
}
}
private void textBox1_Validating(object sender, CancelEventArgs e)
{
this.dataGridView1.CurrentCell.Value = this.textBox1.Text;
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1 .AllowUserToAddRows =true ;
}
}
}

Alright, against my better judgement I will provide an partial answer for this.
First off, this is not VB.NET, this is C#.
Secondly, I can't find any code that actually adds a row for you or indicates that you have tried it. So I will only answer the problem you state in your comment. This since it seems a bit to hard for you to grasp and I want to be helpful.
Which is: "The question is why i press a key in textbox, the cell position would be move to the above cell".
This happens when you have selected the new row with an asterix ( * ) as row number. This is called a "Manually added row".
So now when you try to add text from your textbox you select the last row and start typing in the textbox. What happends then is that the event KeyDown is fired and it executes this command:
this.dataGridView1.AllowUserToAddRows = false;
Which, to make things simple, means "Delete the row with the asterix ( * )". So now the last row no longer exist and the DataGridView needs a new selection. The selection is then passed to the row above. So now the second last row is the last row, and it will be selected. Then you execute this command:
this.dataGridView1 .AllowUserToAddRows =true;
Which means "Create the row with the asterix ( * )", thus making the last row appear again. However, the second last row selection is not affected by adding this row again. So it remains selected. This creates the endresult that the selection jumps up to the line above.

Related

FastObjectListView UpdateObject() randomly reorders rows within primary sort

Data is a generic List of domain objects.
I click the "Deploy Status" column header to sort on that column.
I have a button that does nothing more than folv.UpdateObject(someObject) .
Every time I press that button, the Deploy Status column maintains its sort, but all rows within the sorted blocks are randomly reordered, as per screenshot.
I have commented out everything in the form's code beyond loading the data, the test button, and the FastObjectListView's column.Add() and .SetObjects(). There are no event handlers wired up for the FastObjectListView. I am not setting PrimarySort or SecondarySort in code; only by clicking with the mouse.
You should be able to fix this problem by either calling Sort after your button's call to UpdateObject or changing your usage of UpdateObject to RefreshObject
Reproducing the problem (C# Repro for the issue in the API)
This seems to reproduce the problem you are having. Run the code, sort the Other column ascending. Click the update button.
public class MainForm : Form
{
public MainForm()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
//
// MainForm
//
this.ClientSize = new System.Drawing.Size(300, 300);
this.Name = "MainForm";
this.ResumeLayout(false);
this.PerformLayout();
var OLVa = new FastObjectListView();
OLVa.Width = 250;
OLVa.Height = 250;
OLVa.Columns.Add(new OLVColumn("ID", "ID"));
OLVa.Columns.Add(new OLVColumn("Other", "Other"));
var l1 = new lolz(1, 3);
OLVa.AddObject(l1);
OLVa.AddObject(new lolz(2,3));
this.Controls.Add(OLVa);
var btn = new Button()
{
Text = "Update",
Top = OLVa.Bottom
};
btn.Click += (s,e)=>OLVa.UpdateObject(l1);
this.Controls.Add(btn);
}
private class lolz
{
public int ID;
public int Other;
public lolz(int id, int other)
{
ID = id;
Other = other;
}
}
}
Fixing the problem
The following would fix it for the above example:
btn.Click += (s,e)=>
{
OLVa.BeginUpdate();
try
{
OLVa.UpdateObject(l1);
OLVa.Sort();
}
finally
{
OLVa.EndUpdate();
}
};

Unity Editor - Displaying GUI lines between two points using switch case

I am trying to implement an editor script that would display GUI lines between any two points in the editor. I have three empty game objects as Vector3 points (A, B and C), and for example, if button #1 is pressed, a value of integer "switchCase" will be set to 1, and according to the switch case statement, it will display a line between point A and point B. If button #2 is pressed, "switchCase" is set to 2, and it will display lines between point A and B, and between point B and C, and so on.
The problem I have is that when I press the buttons - nothing happens in the editor. I can see that the value of "switchCase" is changing correctly in the inspector, but the lines are not showing.
If I input the value straight in the inspector, it works as it should, but my goal is to have the value changing when the button is pressed, rather that me changing the value in the inspector manually.
Hopefully my question makes sense. Any help will be appreciated!
Here is the Editor script:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using UnityEditor.AnimatedValues;
using System.Linq;
[CustomEditor(typeof(LineTest))]
public class LineTestInspector : Editor
{
public LineTest myScript;
public void OnSceneGUI()
{
Handles.color = Color.red;
switch (myScript.switchCase)
{
case 1:
GameObject posAobj = GameObject.Find("PointA");
GameObject posBobj = GameObject.Find("PointB");
myScript.posA = posAobj.transform.position;
myScript.posB = posBobj.transform.position;
Handles.DrawLine(myScript.posA, myScript.posB);
break;
case 2:
GameObject posCobj = GameObject.Find("PointC");
myScript.posC = posCobj.transform.position;
Handles.DrawLine(myScript.posA, myScript.posB);
Handles.DrawLine(myScript.posB, myScript.posC);
break;
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (GUILayout.Button("Draw First Line"))
{
myScript.switchCase= 1;
Debug.Log("Switch - 1");
}
if (GUILayout.Button("Draw Second Line"))
{
myScript.switchCase = 2;
Debug.Log("Switch - 2");
}
if (GUILayout.Button("Reset switchCase"))
{
myScript.switchCase = 0;
Debug.Log("Switch - 0");
}
}
}
And the Mono script:
using System.Collections;
using System;
using System.Collections.Generic;
using UnityEngine;
public class LineTest : MonoBehaviour {
public Vector3 posA;
public Vector3 posB;
public Vector3 posC;
public int switchCase;
}
You have to call EditorUtility.SetDirty(myScript); for the Editor to update after changing the values.
Your code should look like this:
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (GUILayout.Button("Draw First Line"))
{
myScript.switchCase = 1;
Debug.Log("Switch - 1");
EditorUtility.SetDirty(myScript);
}
if (GUILayout.Button("Draw Second Line"))
{
myScript.switchCase = 2;
Debug.Log("Switch - 2");
EditorUtility.SetDirty(myScript);
}
if (GUILayout.Button("Reset switchCase"))
{
myScript.switchCase = 0;
Debug.Log("Switch - 0");
EditorUtility.SetDirty(myScript);
}
}

How to display a Labels 'Error on ErrorProvider1'

Goal
I want to display the text that I put in the Label's "Error on ErrorProvider1" attribute whenever I get an error. See the following label's attributes below.
I try to display the text in the red rectangle into my ErrorProvider1 SetError(control, value) function.
If TextBox1.Text.Trim.Contains("'") Then
ErrorProvider1.SetError(lblErr, ErrorProvider1.GetError(lblErr))
Else
ErrorProvider1.SetError(lblErr, "")
End If
How can I retrieve the 'Error on ErrorProvider1' text from the lblErr to display it in the ErrorProvider1 SetError value?
The ErrorProvider component is very awkward to use effectively. It is fixable however, I'll give an example in C# that extends the component with some new capabilities:
ShowError(Control ctl, bool enable) displays the text that you entered at design-time when the enable argument is true. The easier-to-use version of SetError().
HasErrors returns true if the any active warning icons are displayed. Handy in your OK button's Click event handler.
FocusError() sets the focus to the first control that has a warning icon, if any. It returns false if no warnings are remaining.
SetError() is a replacement of ErrorProvider.SetError(). You only need it if you add any controls after the form's Load event fired or if you need to modify the warning text.
Add a new class to your project and paste the code shown below. Compile. Drop it from the top of the toolbox onto the form. The design-time behavior is identical. Modestly tested.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.ComponentModel.Design;
class MyErrorProvider : ErrorProvider {
public void ShowError(Control ctl, bool enable) {
// Easy to use version of SetError(), uses design-time text
if (!enable) base.SetError(ctl, "");
else {
if (errors.ContainsKey(ctl)) base.SetError(ctl, errors[ctl]);
else base.SetError(ctl, "No error text available");
}
}
public bool HasErrors {
// True if any errors are present
get {
foreach (var err in errors)
if (!string.IsNullOrEmpty(base.GetError(err.Key))) return true;
return false;
}
}
public bool FocusError() {
// Set the focus to the first control with an active error
foreach (var err in errors) {
if (!string.IsNullOrEmpty(base.GetError(err.Key))) {
err.Key.Focus();
return true;
}
}
return false;
}
public new void SetError(Control ctl, string text) {
// Use this only to add/modify error text after the form's Load event
if (!string.IsNullOrEmpty(text)) {
if (errors.ContainsKey(ctl)) errors[ctl] = text;
else errors.Add(ctl, text);
}
base.SetError(ctl, text);
}
private void initialize(object sender, EventArgs e) {
// Preserve error text
copyErrors(((Form)sender).Controls);
}
private void copyErrors(Control.ControlCollection ctls) {
foreach (Control ctl in ctls) {
var text = this.GetError(ctl);
if (!string.IsNullOrEmpty(text)) {
errors.Add(ctl, text);
base.SetError(ctl, "");
}
copyErrors(ctl.Controls);
}
}
private Dictionary<Control, string> errors = new Dictionary<Control, string>();
// Plumbing to hook the form's Load event
[Browsable(false)]
public new ContainerControl ContainerControl {
get { return base.ContainerControl; }
set {
if (base.ContainerControl == null) {
var form = value.FindForm();
if (form != null) form.Load += initialize;
}
base.ContainerControl = value;
}
}
public override ISite Site {
set {
// Runs at design time, ensures designer initializes ContainerControl
base.Site = value;
if (value == null) return;
IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (service == null) return;
IComponent rootComponent = service.RootComponent;
this.ContainerControl = rootComponent as ContainerControl;
}
}
}
Your issue is that you are replacing the error message when nothing is wrong. As noted in your comment below, you are storing the localized error message in the label's Tag, so you can do the following:
If TextBox1.Text.Trim.Contains("'") Then
ErrorProvider1.SetError(lblErr, lblErr.Tag)
Else
ErrorProvider1.SetError(lblErr, "")
End If
You were correct to use ErrorProvider1.GetError(Control) to get the value. It's just that you're more than likely replacing it with an empty string before you were retrieving it.

Some rows are collapsed in DataGrid, I am getting issue in KeyBoard navigation

I am using DataGrid, run time i make visible collapse some rows.
Suppose my 4th row's visibility is collapse, and my focus is on 3rd row, when i try to move on 5th row with the help of Down-Arrow key, it is not working. Same way if my focus on 5th row and want to move on 3rd row with Up-Arrow key, it is also not working.
Now, what should i do?
This is actually a bug in .Net, there is a bug report here.
One workaround is to use Attached behavior to handle the up and down selection. The following example requires the IsSynchronizedWithCurrentItem to be set to true for the DataGrid.
Note! make sure you change the while condition to the appropriate way to determine if the item is collapsed.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
namespace DataGridGroupingTest
{
class DataGridKeyboardNavigationAttachedBehavior
{
public static readonly DependencyProperty
KeyboardKey
= DependencyProperty.RegisterAttached(
"IsKeyboardNavigationEnabled",
typeof(bool),
typeof(DataGridKeyboardNavigationAttachedBehavior),
new PropertyMetadata(
false,
OnIsKeyboardNavigationEnabledChanged));
public static bool GetIsKeyboardNavigationEnabled(DependencyObject depObj)
{
return (bool)depObj.GetValue(KeyboardKey);
}
public static void SetIsKeyboardNavigationEnabled(DependencyObject depObj, bool value)
{
depObj.SetValue(KeyboardKey, value);
}
private static void OnIsKeyboardNavigationEnabledChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
DataGrid dataGrid = depObj as DataGrid;
if (dataGrid != null)
{
dataGrid.PreviewKeyDown += dataGrid_PreviewKeyDown;
dataGrid.IsSynchronizedWithCurrentItem = true;
}
}
static void dataGrid_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if (dataGrid != null && dataGrid.CurrentCell != null)
{
if (e.Key == System.Windows.Input.Key.Down || e.Key == System.Windows.Input.Key.Up)
{
ICollectionView view = CollectionViewSource.GetDefaultView(dataGrid.Items);
int loopCount = 0;
do
{
if (e.Key == System.Windows.Input.Key.Down)
{
view.MoveCurrentToNext();
if (view.IsCurrentAfterLast)
{
view.MoveCurrentToFirst();
loopCount++;
}
}
if (e.Key == System.Windows.Input.Key.Up)
{
view.MoveCurrentToPrevious();
if (view.IsCurrentBeforeFirst)
{
view.MoveCurrentToLast();
loopCount++;
}
}
} while (((Person)view.CurrentItem).Boss != null && !((Person)view.CurrentItem).Boss.IsExpanded && loopCount < 2);
// We have to move the cell selection aswell.
dataGrid.CurrentCell = new DataGridCellInfo(view.CurrentItem, dataGrid.CurrentCell.Column);
e.Handled = true;
return;
}
}
}
}
}

ReportViewer - modify toolbar?

Do anyone have good ideas of how to modify the toolbar for the WinForms version of the ReportViewer Toolbar?
That is, I want to remove some buttons and varius, but it looks like the solution is to create a brand new toolbar instead of modifying the one that is there.
Like, I had to remove export to excel, and did it this way:
// Disable excel export
foreach (RenderingExtension extension in lr.ListRenderingExtensions()) {
if (extension.Name == "Excel") {
//extension.Visible = false; // Property is readonly...
FieldInfo fi = extension.GetType().GetField("m_isVisible", BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(extension, false);
}
}
A bit trickysh if you ask me..
For removing toolbarbuttons, an possible way was to iterate through the Control array inside the ReportViewer and change the Visible property for the buttons to hide, but it gets reset all the time, so it is not an good way..
WHEN do MS come with an new version btw?
Yeap. You can do that in a little tricky way.
I had a task to add more scale factors to zoom report. I did it this way:
private readonly string[] ZOOM_VALUES = { "25%", "50%", "75%", "100%", "110%", "120%", "125%", "130%", "140%", "150%", "175%", "200%", "300%", "400%", "500%" };
private readonly int DEFAULT_ZOOM = 3;
//--
public ucReportViewer()
{
InitializeComponent();
this.reportViewer1.ProcessingMode = ProcessingMode.Local;
setScaleFactor(ZOOM_VALUES[DEFAULT_ZOOM]);
Control[] tb = reportViewer1.Controls.Find("ReportToolBar", true);
ToolStrip ts;
if (tb != null && tb.Length > 0 && tb[0].Controls.Count > 0 && (ts = tb[0].Controls[0] as ToolStrip) != null)
{
//here we go if our trick works (tested at .NET Framework 2.0.50727 SP1)
ToolStripComboBox tscb = new ToolStripComboBox();
tscb.DropDownStyle = ComboBoxStyle.DropDownList;
tscb.Items.AddRange(ZOOM_VALUES);
tscb.SelectedIndex = 3; //100%
tscb.SelectedIndexChanged += new EventHandler(toolStripZoomPercent_Click);
ts.Items.Add(tscb);
}
else
{
//if there is some problems - just use context menu
ContextMenuStrip cmZoomMenu = new ContextMenuStrip();
for (int i = 0; i < ZOOM_VALUES.Length; i++)
{
ToolStripMenuItem tsmi = new ToolStripMenuItem(ZOOM_VALUES[i]);
tsmi.Checked = (i == DEFAULT_ZOOM);
//tsmi.Tag = (IntPtr)cmZoomMenu;
tsmi.Click += new EventHandler(toolStripZoomPercent_Click);
cmZoomMenu.Items.Add(tsmi);
}
reportViewer1.ContextMenuStrip = cmZoomMenu;
}
}
private bool setScaleFactor(string value)
{
try
{
int percent = Convert.ToInt32(value.TrimEnd('%'));
reportViewer1.ZoomMode = ZoomMode.Percent;
reportViewer1.ZoomPercent = percent;
return true;
}
catch
{
return false;
}
}
private void toolStripZoomPercent_Click(object sender, EventArgs e)
{
ToolStripMenuItem tsmi = sender as ToolStripMenuItem;
ToolStripComboBox tscb = sender as ToolStripComboBox;
if (tscb != null && tscb.SelectedIndex > -1)
{
setScaleFactor(tscb.Items[tscb.SelectedIndex].ToString());
}
else if (tsmi != null)
{
if (setScaleFactor(tsmi.Text))
{
foreach (ToolStripItem tsi in tsmi.Owner.Items)
{
ToolStripMenuItem item = tsi as ToolStripMenuItem;
if (item != null && item.Checked)
{
item.Checked = false;
}
}
tsmi.Checked = true;
}
else
{
tsmi.Checked = false;
}
}
}
Get the toolbar from ReportViewer control:
ToolStrip toolStrip = (ToolStrip)reportViewer.Controls.Find("toolStrip1", true)[0]
Add new items:
toolStrip.Items.Add(...)
There are a lot of properties to set which buttons would you like to see.
For example ShowBackButton, ShowExportButton, ShowFindControls, and so on. Check them in the help, all starts with "Show".
But you are right, you cannot add new buttons. You have to create your own toolbar in order to do this.
What do you mean about new version? There is already a 2008 SP1 version of it.
Another way would be to manipulate the generated HTML at runtime via javascript. It's not very elegant, but it does give you full control over the generated HTML.
For VS2013 web ReportViewer V11 (indicated as rv), the code below adds a button.
private void AddPrintBtn()
{
foreach (Control c in rv.Controls)
{
foreach (Control c1 in c.Controls)
{
foreach (Control c2 in c1.Controls)
{
foreach (Control c3 in c2.Controls)
{
if (c3.ToString() == "Microsoft.Reporting.WebForms.ToolbarControl")
{
foreach (Control c4 in c3.Controls)
{
if (c4.ToString() == "Microsoft.Reporting.WebForms.PageNavigationGroup")
{
var btn = new Button();
btn.Text = "Criteria";
btn.ID = "btnFlip";
btn.OnClientClick = "$('#pnl').toggle();";
c4.Controls.Add(btn);
return;
}
}
}
}
}
}
}
}
I had this question for al ong time I I found the answer after a long tie and the main source of kowledge I used was this webpega: I'd like to thank you all guys adding the code that allowed me to do it and a picture with the result.
Instead of using the ReportViewer Class, you need to create a new classs, in my case, I named it ReportViewerPlus and it goes like this:
using Microsoft.Reporting.WinForms;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace X
{
class ReportViewerPlus : ReportViewer
{
private Button boton { get; set; }
public ReportViewerPlus(Button but) {
this.boton = but;
testc(this.Controls[0]);
}
public ReportViewerPlus()
{
}
private void testc(Control item){
if(item is ToolStrip)
{
ToolStripItemCollection tsic = ((ToolStrip)item).Items;
tsic.Insert(0, new ToolStripControlHost(boton));
return;
}
for (int i = 0; i < item.Controls.Count; i++)
{
testc(item.Controls[i]);
}
}
}
}
You have to add the button directly in the constructor of the class and you can configure the button in your designer.
Here's a pic of the result, not perfect, but enough to go(safe link I swear, but I can't post my own pics, don't have enough reputation).
http://prntscr.com/5lfssj
If you look carefully in the code of the class, you'd see more or less how it works and you could make your changes and make it possible to establish it in other site of the toolbar.
Thank you so much for helping me in the past, I hope this helps lots of people!
Generally you are suppose to create your own toolbar if you want to modify it. Your solution for removing buttons will probably work if that is all you need to do, but if you want to add your own you should probably just bite the bullet and build a replacement.
You may modify reportviewer controls by CustomizeReportToolStrip method.
this example remove Page Setup Button, Page Layout Button in WinForm
public CustOrderReportForm() {
InitializeComponent();
CustomizeReport(this.reportViewer1);
}
private void CustomizeReport(Control reportControl, int recurCount = 0) {
Console.WriteLine("".PadLeft(recurCount + 1, '.') + reportControl.GetType() + ":" + reportControl.Name);
if (reportControl is Button) {
CustomizeReportButton((Button)reportControl, recurCount);
}
else if (reportControl is ToolStrip) {
CustomizeReportToolStrip((ToolStrip)reportControl, recurCount);
}
foreach (Control childControl in reportControl.Controls) {
CustomizeReport(childControl, recurCount + 1);
}
}
//-------------------------------------------------------------
void CustomizeReportToolStrip(ToolStrip c, int recurCount) {
List<ToolStripItem> customized = new List<ToolStripItem>();
foreach (ToolStripItem i in c.Items) {
if (CustomizeReportToolStripItem(i, recurCount + 1)) {
customized.Add(i);
}
}
foreach (var i in customized) c.Items.Remove(i);
}
//-------------------------------------------------------------
void CustomizeReportButton(Button button, int recurCount) {
}
//-------------------------------------------------------------
bool CustomizeReportToolStripItem(ToolStripItem i, int recurCount) {
Console.WriteLine("".PadLeft(recurCount + 1, '.') + i.GetType() + ":" + i.Name);
if (i.Name == "pageSetup") {
return true;
}
else if (i.Name == "printPreview") {
return true;
}
return false; ;
}