none
Error handling a unique id comparer

    Question

  • Hi everyone I have a class that I use to compare the Id's in an observable collection so the user can't use an id that already exists. When he does this a message box pops out telling him it's the same. What I would like to do is instead of the message box, have the text box turn red and the tooltip to tell him that it is a duplicate.

    I already have such error handling for different validation, like, I have a validator checking if it's a number, and if that number is above 0. I just don't know how to implement it for this comparer class.

    Here is the code:

    The Id Comparer class

    class IdComparer : IEqualityComparer<Dobavljac>
        {
            
           
                
                public bool Equals(Dobavljac x, Dobavljac y)
                {
    
                    
                    if (x.Dob_Id == y.Dob_Id)
    
                    {
                        return true;
    
                    }
    
                    else
    
                    {
                        return false;
                        
                    }
    
    
    
                }
    
    
                public int GetHashCode(Dobavljac dobavljac)
                {
                    
                    if (Object.ReferenceEquals(dobavljac, null)) return 0;
    
           
                    int hashProductCode = dobavljac.Dob_Id.GetHashCode();
    
                    return hashProductCode;
                }
    
            }
    
        }
    

    The presenter method where I call the comparer

     public void SaveDobavljac(Dobavljac dobavljac)
            {
                //bool jednako=dobavljac.Equals(new IdComparer());
                if (dobavljac.IsNew== true)
                {
                    if (!CurrentDobavljac.Contains(dobavljac, new IdComparer()))
    
    
    
                        try
                        {
    
                            _dobavljacRepository.Save(dobavljac);
    
                            CurrentDobavljac.Add(dobavljac);
    
                            StatusText = string.Format("Dobavljac '{0}' je spašen.", dobavljac.LookupDobavljac);
                        }
                        catch
                        {
    
                            MessageBox.Show("Doslo je do greske ");
    
                            StatusText = string.Format("Dobavljac '{0}' nije spasen.", dobavljac.LookupDobavljac);
                        }
                    else
                    {
                        MessageBox.Show("Taj Dobavljac vec postoji ");
    
                        StatusText = string.Format("Dobavljac '{0}' nije spasen.", dobavljac.LookupDobavljac);
                    }
            }
                else
                {
                    _dobavljacRepository.Update(dobavljac);
                }
            }


    The validator that checks the user is typing in numbers and that they are bigger than 0

    public class Validators:ValidationRule
        {
          
    
          public override ValidationResult Validate(object value,
                System.Globalization.CultureInfo cultureInfo)
            {
                int IntValue=0;
               
                try
                {
                   IntValue=Convert.ToInt16(value);
                   
                }
                catch (Exception)
                {
                    return new ValidationResult(false, "Molimo upišite broj");
                }
    
                if (IntValue < 0) return new ValidationResult(false, "Molimo upišite broj veći od 0");
    
                
                return new ValidationResult(true, null);


    The error handling method in the backing code for the view.

     private void TextBox_Error(object sender, ValidationErrorEventArgs e)
            {
                if (e.Action == ValidationErrorEventAction.Added)
                {
                    ((Control)sender).ToolTip = e.Error.ErrorContent.ToString();
                }
                else
                {
                    ((Control)sender).ToolTip = "";
                }
            }


    The wpf code for the text box I am implementing this for

    <TextBox x:Name="id"
                                 
                                 Grid.Column="1"
                            Validation.Error="TextBox_Error">
                            <TextBox.Text>
                                <Binding Path="Dobavljac.Dob_Id" ValidatesOnExceptions="True" NotifyOnValidationError="True" ValidatesOnDataErrors="True">
                                <Binding.ValidationRules>
                                    <p:Validators/>
                                </Binding.ValidationRules>
                            </Binding>
                            </TextBox.Text>
                        </TextBox>

    I know it's a lot of code and maybe you guys didn't need some of it but I figure the more information I give you the better chances are you can help me.

    And any help would be greatly appreciated.

    Friday, May 11, 2012 6:57 AM

All replies

  • Hi dino2dy,

    I understand you want to validate User input text if is repeat in IDs. I think you can Select the ID in your database to see if there is already one in TextBox LostFocus event to achieve your goal.

    Hope it helps.

    Have a nice day.


    Annabella Luo[MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, May 15, 2012 4:11 AM
    Moderator
  • Hi Annabella

    I use a Comparer instead of selecting the ID's from the database. Because I use the model view presenter pattern and I don't work with DataSets I use Adapters. Right now what happens is that if the user writes an already existing Id and clicks the Save button a messagebox pops up telling him he is wrong.

    What I would like to do is avoid this and before he clicks save, like you say, on lost focus, get the text box to go all red and in the tooltip give him an error description.

    Lost focus is a great idea but I'm afraid I don't know how to implement my code with that event to get the functionality I need.

    If you could help I would appreciate it.

    Either way, thanks for your reply.

    Tuesday, May 15, 2012 6:13 AM
  • Hi dino2dy,

    You're following any MVVM pattern. To validate data, you need to implement the IDataErrorInfo on your view model. Create your own validation rule as:http://msdn.microsoft.com/en-us/library/system.windows.data.binding.validationrules.aspx and also set the validation error template and binding error information with ToolTip.

    And here is a sample about validate in MVVM for your reference:http://weblogs.asp.net/marianor/archive/2009/04/17/wpf-validation-with-attributes-and-idataerrorinfo-interface-in-mvvm.aspx

    Hope it helps.

    Have a nice day.


    Annabella Luo[MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, May 15, 2012 7:31 AM
    Moderator
  • Ok so I use that when setting the errors for the key having to be a number and for it having to be bigger than 0.

    public class Validators:ValidationRule
        {
          
    
          public override ValidationResult Validate(object value,
                System.Globalization.CultureInfo cultureInfo)
            {
                int IntValue=0;
               
                try
                {
                   IntValue=Convert.ToInt16(value);
                   
                }
                catch (Exception)
                {
                    return new ValidationResult(false, "Molimo upišite broj");
                }
    
                if (IntValue < 0) return new ValidationResult(false, "Molimo upišite broj veći od 0");
    
                
                return new ValidationResult(true, null);

    But how do I define a rule here for the key being unique? Because this is what you are telling me to do? Or have I completely missed the point?

    Because if I do it here then the error handling is already done in the backing code for the view

    private void TextBox_Error(object sender, ValidationErrorEventArgs e)
            {
                if (e.Action == ValidationErrorEventAction.Added)
                {
                    ((Control)sender).ToolTip = e.Error.ErrorContent.ToString();
                }
                else
                {
                    ((Control)sender).ToolTip = "";
                }
            }
    So It will catch the error. The problem is that I tried creating it in the validation class but I couldn't. Then I posted on the forum and got told to use the comparer which really works. But pops a message box for the error which I want to avoid.
    Tuesday, May 15, 2012 7:40 AM
  • Hi dino2dy,

    Yes it's true that in IDataErrorInfo or validation Rule, we can validate if the User Name is exist. It is seemed that the LostFocus event of TextBox is the key of your issue.

    So what we can do is to move the Lostfocus event from code behind to ViewModel, to excute a command when the LostFocus event fired, you can refer to below two way to achieve that:

    http://social.msdn.microsoft.com/Forums/en/wpf/thread/aa14c9d7-13a3-41c7-85f2-610018b63f5d

    http://blog.functionalfun.net/2008/09/hooking-up-commands-to-events-in-wpf.html

    Hope it helps.

    Have a nice day.


    Annabella Luo[MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, May 15, 2012 8:37 AM
    Moderator
  • Ok so I use the MVP pattern not the MVVM pattern. So not sure how to work with commands or if I even can in the mvp pattern.

    Also not sure that this is what I need because I have the code that checks the ID's. And I already have the TextBoxError event that fires when it gets a false validation result and gives me the functionality I need (on lost focus).

    The problem is that I couldn't fit in the check for whether the key is Unique in the validator class. I had to create a Comparer class.

    That class is then instanced in the application presenter (the main presenter) which then sends a message box error if the comparison returns true.

    I am sorry I am a newbie so am having trouble explaining to you and understanding what you are telling me.


    Tuesday, May 15, 2012 10:29 AM
  • Ok here is the latest failed attempt:

    I have this text changed event

    private void id_TextChanged(object sender, TextChangedEventArgs e)
            {
                string val_id;
                val_id = this.id.Text;
    
                Presenter.Validate(val_id);
            }
    

    Which sends the value in the text field to the presenter

     public int Validate (string val_id)
            {
                _test = new ObservableCollection<Dobavljac>(_dobavljacRepository.FindById(val_id));
    
                IntValue=1;
                bool unique=true;
                if (Test.Count() == 1)
                {
             
                 unique = false;
                }
    
                else
                {
                    unique = true;
                }
    
                if (unique == false)
                {
                    IntValue = 0;
                }
      
                return IntValue;
    
            }

    And there I have this IntValue to be 0 in case my field is not unique. How can I now send that IntValue to the Validator class?

    public class Validators:ValidationRule
        {
            private int _IntValue;
    
            public int IntValue
            {
                get { return _IntValue; }
                set { _IntValue = value; }
            }
    
    
    
          public override ValidationResult Validate(object value,
                System.Globalization.CultureInfo cultureInfo)
            {
                
               
                
                try
                {
                  IntValue= Convert.ToInt16(value);
                   
                }
                catch (Exception)
                {
                    return new ValidationResult(false, "Molimo upišite broj");
                }
    
                if (IntValue < 0) return new ValidationResult(false, "Molimo upišite broj veći od 0");
                if (IntValue == 0) return new ValidationResult(false, "Taj Id vec postoji u bazi");
                //if (!CurrentDobavljac.Contains(dobavljac, new IdComparer()))) return new ValidationResult (false, "Taj Dobavljac vec postoji");
                
                return new ValidationResult(true, null);
    
                
          }
    
    
        }

    As you can see I did a rule in the validator class that if the value is 0 it is a unique id. And I did the test for it in the presenter so that it returns 0 if the id is unique.

    How can I get that value to the validator class?

    Please people help.

    Monday, May 21, 2012 10:37 AM
  • Hi,

    You can validate you values on PreviewLostKeyboardFocus event

    private void TextBox_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
            {
                if (ValidateValue(TextBox.Text) == false)
                {
      //Avoid lost focus
                    e.Handled = true;
                }
            }

    and by setting e.Handled = true, you can avoid the focus lost from your text box until user enter new valid value.

    Hope this will help you :)

    Monday, May 21, 2012 11:27 AM
  • Hi Ahmed Thanks for the reply.

    Would you mind showing me how would this be applied to my problem specifically? Because I am having trouble understanding how to use this to solve my problem.

    Monday, May 21, 2012 11:33 AM
  • Hi dino2dy,

    To handle the lostfocus event in command can help you maintain the MVVM partten, why don't you just see the links I post here in my last reply, and give a little effort to try? If you don't try to resolve your issue, we can't help you neither.

    Have a nice day.


    Annabella Luo[MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, May 22, 2012 4:38 AM
    Moderator
  • Hi Annabella

    Here is the thing. I don't see how your solution can work for me. But since I'm out of ideas I have implemented it anyway.

    I created the EventBehaviourFactory and the static class for the text changed behaviour.

    Then in my Presenter for the View or the ViewModel if you will I put the code that gets called for the event. And this works. The message box pops up every time the text is changed.

    Now here are the problems:

    I have the view model class for that view. But I need it to go to another class, the mainViewModel class if you want.

    Usually if I'm working with events it is enough to do something like this

    public void Close()
            {
                _applicationPresenter.CloseTab(this);
            }

    And that transfers the method or the event to the applicationPresenter class where I have the CloseTab method defined.

    I don't know how to do this with this though

    public ICommand TextChanged
            {
                get
                {
                    //  this is very lazy: I should cache the command!
                    return new TextChangedCommand();
                }
            }

    private class TextChangedCommand : ICommand { public event EventHandler CanExecuteChanged; public void Execute(object parameter) { MessageBox.Show("Text Changed"); } public bool CanExecute(object parameter) { return true; } }

    I don't know if this should be a totally new class? I don't think so but haven't really worked with the MVVM class so...

    The other and I think much bigger problem is that once I have done this is I need to pass a changing parameter from here to the Validators class which inherits from the ValidationRule class and I can't see any way of doing that. I need to somehow get the function for testing whether the key is unique to return a value which will then be passed or transferred somehow into that Validators class and there I can create a Validation rule for that value. But I have no idea how this will help me achieve that.

    If there is another way to do it, and I am being an idiot, which is very likely, please point me to it cos I honestly don't know.


    • Edited by dino2dy Tuesday, May 22, 2012 7:50 AM
    Tuesday, May 22, 2012 7:47 AM