wpf programatically set combobox selected item when bound to dictionary - c#

I have a combobox which is bound do a dictionary
Dictionary<String, myClass> boxItems;
The combobox has the following dataTemplate:
<DataTemplate>
<TextBlock Text="{Binding Path=Key}"></TextBlock>
</DataTemplate>
This works fine for loading the values and getting the selected value, however I can't figure out how to set the selected value from codebehind.
any pointers?
I've tried setting selectedItem and selectedValue to a Key (which I know is in the dictionary), but when I load the page, the combobox hasn't selected anything.

Add this to your ComboBox
<ComboBox SelectedItem="{Binding SelectedBoxItem}"/>
And use this in a class that implements INotifyPropertyChanged:
private myClass _selectedBoxItem;
public myClass SelectedBoxItem
{
get { return _selectedBoxItem; }
set
{
_selectedBoxItem = value;
OnPropertyChanged("SelectedBoxItem");
}
}

You need to create a KeyValuePair with the key you want to select.
You can do something like this:
myCombo.SelectedItem = new KeyValuePair<string, int>("myKey", boxItems["myKey"]);

Related

WinRT apps: ComboxBox and ListBox does not display anything when ItemsSource is List<Type>

I tried to use ListBox to display a set of Type names
in XAML:
<ListBox x:Name="box"></ListBox>
and in code behind
box.ItemsSource= new List<Type>(){typeof(double), typeof(int)};
But the ListBox is displays empty string, although I can feel that there are indeed two items in the Items list and can click.
Even if I change the ItemTemplate to the following, the FullName property of class Type is not shown
<ListBox x:Name="box">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=FullName}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What is going on here? The following shows the name, but is not what I want. I want Type to be stored.
box.ItemsSource= new List<string>(){typeof(double).FullName, typeof(int).FullName};
(I tried ComboBox, which has the same problem)
This is really strange, there are no binding errors at all. I don't know why it happens when you bind to a Type object directly (maybe it has something to do with the System namespace), but there is a workaround which is to create a wrapper class:
public class TypeWrapper
{
private Type _type;
public TypeWrapper(Type type)
{
_type = type;
}
public Type Type { get { return _type; } }
}
Then you create the ItemsSource as following:
box.ItemsSource = new List<TypeWrapper>()
{
new TypeWrapper(typeof (double)),
new TypeWrapper(typeof (int))
};
And in your XAML you use
<TextBlock Text="{Binding Type.FullName}"></TextBlock>
instead of
<TextBlock Text="{Binding FullName}"></TextBlock>

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;

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.

WPF ComboBox Binding To Object On Initial Load

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.

Categories

Resources