WPF ComboBox Binding To Object On Initial Load - c#

I have a combo box that is bound to a list of model objects. I've bound the combo box SelectedItem to a property that is the model type. All of my data binding works beautifully after the window has been loaded. The SelectedItem is set properly and I'm able to save the object directly with the repository.
The problem is when the window first loads I initialize the SelectedItem property and my combobox displays nothing. Before I moved to binding to objects I was binding to a list of strings and that worked just fine on initialization. I know I'm missing something but I can't figure it out.
Thanks in advance for any guidance you can provide.
(One note about the layout of this page. The combo boxes are actually part of another ItemTemplate that is used in a ListView. The ListView is bound to an observable collection in the main MV. Each item of this observable collection is itself a ModelView. It is that second ModelView that has the SelectedItem property.)
Here is my Model:
public class DistributionListModel : Notifier, IComparable
{
private string m_code;
private string m_description;
public string Code
{
get { return m_code; }
set { m_code = value; OnPropertyChanged("Code"); }
}
public string Name
{
get { return m_description; }
set { m_description = value; OnPropertyChanged("Name"); }
}
#region IComparable Members
public int CompareTo(object obj)
{
DistributionListModel compareObj = obj as DistributionListModel;
if (compareObj == null)
return 1;
return Code.CompareTo(compareObj.Code);
}
#endregion
}
Here the pertinent code in my ModelView:
public MailRoutingConfigurationViewModel(int agencyID)
: base()
{
m_agencyID = agencyID;
m_agencyName = DataManager.QueryEngine.GetAgencyName(agencyID);
IntializeValuesFromConfiguration(DataManager.MailQueryEngine.GetMailRoutingConfiguration(agencyID));
// reset modified flag
m_modified = false;
}
private void IntializeValuesFromConfiguration(RecordCheckMailRoutingConfiguration configuration)
{
SelectedDistributionList = ConfigurationRepository.Instance.GetDistributionListByCode(configuration.DistributionCode);
}
public DistributionListModel SelectedDistributionList
{
get { return m_selectedDistributionList; }
set
{
m_selectedDistributionList = value;
m_modified = true;
OnPropertyChanged("SelectedDistributionList");
}
}
And finally the pertinent XAML:
<UserControl.Resources>
<DataTemplate x:Key="DistributionListTemplate">
<Label Content="{Binding Path=Name}" />
</DataTemplate>
</UserControl.Resources>
<ComboBox
ItemsSource="{Binding Source={StaticResource DistributionCodeViewSource}, Mode=OneWay}"
ItemTemplate="{StaticResource DistributionListTemplate}"
SelectedItem="{Binding Path=SelectedDistributionList, Mode=TwoWay}"
IsSynchronizedWithCurrentItem="False"
/>

#SRM, if I understand correctly your problem is binding your comboBox to a collection of objects rather than a collection of values types ( like string or int- although string is not value type).
I would suggest add a two more properties on your combobox
<ComboBox
ItemsSource="{Binding Source={StaticResource DistributionCodeViewSource},
Mode=OneWay}"
ItemTemplate="{StaticResource DistributionListTemplate}"
SelectedItem="{Binding Path=SelectedDistributionList, Mode=TwoWay}"
SelectedValuePath="Code"
SelectedValue="{Binding SelectedDistributionList.Code }"/>
I am assuming here that DistributionListModel objects are identified by their Code.
The two properties I added SelectedValuePath and SelectedValue help the combobox identify what properties to use to mark select the ComboBoxItem by the popup control inside the combobox.
SelectedValuePath is used by the ItemSource and SelectedValue by for the TextBox.

don't call your IntializeValuesFromConfiguration from the constructor, but after the load of the view.
A way to achieve that is to create a command in your viewmodel that run this method, and then call the command in the loaded event.
With MVVM light toolkit, you can use the EventToCommand behavior... don't know mvvm framework you are using but there would probably be something like this.

Related

How to get specific item listbox C# MVVM WPF

Hi i try to get specific item from a listbox. I try to bind but i get crash. Using Prism framework how can i bind to get specific item from listbox, what template i need to make. This is test code:
<ListBox SelectedItem="{Binding SelectIndex}" HorizontalAlignment="Left" Height="297" Margin="57,41,0,0" VerticalAlignment="Top" Width="681">
<ListBoxItem>
<TextBlock Text="Test123"/>
</ListBoxItem>
<ListBoxItem>
<TextBlock Text="Test123"/>
</ListBoxItem>
</ListBox>
C# code:
public int SelectIndex
{
get
{
return 1;
}
}
How can i get if i want specific item from this list? What variable type need to make for binding listbox to select items?
It's crashing because you are binding SelectedItem (of type object) to your SelectIndex property (int property) in your view model (VM). ListBox like many WPF controls have distinct SelectedIndex and SelectedItem properties for binding.
If you want to bind to an int property in order to get the index you should be binding the ListBox's SelectedIndex property instead.
Change:
<ListBox SelectedItem="{Binding SelectIndex}" ...
...to:
<ListBox SelectedIndex="{Binding SelectIndex}" ...
Your VM remains as:
public int SelectIndex { get { return 1; } }
Though to be more useful and allow users to choose different items it should be:
public int SelectIndex { get; set; } // TODO: add support for INotifyPropertyChanged
Optionally you can add:
<ListBox SelectedIndex="{Binding SelectIndex}"
SelectedItem="{Binding SelectedItem}" ...
ViewModel:
public int SelectIndex { get; set; } // TODO: add support for INotifyPropertyChanged
// replace object with your type
public object SelectedItem { get; set; } // TODO: add support for INotifyPropertyChanged

Prevent DataGrid from updating selected item in MVVM

I have a Datagrid with a list binded to ItemsSource and the SelectedItem is binded a single object of this list. My ViewModel implements INotifyPropertyChanged.
The binding works fine, except when there's a variable (canSelectOtherObject = false) that prevents myObject of changing it's value. Even thought myObject doesn't modify it's value, the datagrid on the View selects other object. How can I prevent this?
View:
<DataGrid ItemsSource="{Binding MyObjectList}" SelectedItem="{Binding MyObjectSelected, Mode=TwoWay}">
ViewModel:
private ObservableCollection<MyObject> myObjectList;
private MyObject myObjectSelected;
private bool canSelectOtherObject;
public ObservableCollection<MyObject> MyObjectList
{
get { return myObjectList; }
set { myObjectList = value; }
}
public MyObject MyObjectSelected
{
get { return myObjectSelected; }
set
{
if(canSelectOtherObject)
{
myObjectSelected = value;
OnPropertyChanged("MyObjectSelected");
}
}
}
Thanks!
INotifyPropertyChanged is used to notify the UI to update bindings when the properties of an object change, I think you are describing a situation where the object itself changes.
Given your binding:
<DataGrid ItemsSource="{Binding MicrophoneList}" SelectedItem="{Binding MicrophoneSelected, Mode=TwoWay}">
It's the difference between updating one of the properties of the selected microphone (would require INotifyPropertyChanged), and changing SelectedItem to a different microphone altogether (binding updates whether you notify or not).

Unable to clear selection in a combobox

Simple enough requirement - trying to reset a WPF combobox on user press of a "clear" button. Everything else on the form clears as expected, with the exception of this ComboBox.
<ComboBox ItemsSource="{Binding Members}" DisplayMemberPath="MemberName" SelectedValue="{Binding RequestingMember, Mode=TwoWay}" SelectedValuePath="MemberID" IsEditable="{Binding FixedRequestingMember }"></ComboBox>
Here's the property it's bound to:
public int RequestingMember
{
get { return _requestingMember; }
set
{
if (_requestingMember != value)
{
_requestingMember = value;
}
}
}
And here's what I'm using to clear the box:
this.RequestingMember = -1;
Worth mentioning that there's nothing in the Members collection which corresponds to a key of -1. The value doesn't change from its selection when you press clear, anyway.
I've tried setting the int to 0 and also setting UpdateSourceTrigger=PropertyChanged in the XAML, to no avail. I'm loathe to change RequestingMemeber to a type of int? as it'll need fixes that cascade a long way into other parts of the application.
What am I doing wrong?
Please read the Use SelectedValue, SelectedValuePath, and SelectedItem page on MSDN for the full information on this, but in short, you will have more luck by data binding to the SelectedItem property, rather than using the SelectedValue and SelectedValuePath properties. Try adding a property of the same type as the items in the collection and data binding that to the SelectedItem property instead:
public Member SelectedMember // Implement the INotifyPropertyChanged Interface here!!
{
get { return selectedMember; }
set
{
if (selectedMember != value)
{
selectedMember = value;
NotifyPropertyChanged("SelectedMember");
}
}
}
You will also need to implement the INotifyPropertyChanged Interface in your class with the properties. Your XAML should now look like this:
<ComboBox ItemsSource="{Binding Members}" DisplayMemberPath="MemberName"
SelectedItem="{Binding SelectedMember, Mode=TwoWay}"
IsEditable="{Binding FixedRequestingMember }" />
Now all you need to do to clear the selection is this:
SelectedMember = null;

ListView Observable Collection Will Not Show Members

Cannot get my listview to display data.
XAML
<Grid>
<DockPanel>
<ListView Name="lstDetectedComputers"
MinWidth="200"
DockPanel.Dock="Left"
ItemsSource="{Binding ComputersList}" DisplayMemberPath="ComputerName">
</ListView>
<DataGrid x:Name="ViewNetworkCardInformation"
ItemsSource="{Binding NetworkCardInformation}"/>
</DockPanel>
</Grid>
Code:
private ObservableCollection<Object> _ComputersList;
public ObservableCollection<Object> ComputersList
{
get
{
return _ComputersList;
}
set
{
_ComputersList = value; NotifyPropertyChanged("ComputersList");
}
}
private DataTable _NetworkCardInformation;
public DataTable NetworkCardInformation
{
get
{
return _NetworkCardInformation;
}
set
{
_NetworkCardInformation = value; NotifyPropertyChanged("NetworkCardInformation");
}
}
Strange thing is that NetworkCardInformation shows in my datagrid so this indicates that the datacontext is working as expected.
now im under the impression with a ObservableCollection i do not need a INotifyPropertyChange, if this is wrong please advised.
i have also tried just ItemsSource="{Binding ComputersList}"
I have put a break point into the code to ensure that the observable collection has data, and it is there .
ComputersList Count = 2 System.Collections.ObjectModel.ObservableCollection
[0] {AdminUltimate.Model.NetworkModel.ComputerNode} object {AdminUltimate.Model.NetworkModel.ComputerNode}
ComputerName "ASUS-PC" string
Could someone please assist.
Thank you
You have set DisplayMemberPath as ComputerName but Object doesn't have any such property so it shows nothing on view.
This can be validated by removing DisplayMemberPath, you will see fully qualified class name of your object since ToString() gets called on your object if no ItemTemplate and DisplayMemberPath is set on ListBox.
So, solution would be to change ObservableCollection<Object> to type of more concrete object containing property ComputerName i.e. ObservableCollection<ComputerNode>.

Implementing 2-way binding for Combobox SelectedItem in Windows Store

I have a small problem with Combobox bindings in Windows Store app. It has to be bound to localized enumeration values (enumeration name is BackgroundTrack). I have 2 properties in view model - items list and selected item. I use Tuple<,> to hold enumeration value and its localized string representation.
Property for selected item in vm:
public Tuple<BackgroundTrack, String> SelectedBackgroundTrack
{
get
{
return _selectedBackgroundTrack;
}
set
{
if (_selectedBackgroundTrack == null ||
_selectedBackgroundTrack.Equals(value))
{
_selectedBackgroundTrack = value;
_settingsService.BackgroundTrack = value.Item1;
RaisePropertyChanged("SelectedBackgroundTrack");
}
}
}
Property for items list in vm:
public IEnumerable<Tuple<BackgroundTrack, String>> BackgroundTrackList { get; set; }
Combobox bindings:
<ComboBox
ItemsSource="{Binding Path=BackgroundTrackList}"
SelectedItem="{Binding Path=SelectedBackgroundTrack, Mode=TwoWay}"
Grid.Row="10" ItemTemplate="{StaticResource DataTemplate1}"
/>
<DataTemplate x:Key="DataTemplate1">
<Grid>
<TextBlock Text="{Binding Item2}"/>
</Grid>
</DataTemplate>
ViewModel constructor:
BackgroundTrackList = EnumUtils.GetLiterals<BackgroundTrack>();
SelectedBackgroundTrack = BackgroundTrackList.First(t => t.Item1.Equals(_settingsService.BackgroundTrack));
Problem: I'm setting selected item (from app settings) in ViewModel constructor, but this value does not show in combobox - it has nothing selected. If I select something in combobbox, the binding works correctly and sets the underlying ViewModel property. How do I correct this issue? Do I need to implement INotifyPropertyChanged or defer setting of selected item property programatically?
You need to implement IEquatable<T> on the type that is used for the item. Tuple does not.
You can't set both SelectedItem and SelectedValuePath at same time.
If you are using SelectedItem, remove SelectedValuePath and it will work as expected.

Categories

Resources