0

I need help with this part of my code. I'm trying to do 2 things here:

1st, I need my comboBox cmbTechSearch filled with a list of names retrieved from a SQL database. Those names belong to an object called Tecnico. So far, so good. But if I click on the comboBox twice, I get the names duplicated... And so on. Adding cmbTechSearch.Items.Clear(); didn't solve it because the box was data binded, firing an error message. So I added cmbTechSearch.DataSource = null; which solved the error message but didn't clear my box. Nor did cmbTechSearch.ResetText(); Right now I'm unsure about how to clear it so that data doesn't come duplicated if I click the box again.

2nd, that list retrieved from SQL database brings more than just the name attached. It brings an e-mail for each object too. And I can't figure out how to retrieve the mail associated to the chosen name on that comboBox. Mind you, email is a global string var since I use it in other methods within the code. That part is commented because it doesn't work.

public void TechSearch_loaded(object sender, EventArgs e)

{

//all these 3 entries are supposedly to clear the comboBox cmbTechSearch; all of them fail but if I remove the 1st line I get an error saying that there's already some data bound to the box (but only if I click a 2nd time)

        cmbTechSearch.DataSource = null;
        cmbTechSearch.Items.Clear();
        cmbTechSearch.ResetText();

//there's a class called Tecnico and all the info about that object is saved on a SQL db. This part populates a list of Tecnicos with info from the db.

        List<Tecnico> tecnicos = new List<Tecnico>();
        tecnicos = bd.ProcuraPerfisTipo("TEC");

//then I get a list of Tecnicos and retrieve one attribute (Nome) for each tecnico in the list

        List<String> TechSearch = new List<String>();

        foreach (Tecnico obj in tecnicos)
        {
            TechSearch.Add(obj.Nome);
        }

//lastly I populate the comboBox with the info I got from the list.

        cmbTechSearch.DataSource = TechSearch;

        //email = cmbTechSearch.ToString();
    }

There's a class named Tecnico, another named BDTicketSQL and another named iBDTicketSQL (the first calling the SQL db and running updates, queries and inserts while the second is used for interface). Those classes are all external to this form. I just get date from them to populate the form with whatever info I need.

1 Answers1

0

Alright, so what you need to reduce your effort is DataBinding. Since you've mentioned databinding in your question, I am going to assume you know it. So I'll quickly run through the answer. Also since you hadn't mentioned any platform, I assumed it to be WPF but the code can be copied to WinRT or UWP if you want. Just incase it's a different platform, do let me know in the comments section Link to full solution In case you wana skip

Your XAML: I've used basic binding to codebehind to avoid a lot of classes for a sample. below is the code:

<StackPanel Margin="20">
    <ComboBox x:Name="UserCombobox"
              Height="20"
              Width="300"
              ItemsSource="{Binding DataFromSQLService,Mode=OneWay}"
              SelectedItem="{Binding CurrentSelectedUser,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
              ItemTemplate="{StaticResource UserDataTemplate}"
              SelectionChanged="UserCombobox_SelectionChanged"/>

    <Button Content="Clear Combo" Height="30" Width="100" Margin="10" Click="ClearData"/>

    <Button Content="Load Combo" Height="30" Width="100" Margin="10" Click="LoadData"/>

    <TextBlock Text="{Binding CurrentSelectedUser.Name,Mode=OneWay}" HorizontalAlignment="Center"/>

    <TextBlock Text="{Binding CurrentSelectedUser.Email,Mode=OneWay}" HorizontalAlignment="Center"/>

</StackPanel>

Now, your Window.Resources where you put your dataTemplate for your combobox Items.

 <Window.Resources>
    <DataTemplate x:Key="UserDataTemplate">
        <StackPanel>
            <TextBlock Text="{Binding Name}"/>
        </StackPanel>
    </DataTemplate>
</Window.Resources>

Now, self bind the view to it's codebehind, so in the Window Declaration add

DataContext = "{Binding RelativeSource={RelativeSource Self}}"

Now that the view is ready, let's quickly get our code behind ready.

A Dummy User Class you can replace this with your model class.

public class MyDummyUser
{
    public MyDummyUser(string name, string email)
    {
        Name = name;
        Email = email;
    }

    public string Name { get; set; }

    public string Email { get; set; }
}

Now Create a quick property to hold your currently selected user.

  private MyDummyUser currentSelectedUser;

  public MyDummyUser CurrentSelectedUser
    {
        get { return currentSelectedUser; }
        set { currentSelectedUser = value; RaisePropertyChanged(nameof(CurrentSelectedUser)); }
    }

Now create an observable collection to hold your data from the SQL service:

private ObservableCollection<MyDummyUser> dataFromSQLService;
    public ObservableCollection<MyDummyUser> DataFromSQLService
    {
        get { return dataFromSQLService; }
        set { dataFromSQLService = value; RaisePropertyChanged(nameof(DataFromSQLService)); }
    }

Now Implement INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    //if using c# 6.0 or later replace the above with
    //public void RaisePropertyChanged(string propertyName)=>
    //        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

Now Add a listener to the combobox.SelectionChanged event so that you know when the selected user changed:

 private void UserCombobox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        if (CurrentSelectedUser != null && !string.IsNullOrEmpty(CurrentSelectedUser?.Email?.Trim()))
        {
            //perform what you wana do with the email.
        }
    }

Create Two methods: LoadData and ClearData.

 private void ClearData(object sender, RoutedEventArgs e)
    {
        DataFromSQLService = null;
    }

    private void LoadData(object sender, RoutedEventArgs e)
    {
        List<MyDummyUser> someData = new List<MyDummyUser>()
        {
            new MyDummyUser("User 1","User1@gmail.com"),
            new MyDummyUser("User 2","User2@gmail.com"),
            new MyDummyUser("User 3","User3@gmail.com"),
            new MyDummyUser("User 4","User4@gmail.com"),
            new MyDummyUser("User 5","User5@gmail.com"),
            new MyDummyUser("User 6","User6@gmail.com"),
        };

        DataFromSQLService = new ObservableCollection<MyDummyUser>(someData);
    }

Please Note I've used an example of a WPF but even if you want to use the code for WinRT or UWP it'll work, just remember to switch Window.Resources with Page.Resources also, in UWP you can use x:Bind and using x:Bind can help you get rid of the RelativeResource=self

iam.Carrot
  • 4,976
  • 2
  • 24
  • 71
  • Thanks for the reply. That's a lot to digest... I did forget to mention that I'm working on Windows Forms. Does that make any difference? – Ricardo Pacheco Jun 04 '17 at 18:03
  • Well yes. Because in winForms you don't have xaml. So data binding will have to be done in another way. So for applying the databinding use https://stackoverflow.com/q/2251075/3766231 – iam.Carrot Jun 04 '17 at 18:07
  • I don't have much experience with winForms but I'll try to get a sample for you. – iam.Carrot Jun 04 '17 at 18:08
  • Oh. Sorry. I should have mentioned that on my original post. Thing is my data is working quite well. My most pressing problem is the clearing combo box of content since it keeps adding the same data over and over. – Ricardo Pacheco Jun 04 '17 at 18:25
  • Can you share some more code? I can't even make out what your code is doing. Is there a sample I can look at? – iam.Carrot Jun 04 '17 at 18:26
  • I'll try. Bare with me, please. A bit new in here and sometimes my posts don't come out the way I want. – Ricardo Pacheco Jun 04 '17 at 18:35
  • Updated the original post with comments for each part of the text. The form itself is already built and working like a charm. I'm having a bit of trouble getting things running the way they're supposed to. If it helps out to put you in context, this is a ticket program. I'm opening tickets and delegating them. Here I'm trying to get a list of all the technicians who might have a ticket associated to them. I chose a technician's name, press search and get a list of tickets associated to said technician. – Ricardo Pacheco Jun 04 '17 at 18:49