S
S
Sasha Pleshakov2016-06-04 21:04:13
WPF
Sasha Pleshakov, 2016-06-04 21:04:13

How to bind Dictionary to combobox via {Binding}?

The Dictionary is populated with items, but no binding occurs. What is the problem?

<ComboBox Margin="0,0,10,0" ItemsSource="{Binding clients}"
    SelectedValuePath="Key" DisplayMemberPath="Value"/>

Declaring and initializing a Dictionary variable
Dictionary<string, string> clients;
 
public AddOrder()
{
    InitializeComponent();    
    connection = new OleDbConnection(ConfigurationManager.ConnectionStrings["AccessBarbershop"].ConnectionString);
    clients = GetClients();
}

A method that returns a Dictionary.
private Dictionary<string, string> GetClients()
{
    Dictionary<string, string> clients = new Dictionary<string, string>();
    using (connection)
    {
        if (connection.State != ConnectionState.Open)
            connection.Open();
        string request = "SELECT Код_Клиента, ФИО FROM Клиенты";
        using (OleDbCommand command = new OleDbCommand(request, connection))
            using (OleDbDataReader reader = command.ExecuteReader())
                while (reader.Read())
                    clients.Add(reader["Код_Клиента"].ToString(), reader["ФИО"].ToString());
    }
    return clients;
}

Changed methods and added a class.
private ObservableCollection<Clients> GetClients()
{
    var clients = new ObservableCollection<Clients>();
    if (connection.State != ConnectionState.Open)
        connection.Open();
    string request = "SELECT Код_Клиента, ФИО FROM Клиенты";
    using (OleDbCommand command = new OleDbCommand(request, connection))
    using (OleDbDataReader reader = command.ExecuteReader())
        while (reader.Read())
            clients.Add(new Clients(reader["Код_Клиента"].ToString(), reader["ФИО"].ToString()));
    return clients;
}
}

public class Clients : INotifyPropertyChanged
{   
public Clients(string id, string name)
{
    ID = id; Name = name;
}
string id;
public string ID
{
    get { return id; }
    set { id = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ID")); }
}
string name;
public string Name
{
    get { return name; }
    set { name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); }
}

public event PropertyChangedEventHandler PropertyChanged;
}

<ComboBox Margin="0,0,10,0" ItemsSource="{Binding clients}"
    SelectedValuePath="ID" DisplayMemberPath="Name"/>

solution

Answer the question

In order to leave comments, you need to log in

3 answer(s)
S
Stanislav Makarov, 2016-06-04
@mnepoh

You did everything wrong.
1) For bindings to work, the object to which the property you are binding (i.e. the one WHERE clients are located) must implement INotifyPropertyChanged and pull PropertyChanged when its properties change so that the binding can know about it; in your particular case, this may not be so critical, but as soon as there are other properties besides clients of the primitive type, you will realize that you cannot bind to them;
2) For bindings to work, you need to bind to properties. Yes, the field will probably work, but from the point of view of the architecture and the idea of ​​​​MVVM, this is movement against the wind;
3) The binding in your case partly works because it apparently pulls data from the dictionary when it already exists and the elements are loaded into it, but does not receive information that the contents of the dictionary are somehow changing. She can't get this information, because. a regular dictionary does not implement INotifyCollectionChanged. I draw your attention, this is a different interface for collections. Collections that implement it raise a CollectionChanged event when they are changed by someone. This allows all bindings to be notified of all changes to the collection, such as when you add a new element to the collection. Of the standard collections that implement INotifyCollectionChanged, there is ObservableCollection, the functionality of which is enough in 95% of cases. This is the most common collection (read - a list. But not a dictionary!), with the difference that it implements INotifyCollectionChanged,
4) Binding to dictionary elements is also not a good idea, especially if you don't fully understand how things work. Taking into account point 3, it is much more reasonable to make the Client view model with the Id and Name properties, and use ObservableCollection<ClientViewModel>. At the same time, the ClientViewModel must implement INotifyPropertyChanged if its properties can change. Accordingly, SelectedValuePath will be Id (if you need), and DisplayMemberPath will be Name. That's when everything should work.

#
#algooptimize #bottize, 2016-06-04
@user004

в одном месте
using (connection)
   в другом
connection = new OleDbConnection

why?
related
binding
source
datacontext
elementname
source
public property get (not field)

R
Roman, 2016-06-05
@yarosroman

Has the DataContext been assigned?

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question