I'm trying to update my gridview using an event on a contextMenu.
but it's not working..
here's my code:
RowFormatting
void dgItemList_RowFormatting(object sender, RowFormattingEventArgs e)
{
ItemModel rowModel = e.RowElement.RowInfo.DataBoundItem as ItemModel;
if (rowModel.Status == 2)
{
e.RowElement.ForeColor = Color.Red;
}
}
ClickEvent
void Deactivate_Click(object sender, EventArgs e)
{
GridViewRowInfo row = dgItemList.CurrentRow;
ItemModel rowModel = row.DataBoundItem as ItemModel;
if(UiHelpers.ShowConfirmForm("Do you want to Deactivate this Item?"))
{
ServiceResult result = _svc.UpdateItemStatus(rowModel.ItemID);
if(result.Successful)
{
UiHelpers.ShowSuccessForm(rowModel.Description + " was successfully deactivated!");
dgItemList.TableElement.Update(GridUINotifyAction.StateChanged);
}
}
}
I am usng the .TableElement.Update() to run the rowFormatting.. however it isn't working... the function UpdateItemStatus just change the status of an item to 2. I am really new to this so bear with me.
I'm using C#, and Telerik.
Besides making sure the Status is set, I would also recommend using the
row.InvalidateRow()
method, which will invalidate only one row, while the TableElement.Update is heavier update.
Besides, in the RowFormatting handler, you will also have to reset the introduced appearance modifications as the grid uses virtualization and elements are being reused during operations like scrolling, filtering, etc:
void radGridView1_RowFormatting(object sender, RowFormattingEventArgs e)
{
if (e.RowElement.RowInfo.Cells[0].Value.ToString().Contains("3"))
{
e.RowElement.DrawFill = true;
e.RowElement.BackColor = Color.Yellow;
e.RowElement.GradientStyle = GradientStyles.Solid;
}
else
{
e.RowElement.ResetValue(LightVisualElement.DrawFillProperty, ValueResetFlags.Local);
e.RowElement.ResetValue(LightVisualElement.BackColorProperty, ValueResetFlags.Local);
e.RowElement.ResetValue(LightVisualElement.GradientStyleProperty, ValueResetFlags.Local);
}
More information on row formattig can be found here: link. And here you can read about the UI Virtualization: link
Related
I am working on a Xamarin project and I need to be able to tell if the changes that occur to the text in an Entry view are from the code or from the UI, is this possible in Xamarin? or is there a known work around to do this.
I know about the OnTextChanged event but this only tells you that the Text property has changed, and gives you access to the old and new value of the Text property. It does not differentiate between different causes of text change.
You can get some idea from this thread, check if the entry is focused to differentiate between different causes of text change:
public MainPage()
{
InitializeComponent();
myEntry.TextChanged += MyEntry_TextChanged;
}
private void MyEntry_TextChanged(object sender, TextChangedEventArgs e)
{
var entry = sender as Entry;
if (entry.IsFocused)
{
//change from UI
Console.WriteLine("change from UI");
}
else{
//change from code
Console.WriteLine("change from code");
}
}
Update: The better way to solve op's problem:
You can set a flag yourself that tells your code to ignore the event. For example:
private bool ignoreTextChanged;
private void textNazwa_TextCanged(object sender, EventArgs e)
{
if (ignoreTextChanged) return;
}
Create a method and use this to set the text instead of just calling Text = "...";::
private void SetTextBoxText(TextBox box, string text)
{
ignoreTextChanged = true;
box.Text = text;
ignoreTextChanged = false;
}
Refer: ignoreTextChanged
you can use EntryRenderer to detect keypress event and use that flag to detect the change by code or by UI.
Here are the step:
- Exetend your entry control with new event OnTextChangeByUI
- Write custom render for both platform
e.g for android it will be something like this
public class ExtendedEntryRender : EntryRenderer
{
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Control != null)
{
Control.KeyPress += ((Entry)Element).OnTextChangeByUI;
}
}
}
I have a repositoryItemCheckEdit in a column of my grid. The task I want to do is :
Once the user pressed the CheckEdit , this cell become disable so that the user can not make click again.
To do this task I'm using the CheckedChanged event, in the following way :
private void repositoryItemCheckEdit1_CheckedChanged(object sender, EventArgs e)
{
var obj = sender as CheckEdit;
if (obj.Checked)
{
repositoryItemCheckEdit1.Enabled = false;
}
}
With the above event the only thing I get is that the cell becomes clearer , but not is disabled. Even if I make click again it allows me to do it.
Any help is appreciated.
You will probably have more luck/an easier time dealing with this using the brute force method... at least i find this a lot easier than dealing with the crazyness of DataGridView controls scheme.
Use the Tag attribute of your control to set a flag on it, and then when someone tries to un-check it/change it, force it back to checked. Like so:
private void repositoryItemCheckEdit1_CheckedChanged(object sender, EventArgs e)
{
var obj = sender as CheckEdit;
if(obj.Tag != null)
{
obj.Checked = true;
repositoryItemCheckEdit1.Enabled = false;
}
else
{
if (obj.Checked)
{
obj.Tag = true;
repositoryItemCheckEdit1.Enabled = false;
}
}
}
Yesterday I try to implement a new listview that support sub-item edit, my solution is to show a textbox when double click the sub-item. The key code as following:
protected override void OnDoubleClick(EventArgs e)
{
Point pt = this.PointToClient(Cursor.Position);
ListViewItem curItem;
int subItemIndex = GetSubItemAt(pt.X, pt.Y, out curItem);
DoubleClickEventArgs args = new DoubleClickEventArgs(subItemIndex);
base.OnDoubleClick(args);
if (subItemIndex>=0 && !args.Cancel)
{
//StartEdit(...);
}
}
public void EndEdit(bool acceptChanges)
{
//validation
.................
.................
AfterSubItemEventArgs e = new AfterSubItemEventArgs(this.SelectedItems[0], m_editSubItemIndex, this.SelectedItems[0].SubItems[m_editSubItemIndex].Text, m_textbox.Text, false);
OnAfterSubItemEdit(e);
if (e.Cancel)
{
//....
}
else
{
//set new value
}
m_textbox.Visible = false;
m_editSubItemIndex = -1;
}
OnAfterSubItemEdit is a event that user can do some validations or other operations. I add a check in this method, if the new value exist, I will show a messagebox to user firstly, then hide the textbox. But now, the problem comes, when i move the mouse, the listview items can be selected, I don't how to solve this issue, I tried my best to find out the way, but failed. So, please help me!
Listview has a LabelEdit property; when you set it "true", then in an event handler you can call Listview.Items[x].BeginEdit(), and edit an item. As an example, you can handle ListView.DoubleClick event and call BeginEdit right there:
private void Form1_Load(object sender, System.EventArgs e)
{
listView1.LabelEdit = true;
}
private void listView1_DoubleClick(object sender, System.EventArgs e)
{
if(this.listView1.SelectedItems.Count==1)
{
this.listView1.SelectedItems[0].BeginEdit();
}
}
The problem is that your form still calls the DoubleClick event whether the value exists or not. Add appropriate condition before calling base DoubleClick in your code, i.e.:
if(!new value exists)
base.OnDoubleClick(args);
I have a dropdown list and radio button. If something is selected from the dropdown by the user, I want the radio button cleared. If the radio button is selected I want the selection of the dropdown cleared. Unfortunately, this creates events that cancel each other out. I tried using the sender as shown below to determine if the value was being changed by code or by the user, but that doesn't work. How do I make these events only work if the user is the source of the action?
private void rbBlank_Checked(object sender, RoutedEventArgs e)
{
// Verify source of event
if (sender is RadioButton)
{
// Display
comboBoxTitles.SelectedIndex = -1;
}
}
private void comboBoxTitles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
// Verify source of event
if (sender is ComboBox)
{
// Display
rbBlank.IsChecked = false;
}
}
You won't be able to tell the difference between the two since the source will be the same instance for both occasions.
This doesn't answer the question directly but if you compare the SelectedIndex of comboBoxTitles in the SelectionChanged event handler, your problem should be solved
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (comboBoxTitles.SelectedIndex != -1)
{
rbBlank.IsChecked = false;
}
}
Try to compare if sender == instance of a control instead of is type of.
private void rbBlank_Checked(object sender, RoutedEventArgs e)
{
// Verify source of event
if (sender == rbBlank)
{
// Display
comboBoxTitles.SelectedIndex = -1;
}
}
private void comboBoxTitles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
// Verify source of event
if (sender == comboBoxTitles)
{
// Display
rbBlank.IsChecked = false;
}
}
If you know the IDs of those controls, you can try something like this:
System.Web.UI.WebControls.WebControl webControl = (System.Web.UI.WebControls.WebControl) sender;
if( webControl.ID == <comboboxId>)
{
//Do something
}
I havent tried this, but I guess it might work.
The working code sample here synchronizes (single) selection in a TreeView, ListView, and ComboBox via the use of lambda expressions in a dictionary where the Key in the dictionary is a Control, and the Value of each Key is an Action<int>.
Where I am stuck is that I am getting multiple repetitions of execution of the code that sets the selection in the various controls in a way that's unexpected : it's not recursing : there's no StackOverFlow error happening; but, I would like to figure out why the current strategy for preventing multiple selection of the same controls is not working.
Perhaps the real problem here is distinguishing between a selection update triggered by the end-user and a selection update triggered by the code that synchronizes the other controls ?
Note: I've been experimenting with using Delegates, and forms of Delegates like Action<T>, to insert executable code in Dictionaries : I "learn best" by posing programming "challenges" to myself, and implementing them, as well as studying, at the same time, the "golden words" of luminaries like Skeet, McDonald, Liberty, Troelsen, Sells, Richter.
Note: Appended to this question/code, for "deep background," is a statement of how I used to do things in pre C#3.0 days where it seemed like I did need to use explicit measures to prevent recursion when synchronizing selection.
Code : Assume a WinForms standard TreeView, ListView, ComboBox, all with the same identical set of entries (i.e., the TreeView has only root nodes; the ListView, in Details View, has one Column).
private Dictionary<Control, Action<int>> ControlToAction = new Dictionary<Control, Action<int>>();
private void Form1_Load(object sender, EventArgs e)
{
// add the Controls to be synchronized to the Dictionary
// with appropriate Action<int> lambda expressions
ControlToAction.Add(treeView1, (i => { treeView1.SelectedNode = treeView1.Nodes[i]; }));
ControlToAction.Add(listView1, (i => { listView1.Items[i].Selected = true; }));
ControlToAction.Add(comboBox1, (i => { comboBox1.SelectedIndex = i; }));
// optionally install event handlers at run-time like so :
// treeView1.AfterSelect += (object obj, TreeViewEventArgs evt)
// => { synchronizeSelection(evt.Node.Index, treeView1); };
// listView1.SelectedIndexChanged += (object obj, EventArgs evt)
// => { if (listView1.SelectedIndices.Count > 0)
// { synchronizeSelection(listView1.SelectedIndices[0], listView1);} };
// comboBox1.SelectedValueChanged += (object obj, EventArgs evt)
// => { synchronizeSelection(comboBox1.SelectedIndex, comboBox1); };
}
private void synchronizeSelection(int i, Control currentControl)
{
foreach(Control theControl in ControlToAction.Keys)
{
// skip the 'current control'
if (theControl == currentControl) continue;
// for debugging only
Console.WriteLine(theControl.Name + " synchronized");
// execute the Action<int> associated with the Control
ControlToAction[theControl](i);
}
}
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
synchronizeSelection(e.Node.Index, treeView1);
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
// weed out ListView SelectedIndexChanged firing
// with SelectedIndices having a Count of #0
if (listView1.SelectedIndices.Count > 0)
{
synchronizeSelection(listView1.SelectedIndices[0], listView1);
}
}
private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex > -1)
{
synchronizeSelection(comboBox1.SelectedIndex, comboBox1);
}
}
background : pre C# 3.0
Seems like, back in pre C# 3.0 days, I was always using a boolean flag to prevent recursion when multiple controls were updated. For example, I'd typically have code like this for synchronizing a TreeView and ListView : assuming each Item in the ListView was synchronized with a root-level node of the TreeView via a common index :
// assume ListView is in 'Details View,' has a single column,
// MultiSelect = false
// FullRowSelect = true
// HideSelection = false;
// assume TreeView
// HideSelection = false
// FullRowSelect = true
// form scoped variable
private bool dontRecurse = false;
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
if(dontRecurse) return;
dontRecurse = true;
listView1.Items[e.Node.Index].Selected = true;
dontRecurse = false;
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if(dontRecurse) return
// weed out ListView SelectedIndexChanged firing
// with SelectedIndices having a Count of #0
if (listView1.SelectedIndices.Count > 0)
{
dontRecurse = true;
treeView1.SelectedNode = treeView1.Nodes[listView1.SelectedIndices[0]];
dontRecurse = false;
}
}
Then it seems, somewhere around FrameWork 3~3.5, I could get rid of the code to suppress recursion, and there was was no recursion (at least not when synchronizing a TreeView and a ListView). By that time it had become a "habit" to use a boolean flag to prevent recursion, and that may have had to do with using a certain third party control.
I believe your approach is totally fine. If you want something a little more advanced, see Rein in runaway events with the "Latch", which allows for
void TabControl_TabSelected(object sender, TabEventArgs args)
{
_latch.RunLatchedOperation(
delegate
{
ContentTab tab = (ContentTab)TabControl.SelectedTab;
activatePresenter(tab.Presenter, tab);
});
}
Note: I always assumed an SO user should never answer their own question. But, after reading-up on SO-Meta on this issue, I find it's actually encouraged. Personally, I would never vote on my own answer as "accepted."
This "new solution" uses a strategy based on distinguishing between a control being updated as a result of end-user action, and a control being updated by synchronizing code: this issue was mentioned, as a kind of "rhetorical question," in the original question.
I consider this an improvement: it works; it prevents multiple update calls; but, I also "suspect" it's still "not optimal": appended to this code example is a list of "suspicions."
// VS Studio 2010 RC 1, tested under Framework 4.0, 3.5
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace SynchronizationTest_3
{
public partial class Form1 : Form
{
private readonly Dictionary<Control, Action<int>> ControlToAction = new Dictionary<Control, Action<int>>();
// new code : keep a reference to the control the end-user clicked
private Control ClickedControl;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ControlToAction.Add(treeView1, (i => { treeView1.SelectedNode = treeView1.Nodes[i]; }));
ControlToAction.Add(listView1, (i => { listView1.Items[i].Selected = true; }));
ControlToAction.Add(comboBox1, (i => { comboBox1.SelectedIndex = i; }));
// new code : screen out redundant calls generated by other controls
// being updated
treeView1.AfterSelect += (obj, evt)
=>
{
if (treeView1 == ClickedControl) SynchronizeSelection(evt.Node.Index);
};
listView1.SelectedIndexChanged += (obj, evt)
=>
{
if (listView1.SelectedIndices.Count > 0 && listView1 == ClickedControl)
{
SynchronizeSelection(listView1.SelectedIndices[0]);
}
};
comboBox1.SelectedValueChanged += (obj, evt)
=>
{
if (comboBox1 == ClickedControl) SynchronizeSelection(comboBox1.SelectedIndex);
};
// new code here : all three controls share a common MouseDownHandler
treeView1.MouseDown += SynchronizationMouseDown;
listView1.MouseDown += SynchronizationMouseDown;
comboBox1.MouseDown += SynchronizationMouseDown;
// trigger the first synchronization
ClickedControl = treeView1;
SynchronizeSelection(0);
}
// get a reference to the control the end-user moused down on
private void SynchronizationMouseDown(object sender, MouseEventArgs e)
{
ClickedControl = sender as Control;
}
// revised code using state of ClickedControl as a filter
private void SynchronizeSelection(int i)
{
// we're done if the reference to the clicked control is null
if (ClickedControl == null) return;
foreach (Control theControl in ControlToAction.Keys)
{
if (theControl == ClickedControl) continue;
// for debugging only
Console.WriteLine(theControl.Name + " synchronized");
ControlToAction[theControl](i);
}
// set the clicked control to null
ClickedControl = null;
}
}
}
Why I "suspect" this is not optimal:
the idiosyncratic behavior of WinForms controls has to be taken into account: for example, the ListView Control fires its Selected### Events before it fires a Click Event: ComboBox and TreeView fire their Click Events before their SelectedValueChanged and AfterSelect Events respectively: so had to experiment to find that using 'MouseDown would work the same across all three controls.
a "gut level" feeling that I've gone "too far" out on "some kind of limb" here: a sense a much simpler solution might be possible.