Getting SelectedItem of ComboBox (MVVM) - c#

I'd like to get the selected Item of a ComboBox using the MVVM Pattern (beginner).
I've read that this could be achieved by binding the SelectedItem Property to a Property in the ViewModel.
XAML:
<ComboBox ItemsSource="{Binding RoomLockerLinkCollection}"
DisplayMemberPath="Room.Name"
SelectedItem="{Binding SelectedRoom}"/>
ViewModel:
public Room SelectedRoom { get; set; }
But it's not working - the only thing thats happening is a appearing red border around that ComboBox - in addition after selecting a new item in the ComboBox the "SelectedRoom" property in my VM is still null.
Edit 1 :
One short additional question:
The binding works fine - at least for the top "category". My Wrapper-Class also contains a list of lockers.
<ComboBox DataContext="{Binding SelectedItem, ElementName=_cmbRoomSelection}" ItemsSource=" {Binding LockerCollection}" DisplayMemberPath="Name" SelectedValue="{Binding SAVM.SelectedLocker, Mode=TwoWay}" />
When I check the type of the SelectedValue it's a "Locker" - fine.
But the SelectedLocker-Property in my VM stays null...
Additional, could s.o. explain when to use "SelectedItem" and "SelectedValue"? What's the difference? Setting the DataContext in the xaml code above can not be done by binding the SelectedValue...
Edit 2 (Solution) :
Okay, got it!
As I figured out I've reset my DataContext - now the Property SAVM of course could not be found.
Solution:
<ComboBox DataContext="{Binding SelectedItem, ElementName=_cmbRoomSelection}"
ItemsSource="{Binding LockerCollection}"
DisplayMemberPath="Name"
SelectedValue="{Binding SAVM.SelectedLocker **ElementName=_vStorage**, Mode=TwoWay}" />

The red box is an indication of a validation error from your Binding ,
The most common error would be that the BindingSource and the BindingTarget are not of the same type.
Use SelectedValue and SelectedValuePath to bind to your Room object.
CS :
public class Room
{
public string RoomName { get; set; }
}
public class RoomWrapper
{
public Room Room { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
public List<RoomWrapper> RoomWrappers
{
get
{
var list = new List<RoomWrapper>();
for (int i = 0; i < 10; i++)
{
list.Add(new RoomWrapper { Room = new Room { RoomName = "Room " + i } });
}
return list;
}
}
private Room selectedRoom;
public Room SelectedRoom
{
get { return selectedRoom; }
set
{
selectedRoom = value;
}
}
XAML :
<ComboBox ItemsSource="{Binding RoomWrappers}"
DisplayMemberPath="Room.RoomName"
SelectedValuePath="Room"
SelectedValue="{Binding SelectedRoom, Mode=TwoWay}" />

Related

Populate RadComboBox from enum list in WPF MVVM

I found some topics "How to bind a combobox from enum list", but my problem is that I try to use MVVM arhitecture and let my View (xaml) clear as you see below:
part of View (xaml.cs):
public partial class GreenCertificatesStockForm : Erp.Core.Wpf.BaseWindow
{
private Models.GreenCertificatesGroupModel model;
public GreenCertificatesStockForm()
{
model = new Models.GreenCertificatesGroupModel();
this.DataContext = model;
InitializeComponent();
model.LoadForm(); // propose some dates for my form
model.RequestClose += () => { Close(); };
}
}
part of View (xaml) my RadComboBox:
<telerik:RadComboBox Name="certificatesTypeRadComboBox"
Margin="5 2 0 2" Width="150"
SelectedValue="{Binding CertificatesTypeEnum , Mode=TwoWay,
ValidatesOnDataErrors=True,
ValidatesOnExceptions=True,
NotifyOnValidationError=True}"
ItemSource="{Binding }"
SelectedItem="{Binding }"
telerik:StyleManager.Theme="Office_Blue" BorderBrush="#FF707070" Background="#FFDDDDDD"
>
</telerik:RadComboBox>
So, my Enum list is created in my ViewModel (class.cs) as:
public enum CertificatesTypeEnum {
Estimat = 1,
Calculat = 2,
Facturat = 3
}
I need to display in my RadComboBox all Values of the Enum and by selectedValue to save the specific Key of selection in DB (this with a parameter). How can I display the values from ViewModel into ComboBox (View)?
I know can do something like :
var items = Enum.GetValues(typeof(CertificatesTypeEnum)).Cast<CertificatesTypeEnum>().Select(i => new ComboboxItem()
{ Text = Enum.GetName(typeof(gender), i), Value = (int)i}).ToArray<ComboboxItem>();
//Add the items to your combobox (given that it's called comboBox1)
RadComboBoxName.Items.AddRange(items);
but this must be made in xaml.cs file (and I don't want this solution), because in ViewModel the combobox are not recognised and will be not found.
In short : display Values of Enum list from ViewModel class in xaml file.
Why don't you just call the Enum.GetValues method in the view model? This is MVVM:
public class GreenCertificatesGroupModel
{
public IEnumerable<CertificatesTypeEnum> EnumValues
{
get
{
var list = Enum.GetValues(typeof(CertificatesTypeEnum)).Cast<CertificatesTypeEnum>();
return list;
}
}
private CertificatesTypeEnum _selectedItem;
public CertificatesTypeEnum SelectedItem
{
get { return _selectedItem; }
set { _selectedItem = value; }
}
}
XAML:
<telerik:RadComboBox ItemsSource="{Binding EnumValues}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />

How to pass data from DataContext to ListBox in WPF?

I have a class defined like:
public class Agent
{
public int Id { get; set; }
public string Category { get; set; }
// rest removed for brevity
}
Then, in WPF, I get the data as List and pass it to DataContext as this:
List<Agent> agents; // this includes my data
this.DataContext = agents;
And in .xaml part I want to list the Category field of each object. I have something like this:
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
Grid.Column="1"
ItemSource="{Binding Path=Category"} />
But this doesn't seem to work correctly. Any ideas?
Let me help you to do this in the correct way as Alex suggested.
Create a list and populate it in ViewModel like this
ViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
agents = new ObservableCollection<Agent>();
LoadData();
}
private void LoadData()
{
agents.Add(new Agent { Id = 1, Category = "a" });
agents.Add(new Agent { Id = 2, Category = "b" });
agents.Add(new Agent { Id = 3, Category = "c" });
}
}
In XAML, Make your list and use data template like this:
<Window.Resources>
<DataTemplate x:Key="AItemTemplate">
<TextBlock Text="{Binding Category}"></TextBlock>
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource="{Binding agents}"
ItemTemplate="{StaticResource AItemTemplate}"></ListBox>
That is it !!
Normally the DataContext would be a view model class that would contain the list of agents; then you can bind the ItemsSource to that list. Any of the many examples that deal with listbox will be pretty straight forward when it comes to that. Not really sure how the binding should look like if the list itself is the DataContext.
Then once the ItemsSource is set to a list of agents, if you want to show the Category in the list, the simpler way is to set DisplayMemberPath to "Category".
I suggest looking into MVVM and learning to apply it, it's an invaluable concept in my opinion.
You try to bind your listbox to a string property.
You can try this :
Give a name to your user control for exemle myUC
Add a property to your user control :
public List<Agent> AgentList { get; set; };
Fill your agentlist :
this.AgentList = //fill method
And bind your listbox like this :
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
Grid.Column="1"
ItemSource="{Binding Path=AgentList, ElementName=myUC"} />
may be this will give you an idea:
http://www.c-sharpcorner.com/forums/wpf-datacontext-binding-with-listbox
The fastest way to get what you want is :
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
DisplayMemberPath="Category"
Grid.Column="1"
ItemSource="{Binding Path=."} />
ItemsSource is binded directly to your Datacontext (which is your list) And then you tell to your ListBox to display the property Category.
But the proper way would have been :
1 - Create a DataContext
public class AgentsDC
{
public List<Agent> Agents { get; set; }
}
2 - Give this class as DataContext
this.DataContext = new AgentsDC();
3 - Bind all these things
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
DisplayMemberPath="Category"
Grid.Column="1"
ItemSource="{Binding Path=Agents"} />
I also would suggest you to use MVVM. But if you do not want to then try this.
XAML:
<ListBox Name="AgentCategoryListBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Category}" d:DataContext="{d:DesignData}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
CS:
public MainWindow()
{
InitializeComponent();
List<Agent> agents = new List<Agent>
{
new Agent
{
Category = "Category"
}
};
DataContext = agents;
}
public class Agent
{
public string Category
{
get;
set;
}
}

WPF XAML Binding List and Combobox

I am teaching myself how to bind classes to XAML objects. I can't find anything on data within lists. Either that or I don't know the terminology very well. I want to make a combobox that is tied to the list, displaying the name of each Item in the Items list. How would I bind this to the combobox?
class Section
{
List<Item> Items = new List<Item>();
}
class Item
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
Try This,
<ComboBox ItemsSource="{Binding Items}" DisplayMemberPath="Name" />
Make your Items collection as a property.
public List<Item> Items { get; set;}
Section Class should be public and make it as your DataContext
Assuming Section is the current DataContext :
<ComboBox ItemsSource="{Binding Items}"
DisplayMemberPath="Name" />

Having trouble binding ViewModel to ComboBox

I have a viewmodel setup as the following
public class cDriveListVM
{
public string Drive { get; set; }
public cDriveListVM(string name)
{
Drive = name;
}
}
I declare the observablecollection in the window and set its datacontext to this observable collection.
public ObservableCollection<cDriveListVM> DriveList { get; set; }
private void dl()
{
DriveList = new ObservableCollection<cDriveListVM>();
DriveList.Add(new cDriveListVM("drive 1"));
DriveList.Add(new cDriveListVM("drive 2"));
this.DataContext = DriveList;
}
Xml for combobox:
<ComboBox x:Name="Drive_ComboBox" ItemsSource="{Binding Path=Drive}" HorizontalAlignment="Center" IsReadOnly="True" Grid.Column="0" Grid.Row="0" Width="300" Margin="10" SelectionChanged="Drive_Changed" Height="22" VerticalAlignment="Top"/>
I am just learning how to use Viewmodel so I am unsure what I am doing wrong, any help would be appreciated. I updated the xml file it results in the following combbox.
There are a few problems with this code.
One, the binding is set up wrong. Since the property with the viewmodel collection is DriveList, the binding should be ItemsSource="{Binding Path=DriveList}".
Two, you are attempting to display a field from your viewmodel, which is not doable. WPF's binding engine only works with properties, so the viewmodel should have a property:
public string Drive { get; set; }
And finally, the DisplayMemberPath should match the property name from the viewmodel: DisplayMemberPath="Drive".
Update: I just noticed that the DataContext is the observable collection itself -- I probably missed it on the first read. In that case, you want to bind directly to the data context:
ItemsSource="{Binding}"
And set DisplayMemberPath to the property you want to display:
DisplayMemberPath="Drive"

Get text of RadAutoCompleteBox

How can I get the text of a RadAutoCompleteBox using RadControls Q1 2013 in C#?
autoCompleteBox.SelectedItem returns "ServerCrafterTelerikWPF.Command".
Edit 1:
Here's my XAML:
<telerik:RadAutoCompleteBox x:Name="txtboxCommand" ItemsSource="{Binding Commands, Source={StaticResource ViewModel}}"
DisplayMemberPath="ACommand" AutoCompleteMode="Append" HorizontalAlignment="Left"
telerik:StyleManager.Theme="Modern" Margin="280,405,0,0"
VerticalAlignment="Top" Width="330" Height="30" KeyDown="txtboxCommand_KeyDown"/>
And I don't have any C# code. I just want, when a button is pressed, to get the text that is in the RadAutoCompleteBox.
Edit 2:
And here's my collection:
public class Command
{
public string ACommand { get; set; }
}
/// <summary>
/// A view model for MainWindow.xaml
/// </summary>
public class ViewModel
{
public ObservableCollection<Command> Commands { get; set; }
public ViewModel()
{
Commands = new ObservableCollection<Command>()
{
new Command() {ACommand = "stop "},
// Other commands...
// ...
// ...
};
}
}
You should take it from the SelectedItem property. Cast it to your class and then get it from MyClass.ACommand
And I suggest binding SelectedItem with Mode=TwoWay in your ViewModel can help a lot.
Just add a Member to ViewModel which is implementing Command like:
private Command _SelectedItem;
public Command SelectedItem
{
//get set with INotifyPropertyChanged
}
Then from the xaml: Bind RadAutoCompleteBox's SelectedItem Property like:
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
I have reproduced the problem.
Yes. I had the same problem. And I found the problem and the answer too.
I got the problem because of using of type string for the selected item in my view model.
private string selectedCommand;
public string SelectedCommand
{
get
{
return selectedCommand;
}
set
{
selectedCommand = value;
NotifyPropertyChanged("SelectedCommand");
}
}
Use the type as Command class and your problem will be solved.
private Command selectedCommand;
public Command SelectedCommand
{
get
{
return selectedCommand;
}
set
{
selectedCommand = value;
NotifyPropertyChanged("SelectedCommand");
}
}
Bind the SelectedItem property of the RadAutoCompleteBox in the XAML
<telerik:RadAutoCompleteBox
x:Name="txtboxCommand"
ItemsSource="{Binding Commands, Source={StaticResource ViewModel}}"
DisplayMemberPath="ACommand"
AutoCompleteMode="Append"
HorizontalAlignment="Left"
telerik:StyleManager.Theme="Modern"
Margin="280,405,0,0"
VerticalAlignment="Top"
Width="330"
Height="30"
KeyDown="txtboxCommand_KeyDown"
SelectedItem="{Binding SelectedCommand, Mode=TwoWay}"/>
If you wanna get the selected item by the code-behind, convert the selected item to the Command class type.
var selectedItem = autoCompleteBox.SelectedItem as Command;
And actually there can be multiple selected items. In that case you have to define a collection of Command objects.
private ObservableCollection<Command> selectedCommands;
public ObservableCollection<Command> SelectedCommands
{
get
{
return selectedCommands;
}
set
{
selectedCommands = value;
NotifyPropertyChanged("SelectedCommands");
}
}
And bind it to the SelectedItems property (plural of SelectedItem) of the RadAutoCompleteBox control.
SelectedItems="{Binding SelectedCommands, Mode=TwoWay}"
And make sure you have initiated the SelectedItems.
this.SelectedCommands = new ObservableCollection<Command>();
The SearchText property of the RadAutoCompleteBox should provide you the value.
According to the documentation it gets or sets the string that is into the TextBox part of the RadAutoCompleteBox. The SearchText value is used to filter the RadAutoCompleteBox' ItemsSource.
If you want to get the "Text" of the selected item of the AutocompleteBox, then you need to cast it to the specified type. In your case it is of type ServerCrafterTelerikWPF.Command.
var selectedItem = autoCompleteBox.SelectedItem;
if (selectedItem is ServerCrafterTelerikWPF.Command) {
var selectedCommand = selectedItem as ServerCrafterTelerikWPF.Command;
string textOfAutoCompleteBox = selectedCommand.ACommand;
}

Categories