I am trying to extend the Silverlight Validation to include severity. I am taking the approach of adding a special character at the beginning of the message to indicate if it is an error or a warning, and changing the style to either red or blue. I have successfully implemented this for the Validation Summery control, input controls and ValidationToolTips by specifying a custom Style and using value converters. But I can't seem to get it to work with labels.
My problem is that I can’t seem to bind the validation message. I have tried the following without any success:
OR
Can someone please provide some help or suggest an alternative approach.
Links and or sample code is greatly appreciated.
I've solved this by throwing exceptions of different types (the ValidationWarning exception for warnings). Each time when validation exception is thrown, the BindingValidationError event is triggered. In event handler I check for exception type and change the style depending on exception:
private void OnBindingValidationError(object sender, ValidationErrorEventArgs e)
{
var textBox = sender as TextBox;
if (textBox != null)
{
if (e.Error.Exception is ValidationWarning)
{
UpdateStyle(textBox, "TextBoxWithWarning");
}
else
{
UpdateStyle(textBox, "TextBoxWithError");
}
}
}
private static void UpdateStyle(TextBox textBox, string styleName)
{
var newStyle = (Style)Application.Current.Resources[styleName];
if (textBox.Style != newStyle)
{
textBox.Style = newStyle;
textBox.Focus();
}
}
Related
using rxBindings im trying to slow down a click event but i would like to know what the parameter is need.
For example, here is a call i am doing on a imageview. So ImageView v;
RxView.clicks(v)
.throttleFirst(400, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
#Override
public void accept(#io.reactivex.annotations.NonNull Object v) throws Exception {
showBottomSheet(getAdapterPosition());
}
});
but im im not sure what the parameter in accept should be ?
I was expecting i would get the view here but when i try changing the type to View i get an error of no such method.
If you look at the source code of the Observable generate using RxView.clicks(), you will see that when the click happens, the following code is triggered:
observer.onNext(Notification.INSTANCE);
that is defined in the library, as:
public enum Notification {
INSTANCE
}
It is just a convenient way for indicating that the event happened, it doesn't carry any extra information.
I am making a media app. In which I load playlists and then when I play from one playlist, it plays fine, but I have the same file in another playlist, It gives an exception, of system dubugger like this
I am using following code when gridview selection changes to play the file.
private async void PlaylistGridView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
if (PlaylistGridView.SelectedIndex != -1)
{
CurrentlyPlayingVideo = (VideoFile)PlaylistGridView.SelectedItem;
CurrentlyPlayingFile = CurrentlyPlayingVideo.File;
var s = await CurrentlyPlayingFile.OpenReadAsync();
var sq = me;
me.SetSource(s, CurrentlyPlayingFile.ContentType);
}
}
catch { }
}
the message in e.Message is 'Object refrence is not set to instance of object',
I surely know it is null type error, but problem is i dnt know which object is null!!, I am even using try catch blocks, but still its giving that exception in the picture above, and not telling me the object which is null, until i dnt know which object is null, how can i fix the error?
EDIT :
I tried to run in release mode with visual studio and this is the error i get even before trying to play anything.
Object reference is not set to instance of an object
I had seen this error when I build an uwp too. If I'm not mistaken, any of your Control (Button , Textblock , etc) is called by any of your method (including event) before they have been initialized to the Page Check the calling once again
I want to suppress the MFC error message on data validation:
void CMotorView::DoDataExchange(CDataExchange* pDX)
{
DDX_Text(pDX, IDC_AMBIENTTEMP, m_pSet->m_AmbientTemp);
}
If the text in editcontrol IDC_AMBIENTTEMP is non numeric on saving data to variables, the framework will show a messagebox prompting the user to enter a number. I want to suppress this message, and handle the error in my own code.
I assumed the framework will throw an exception in case of validation error, but this appears not to be the case. Neither does DDX_Text return a value What am I doing wrong?
void CMotorView::DoDataExchange(CDataExchange* pDX)
{
try
{
DDX_Text(pDX, IDC_AMBIENTTEMP, m_pSet->m_AmbientTemp);
}
catch(CUserException* ex)
{
// nothing caught here
}
catch(...)
{
// nothing caught here either
}
}
In case of an error DDX_Text first displays an error dialog, then it throws an exception. You can catch this with catch(CUserException *e). Please note that a pointer is thrown!
I'd suggest that you either DDX_Text to a string. This does not fail and you can then check if the string is really a number. Or you can write your own DDX_TextMyFn to do what you want. You can use the MFC original function as a base implementation.
Set ES_NUMBER as a style for the edit control. This will reduce errors user can make.
The message boxes inside the DDX routines can't be suppressed or redirected.
Here is some pseudocode that uses a class CEditInt that has a member unction GetValue/SetValue.
You can also write a DDX_EditInt routine that works on a CEdit control and use Get/SetDlgItemInt.
void AFXAPI DDX_EditInt(CDataExchange* pDX, int nIDC, int &iValue)
{
// Get pointer to control
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
CEditInt *pWnd = (CEditInt *)CWnd::FromHandle(hWndCtrl);
// Must be an CEditInt
ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CEditInt)));
// get the information from the defined window
if (pDX->m_bSaveAndValidate)
// Get the Value
iValue = pWnd->GetValue();
else
pWnd->SetValue(iValue);
}
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));
I have a Silverlight form that performs exception-based data validation. I learned how to do this data validation the following way:
Set controls to be validated as follows:
<TextBox Text="{Binding Mode=TwoWay,NotifyOnValidationError=True, Source={StaticResource docSan}, Path= metadati.paziente.residenza, ValidatesOnExceptions=True}"/>
Make the target property work as follows
public new string residenza
{
get { return base.residenza; }
set
{
if (string.IsNullOrEmpty(value)) throw new ArgumentNullException("value");
base.residenza = value;
}
}
Where the base class defines a non-validating property in an INotifyPropertyChanged way
Unfortunately VS2010 at design time warns me about the exception for each text box. This doesn't prevent the application from running (it works fine) but it's just annoying.
Somebody knows how to tell VS that it's OK if at design time no value is specified thus the code throws naturally?
If I understand correctly, it is the if ... throw statement in the setter that causes the warnings in the designer?
I think you can use the DesignerProperties.IsInDesignTool to prevent this line from running in design-time:
set
{
if (!System.ComponentModel.DesignerProperties.IsInDesignTool)
{
if (string.IsNullOrEmpty(value)) throw new ArgumentNullException("value");
}
base.residenza = value;
}