Devexpress GridControl : Prevent new row added automatically - insert

Please guide me how to prevent new rows added automatically on DevExpress.XtraGrid.GridControl
I want to control when new rows is added, in my case i'm using a keydown event (CTRL + I ) for this task. But the grid keep adding new rows automatically if i move the focus (cursor pointer) to the area right below to the last row and click.
The GridControl.MainView is a BandedGridView, which contains the datasource.

You can use BandedGridView.OptionsView.NewItemRowPosition property. You can set its value to NewItemRowPosition.None to hide new item row.
Another way is to handle BandedGridView.ShownEditor event. Inside of this you can check if BandedGridView.FocusedRowHandle property is equals to GridControl.NewItemRowHandle and cancel editor activation.
Here is example:
private void bandedGridView1_ShowingEditor(object sender, CancelEventArgs e)
{
if (bandedGridView1.FocusedRowHandle == GridControl.NewItemRowHandle)
{
// Do here additional checks if you need. After your checks set e.Cancel to true.
e.Cancel = true;
}
}

You can handle the ValidateRow event. If you set e.Valid = false you wont add a new row. So check if your object is empty or invalid and just if the needed values are typed you give the row free.
private void grvMyView_ValidateRow(object sender, ValidateRowEventArgs e)
{
if (grvMyView.IsNewItemRow(e.RowHandle))
{
MyObject obj = grvMyView.GetRow(e.RowHandle) as MyObject;
e.Valid = obj.IsValid();
}
}

As of version 15 you can simply set your TableView's NewItemRowPosition to NewItemRowPosition.None. Be sure to call CommitEditing() on your TableView first.

Related

Xamarin forms switch events lead to infinte loop - Group switches

I am trying to develop an app using Xamarin.Forms. At a certain point I am trying to have multiple switches that are grouped. This is to say that when one switch is toggled, every other switch needs to be untoggled and, at the same time, there needs to be at least one switch always toggled. This is to say that tapping on a switch that is already toggled should not change anything.T
Now my problem is that Xamarin.forms Toggled event for switches can be fired from the UI, but is also fired programmatically. I thought I had found a way around this problem, but still by doing:
-If the switch was turned on, turn off all others and do application stuff.
-else if a switch was turned off, check if there are any others that are on. If not, turn the switch back on. If yes, do nothing.
A sample code for two switches could be:
private void OnFirstToggled(object sender, EventArgs args)
{
if(FirstSwitch.isToggled)
{
//Application stuff.
SecondSwitch.isToggled = false;
}
else if (!SecondSwitch.isToggled)
{
FirstSwitch.isToggled = true;
}
}
private void OnSecondToggled(object sender, EventArgs args)
{
if(SecondSwitch.isToggled)
{
//Application stuff.
FirstSwitch.isToggled = false;
}
else if (!FirstSwitch.isToggled)
{
SecondSwitch.isToggled = true;
}
}
This solution results in an infinite loop when an already toggled switch is tapped. In fact, the isToggled property of the switch alternates between true and false infinitely. However when debugging the other event never seems to be fired (or at least my debugger does not see it). This is why I don't understand where the isToggled property is changed after that first tap.
I know this is probably a very simple issue, but I cannot seem to find the solution somewhere online. Can anyone see the problem or recommend a better, common way to implement this?
I write a simple solution to you to always keep one Switch open from a Switch group.
Let's first add three switch for test, make sure these Switch will fire the same event of Toggled:
<StackLayout>
<!-- Place new controls here -->
<Switch Toggled="Switch_Toggled" x:Name="FirstSwitch"/>
<Switch Toggled="Switch_Toggled" x:Name="SecondSwitch"/>
<Switch Toggled="Switch_Toggled" x:Name="ThirdSwitch"/>
</StackLayout>
In the code behind, I add those Switches into a list, and loop them in Switch_Toggled event to open/close the Switches:
public partial class MainPage : ContentPage
{
List<Switch> switchList;// To store all your Switches
bool isLooping; //To make sure the Switch_Toggled metod not fired a second time during one toogle event
public MainPage()
{
InitializeComponent();
switchList = new List<Switch>();
switchList.Add(FirstSwitch);
switchList.Add(SecondSwitch);
switchList.Add(ThirdSwitch);
isLooping = false;
}
private void Switch_Toggled(object sender, ToggledEventArgs e)
{
//To make sure the Switch_Toggled metod not fired a second time during one toogle event
if (isLooping == true)
{
return;
}
isLooping = true;
Switch clickSwitch = sender as Switch;
clickSwitch.IsToggled = true;
foreach (var tempSwitch in switchList)
{
if (tempSwitch != clickSwitch)
{
if (tempSwitch.IsToggled == true)
{
tempSwitch.IsToggled = false;
}
}
}
isLooping = false;
}
}
You can try this solution and feel free to ask me any question if you don't understand.
Your problem are the two else blocks. Take in account that you're toggling it on anyway.

JavaFX: Prevent selection of a different tab if the data validation of the selected tab fails

I'm creating a CRUD application that store data in a local h2 DB. I'm pretty new to JavaFX. I've created a TabPane to with 3 Tab using an jfxml created with Scene Builder 2.0. Each Tab contains an AncorPane that wrap all the controls: Label, EditText, and more. Both the TabPane and the Tabs are managed using one controller. This function is used to create and to update the data. It's called from a grid that display all the data. A pretty basic CRUD app.
I'm stuck in the validation phase: when the user change the tab, by selecting another tab, it's called a validation method of the corresponding tab. If the validation of the Tab fails, I want that the selection remains on this tab.
To achieve this I've implemented the following ChangeListener on the SelectionModel of my TabPane:
boolean processingTabValidationOnChange = false;
tabPane.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
if (processingTabValidationOnChange == false) {
boolean success;
switch (t.intValue()) {
case 0: success = validationTab1Passed();
break;
case 1: success = validationTab2Passed();
break;
case 1: success = validationTab3Passed();
break;
default: success = false;
}
if (success == false) {
processingTabValidationOnChange = true;
// select the previous tab
tabPane.getSelectionModel().select(t.intValue());
processingTabValidationOnChange = false;
}
}
}
});
I'm not sure that this is the right approach because:
The event changed is fired two times, one for the user selection and one for the .select(t.intValue()). To avoid this I've used a global field boolean processingTabValidationOnChange... pretty dirty I know.
After the .select(t.intValue()) the TabPane displays the correctly Tab as selected but the content of the tab is empty as if the AnchorPane was hidden. I cannot select again the tab that contains the errors because it's already selected.
Any help would be appreciated.
Elvis
I would approach this very differently. Instead of waiting for the user to select a different tab, and reverting if the contents of the current tab are invalid, prevent the user from changing tabs in the first place.
The Tab class has a disableProperty. If it is set to true, the tab cannot be selected.
Define a BooleanProperty or BooleanBinding representing whether or not the data in the first tab is invalid. You can create such bindings based on the state of the controls in the tab. Then bind the second tab's disableProperty to it. That way the second tab automatically becomes disabled or enabled as the data in the first tab becomes valid or invalid.
You can extend this to as many tabs as you need, binding their properties as the logic dictates.
Here's a simple example.
Update: The example linked above is a bit less simple now. It will dynamically change the colors of the text fields depending on whether the field is valid or not, with validation rules defined by bindings in the controller. Additionally, there are titled panes at the top of each page, with a title showing the number of validation errors on the page, and a list of messages when the titled pane is expanded. All this is dynamically bound to the values in the controls, so it gives constant, clear, yet unobtrusive feedback to the user.
As I commented to the James's answer, I was looking for a clean solution to the approach that I've asked. In short, to prevent the user to change to a different tab when the validation of the current tab fails. I proposed a solution implementing the ChangeListener but, as I explained: it's not very "clean" and (small detail) it doesn't work!
Ok, the problem was that the code used to switch back the previous tab:
tabPane.getSelectionModel().select(t.intValue());
is called before the process of switching of the tab itself it's completed, so it ends up selected... but hidden.
To prevent this I've used Platform.runLater(). The code .select() is executed after the change of tab. The full code becomes:
//global field, to prevent validation on .select(t.intValue());
boolean skipValidationOnTabChange = false;
tabPane.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
if (skipValidationOnTabChange == false) {
boolean success;
switch (t.intValue()) {
case 0:
success = validationTab1Passed();
break;
case 1:
success = validationTab2Passed();
break;
case 1:
success = validationTab3Passed();
break;
default:
success = false;
}
if (success == false) {
Platform.runLater(new Runnable() {
#Override
public void run() {
skipValidationOnTabChange = true;
tabPane.getSelectionModel().select(t.intValue());
skipValidationOnTabChange = false;
}
});
}
}
}
});
Anyway, if anyone has a better solution to accomplish this, you're welcome. In example using a method like consume() to prevent the tab to be selected two times. This way I can eliminated the global field skipValidationOnTabChange.
Elvis
I needed to achieve the similar thing. I've done this by changing the com.sun.javafx.scene.control.behavior.TabPaneBehaviour class by overriding selectTab method:
class ValidatingTabPaneBehavior extends TabPaneBehavior {
//constructors etc...
#Override
public void selectTab(Tab tab) {
try {
Tab current = getControl().getSelectionModel().getSelectedItem();
if (current instanceof ValidatingTab) {
((ValidatingTab) current).validate();
}
//this is the method we want to prevent from running in case of error in validation
super.selectTab(tab);
}catch (ValidationException ex) {
//show alert or do nothing tab won't be changed
}
}
});
The ValidatingTab is my own extension to Tab:
public class ValidatingTab extends Tab {
public void validate() throws ValidationException {
//validation
}
}
This is the "clean part" of the trick. Now we need to place ValidatingTabPaneBehavior into TabPane.
First you need to copy (!) the whole com.sun.javafx.scene.control.skin.TabPaneSkin to the new class in order to change its constructor. It is quite long class, so here is only the part when I switch the Behavior class:
public class ValidationTabPaneSkin extends BehaviorSkinBase<TabPane, TabPaneBehavior> {
//copied private fields
public ValidationTabPaneSkin(TabPane tabPane) {
super(tabPane, new ValidationTabPaneBehavior(tabPane));
//the rest of the copied constructor
}
The last thing is to change the skin in your tabPane instance:
tabPane.setSkin(new ValidationTabPaneSkin(tabPane));

Windows phone - How to exit on double tap?

I'm learning to develop windows phone application. I started with a browser based app by following this tutorial - http://blogs.msdn.com/b/jaimer/archive/2011/02/04/back-button-press-when-using-webbrowser-control-in-wp7.aspx. I'm experimenting with http://m.facebook.com I can correctly use back button to go to the previous page and all that stuff but I'm not able to implement exit on double tap of back button.
I have seen many browsers app which exit after double tapping the back button. for example - Flipkart - http://www.windowsphone.com/en-us/store/app/flipkart/84fc03ea-210d-4e3e-88e0-de502a2434c5
There is no double tab event for back button. How can we achieve this?
You can create a global long that represents the last time the user pressed the back button.
Every time the back button is pressed, you can make your program subtract the number of elapsed ticks. If it has passed a short amount of ticks, you can make your program exit. If not, set the last tick variable once more.
You can get the current tick that represents the current time with System.DateTime.Ticks.
Simple code sample:
long LastExitAttemptTick = DateTime.Ticks;
private void BackButtonPressHandler(...)
{
long thisTick = DateTime.Ticks;
if (LastExitAttemptTick - thisTick < [specified amount])
throw new Exception("Exit Exception"); //You can use XNA, but this is a quick and dirty way of exiting
else
LastExitAttemptTick = DateTime.Ticks;
}
You can use a value of 10,000,000 ticks (1 second). MSDN says 10,000 ticks per millisecond, so 10,000 * 1000 = 10,000,000.
EDIT: Or as you said, you can also use DateTime.Now and use the seconds value instead. Either way works.
well this kind of logic could work for you
make a global variable
int Count=0
protected ovverride void OnBackKeyPress(CancelEventArgs e)
{
if(Count==0)
{
e.Canel=true;
Count++;
}
else if(Count==1)
{
Count=0;
//code for exiting
//may be App.Current.Terminate(); in wp8
//or in wp7
//if (NavigationService.CanGoBack)
//{
// while (NavigationService.RemoveBackEntry() != null)
// {
// NavigationService.RemoveBackEntry();
// }
//}
}
}
Hope this helps
To close the application on double click, you can use DispatcherTimer task to check whether a two clicks are within one second, if yes close the application else start timer and again check. The snippet for that as follows:
make a DispatcherTimer object as a class field like,
DispatcherTimer dt = new DispatcherTimer();
In your class's constructor specify the interval you want to check for double tap and also add event handler to perform some action when specified time has elapsed. You can do in a class's constructor,
dt.Interval = TimeSpan.FromSeconds(1.0);
dt.Tick += delegate(object s, EventArgs e)
{
dt.Stop();
};
Here what we're doing is we're specifying timespan of 1 second to check whether double tap occurs within that second. Tick event is for what we want to do when timer completes its 1 second. We're simply going to stop the timer.
Now navigate to back key event handler and here is my code to check double tap:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
if (!dt.IsEnabled)
dt.Start();
else
new Microsoft.Xna.Framework.Game().Exit();
}
When for the first tap, timer is not started, it will go to if condition and will start the timer. If second tap occurs after 1 second, then the Tick event we wrote in constructor will fire and according to logic written there, the timer will stop.
Now assume the double tap occurs consequently within 1 second. For the 1st tap as usual it will start the timer, if immediately user presses back button again, then in its handler, it will check whether timer is running. As timer has not completed its 1 second interval, else condition will fired up and the application will close.
I used XNA library / shortcut to force close the application. To work with new Microsoft.Xna.Framework.Game().Exit(); method you should add a microsoft.xna.framework.game.dll in a reference.
Make TimeSpan interval as required.
Hope this helps. Thanks.
EDIT:
Sometimes XNA is not installed on windows 8. Here is a solution for that, so that you add above mentioned assembly reference in you project.
http://blogs.msdn.com/b/astebner/archive/2012/02/29/10274694.aspx
You have to download update which is around around 23MB.
To save time here's a Dropbox link to above assembly reference:
https://db.tt/RYTwv7cS
Yes there is no Double Tap event for back button. You have to write your own logic to exit application on Double Tap on device back key tap twice. Here is the solution this may be help you.
Create a Global variable and initialize with zero
Int TapCount =0;
Now Override OnBackKeyPress event with your own logic.
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
TapCount++;
if(TapCount==2)
{
if( windows phone 8 )
{
Application.Current.Terminate();
}
else
{
if (NavigationService.CanGoBack)
{
while (NavigationService.RemoveBackEntry() != null)
{
NavigationService.RemoveBackEntry();
}
}
}
}
else
e.Canel=true;
base.OnBackKeyPress(e);
}
It's very simple. I've implemented it like this:
First declare global variable:
int count;
Now initialize its value in OnNavigatedTo(NavigationEventArgs e) method:
count = 0;
Now at last add the below code to your cs file:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
count++;
e.Cancel = true;
if(count == 2)
{ e.Cancel = false; base.OnBackKeyPress(e); }
}

How to trigger datatemplate selector in Windows Phone?

I have a property and depending upon it's state (say A and B) I either show a usercontrol of animation or a image.
Now, if the property changes, I want to trigger the datatemplate selector again. On searching, I found that in WPF I could have used DataTemplate.Trigger but it's not available in WP.
So, my question is
Is their a way to trigger datatemplate selector so when property changes from state A to B, then appropriate usercontrol gets selected. If yes, then please give some example how to implement it.
Also, as there are only two states, if think I can use Converter to collapse the visibility. For basic if else situation, I will need to write two converters.( Can I somehow do it using one converter only?)
Here is the exact situation.
If state == A :
select userControl_A
else : select userControl_B
Also,
Will the animation usercontrol will effect the performance when it's in Collapsed state?
EDIT- Just realized, I can use parameter object to write just one converter.
You could implement a DataTemplateSelector like described here.
I use it and it works pretty well.
EDIT:
If you need to update the DataTemplate when the property changes, you should subscribe to the PropertyChanged event of the data object in the TemplateSelector and execute the SelectTemplate method again.
Here is the code sample:
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
City itemAux = item as City;
// Subscribe to the PropertyChanged event
itemAux.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(itemAux_PropertyChanged);
return GetTemplate(itemAux, container);
}
private DataTemplate GetTemplate(City itemAux, DependencyObject container)
{
if (itemAux != null)
{
if (itemAux.Country == "Brazil")
return BrazilTemplate;
if (itemAux.Country == "USA")
return UsaTemplate;
if (itemAux.Country == "England")
return EnglandTemplate;
}
return base.SelectTemplate(itemAux, container);
}
void itemAux_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
// A property has changed, we need to reevaluate the template
this.ContentTemplate = GetTemplate(sender as City, this);
}

Trying to change value cells in a background worker thread

I'm trying to update a Ultragridrow cell in a background worker, but this is throwing a InvalidOperation Exception when this is called more than 1 time.
Here you have the method that starts the RunWorkerAsync.
private void RefreshGridCacheStart()
{
try
{
if (this.uGridCache.Rows.Count == 0)
{
return;
}
if(!workerThread.IsBusy)
{
workerThread.DoWork += LookUpHostnames;
workerThread.ProgressChanged += UpdateCacheHostCell;
workerThread.RunWorkerCompleted += WorkerCompleted;
workerThread.WorkerReportsProgress = true;
workerThread.RunWorkerAsync();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
}
}
This is the DoWork method:
private void LookUpHostnames(object sender, DoWorkEventArgs e)
{
var rowValues = new object[2];
try
{
foreach (UltraGridRow row in uGridCache.Rows)//here is were I get an invalid operation exception
{
string cellValue = row.Cells["Host"].Text;
if (Globals.cNet.isValidIP(cellValue))
{
rowValues[0] = row;
rowValues[1] = cellValue;
workerThread.ReportProgress(0, rowValues);
string resolvedHostname = Globals.cIPLookup.LookupHostFromIP(cellValue);
rowValues[1] = resolvedHostname;
workerThread.ReportProgress(0, rowValues);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
}
}
And this is the Report Progress method:
private void UpdateCacheHostCell(object sender, ProgressChangedEventArgs e)
{
var rowValues = e.UserState as object[];
var row = (UltraGridRow) rowValues[0];
var sMesage = (string) rowValues[1];
row.Cells["Host"].Value = sMesage;
}
You can find your answer here Different question but ultimately the same problem. Your are changing data inside a foreach loop which invalidates the enumerator.
There are 2 possible solutions I see from reading your code
Save all changes that need to be made to an List of changes and only report progress once after the foreach loop. This might not be a very good solution though since you are processing in the background. If there is other code running that could also change the data in the grid you would get the same error again.
Since you are not adding rows you could easily change the foreach to a for loop. This might also lead to an issue if code on the main thread could add, or worse, remove rows
Sounds like something must be changing the underlying row collection hence invalidating your enumerable.
If you convert your enumerable to a list using .ToList() (this will cause the enumerable to iterate and give you a new list containing the items in the original) you will be able to iterate over this new enumerable and changes in the source won't affect you.
foreach (UltraGridRow row in uGridCache.Rows.ToList())
{
....
workerThread.ReportProgress(0, rowValues);
}
You will have to be aware that if something else is changing the rows on the grid, your ReportProgress might be reporting progress of something that no longer exists in the grid, you might want to check in your ReportProgress handler whether reporting on progress for that item is still valid before doing whatever you do.
The MSDN documentation on DoWork states the following:
"You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the BackgroundWorker events.".
You can view the full details of the DoWork method here:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx
Accessing the UltraGridRows from this event is causing you to access the UltraGrid from another thread and windows forms controls aren't thread safe.
Note that this isn't limited to accessing properties of the control. If you were to set values in the data source that the UltraGrid is bound to you would have the same issue as the change notifications would then happen on the background thread and the UI would still be manipulated from the background thread.
Note that there are only a few members that are actually thread safe on windows forms controls and these are documented in the section on Thread Safety for Control on MSDN: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.aspx
Safe, Simple Multithreading in Windows Forms is a good resource for threading in windows forms even though it is older:
Part 1: http://msdn.microsoft.com/en-us/library/ms951089.aspx
Part 2: http://msdn.microsoft.com/en-us/library/ms951109.aspx
Part 3: http://msdn.microsoft.com/en-us/library/ms993020.aspx
How to: Make Thread-Safe Calls to Windows Forms Controls is also a good resource
http://msdn.microsoft.com/en-us/library/ms171728.aspx

Resources