Reputation: 183
Objective: having bound the SelectedItem of a ListBox (or ComboBox) to an instance of an object through xaml, I would like to set the selected instance of the object through the view model and have it reflect on the ListBox or ComboBox.
<ComboBox x:Name="cboServers" HorizontalAlignment="Left" Margin="535,694,0,0" VerticalAlignment="Top" Width="225"
ItemsSource="{Binding Settings.Servers}"
SelectedItem="{Binding Settings.SelectedServer, Mode=TwoWay}"
DisplayMemberPath="UserFriendlyName">
C# Model View code
public ObservableCollection<AutoSyncServer> Servers { get; set; }
private AutoSyncServer _selectedServer;
public AutoSyncServer SelectedServer
{
get { return _selectedServer;}
set
{
_selectedServer = value;
OnPropertyChanged("SelectedServer");
}
}
The list or combo box populates correctly. Selecting an item on the ListBox or ComboBox will correctly set the SelectedServer object.
However, if I try to write a set statement in C# such as:
Servers.Add(newServer);
SelectedServer = newServer;
The ListBox or ComboBox will correctly add the item and the SelectedServer object will be correctly set on the MVVM model, but the front end will not reflect this selection.
In this specific case, an xml file is read saying what the user had selected last, and when the window opens the ComboBox has nothing selected (the servers are all loaded correctly within it though)
What's missing here?
Upvotes: 0
Views: 467
Reputation: 37060
The actual object in SelectedItem
must be an object instance which is found in the Servers
collection, in the Object.ReferenceEquals(a, b)
sense. Not just the same Name and ID (or whatever) properties; the same exact class instance.
The classic case where people run afoul of this is deserializing equivalent items in multiple places. Servers
has a collection of deserialized AutoSyncServer
instances, and Settings.SelectedServer
is a separately deserialized AutoSyncServer
instance, which has identical property values to one of the items in Servers
. But it's still a different object, and the ComboBox
has no way of knowing that you intend otherwise.
You could override AutoSyncServer.Equals()
to return true if the two instances of AutoSyncServer
are logically equivalent. I don't like doing that because it changes the semantics of the =
operator for that class, which has bitten me before. But it's an option.
Another option is to have one canonical static collection of AutoSyncServer
and make sure every class gets its instances from that.
I don't understand why this code didn't work, given the above:
Servers.Add(newServer);
SelectedServer = newServer;
Once newServer
is in Servers
, it should be selectable. I tested that and it's working for me as you would expect.
Upvotes: 2
Reputation: 622
i think you must avoid "sub-bindings", they work once when the view ask for, but not well after Settings.SelectedServer ==> SelectedServer
and if you comment OnServerChanged?.Invoke(this, _selectedServer);
what is happening ? it works ?
Upvotes: 0