Populate RadComboBox from enum list in WPF MVVM - c#

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}" />

Related

WPF MVVM - Get access to DependencyProperty of DataGrid in View from ViewModel

In my View I have a DataGrid which stores objects of 2 descending types. Every row has a Button with a Command connected to the ViewModel. In the ViewModel I need to find out which type of object has been chosen.
The question is what is the best and simple way of accessing SelectedItem property of the DataGrid from the Execute command method in a ViewModel?
So far I did it like this:
var window = Application.Current.Windows.OfType<Window>()
.SingleOrDefault(x => x.IsActive);
var dataGrid = (DataGrid) window.FindName("MyGridName");
...
UPDATE - Xaml:
<DataGrid Name="MyGridName" ItemsSource="{Binding Elements}"
AutoGenerateColumns="False" CanUserAddRows="False"
CanUserDeleteRows="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTemplateColumn Width="auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="OptionsBtn" Margin="5" Width="auto"
Height="30" Content="Options"
Command="{Binding ElementName=ElementsViewWindow,
Path=DataContext.ShowOptionsMenuCommand}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
If you take the right MVVM approach this is very easy to do. All you need is to define the item collection of you entities which will be bound to ItemsSource of your DataGrid and a property which will be bound to SelectedItem of your DataGrid. Then in your command you simply reference your selected item property of your model to access the selected item in your DataGrid.
Here is an example implementation with MVVM Light. First you define an observable collection of your entities:
public const string ItemsCollectionPropertyName = "ItemsCollection";
private ObservableCollection<DataItem> _itemsCollection = null;
public ObservableCollection<DataItem> ItemsCollection
{
get
{
return _itemsCollection;
}
set
{
if (_itemsCollection == value)
{
return;
}
_itemsCollection = value;
RaisePropertyChanged(ItemsCollectionPropertyName);
}
}
Then you define a property to hold the selected item:
public const string SelectedItemPropertyName = "SelectedItem";
private DataItem _selectedItem = null;
public DataItem SelectedItem
{
get
{
return _selectedItem;
}
set
{
if (_selectedItem == value)
{
return;
}
_selectedItem = value;
RaisePropertyChanged(SelectedItemPropertyName);
}
}
After that you define a command to handle business logic:
private ICommand _doWhateverCommand;
public ICommand DoWhateverCommand
{
get
{
if (_doWhateverCommand == null)
{
_doWhateverCommand = new RelayCommand(
() => { /* do your stuff with SelectedItem here */ },
() => { return SelectedItem != null; }
);
}
return _doWhateverCommand;
}
}
Finally you create view elements and bind them to the ViewModel:
<DataGrid ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem}" AutoGenerateColumns="True" />
<Button Content="Do stuff" Command="{Binding DoWhateverCommand}" />
The question is what is the best and simple way of accessing SelectedItem property of DataGrid from Execute command function in a ViewModel?
Just add a property to the view model class where the ShowOptionsMenuCommand property is defined and bind the SelectedItem property of the DataGrid to this one:
<DataGrid Name="MyGridName" ItemsSource="{Binding Elements}" SelectedItem="{Binding SelectedElement}" ... >
Then you can access the source property (SelectedElement or whatever you choose to call it) directly from the Execute method.
The other option would be to pass the item as a CommandParameter to the command:
<Button Name="OptionsBtn" ... Content="Options"
Command="{Binding ElementName=ElementsViewWindow, Path=DataContext.ShowOptionsMenuCommand}"
CommandParameter="{Binding}" />

Getting SelectedItem of ComboBox (MVVM)

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}" />

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;
}

DataGrid Showing Blank Lines when bound to an ObservableCollection<Object>

I have a simple DataGrid which I am binding to a ObservableCollection and its producing black small lines in the Grid with no Data Visible. I am using ObservableCollection as I have the collection being built in RunTime using Reflection.
I am doing something like this
XAML
<DataGrid ItemsSource="{Binding Data}" />
C#
public ObservableCollection<object> Data
{
get { return _Data; }
set {
this._deals = value;
this.NotifyPropertyChanged("Deals");
}
}
public Run()
{
this.Data = CreateData(typeof(MyRecordClass)) //'MyRecordClass' needs to be passed at runtime
}
public ObservableCollection<Object> CreateData(Type RecordType)
{
ObservableCollection<Object> data = new ObservableCollection<object>();
var record = Activator.CreateInstance(RecordType);
// Logic to load the record with Data
data.Add(record);
return data;
}
Is there a way in which I can make the DataGrid read an ObservableCollection without specifying the ColumnNames or create a ObservableCollection object in the CreateData function ?
Your collection should have public properties, so datagrid could bind columns to it.
If you use collection type of Object than you have no properies for binding, so the empty rows will be displayed.
Here is example for you:
public partial class MainWindow : Window
{
public ObservableCollection dataSource;
public MainWindow()
{
InitializeComponent();
this.dataSource = new ObservableCollection<SomeDataSource>();
this.dataSource.Add(new SomeDataSource { Field = "123" });
this.dataSource.Add(new SomeDataSource { Field = "1234" });
this.dataSource.Add(new SomeDataSource { Field = "12345" });
this.dataGrid1.ItemsSource = this.dataSource;
}
}
public class SomeDataSource
{
public string Field {get;set;}
}
<DataGrid AutoGenerateColumns="False" Height="253" HorizontalAlignment="Left" Margin="27,24,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="448">
<DataGrid.Columns>
<DataGridTextColumn Header="First" Binding="{Binding Path=Field, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
</DataGrid>

WPF/C# - ´binding list<string> to combobox

I want my combobox item names and values to be taken from my List of course I don't want my view model to hold combobox items list.
I got a list a,b,c,d
public List<String> ComboList { get; set; }
...
ComboList = new List<String>();
ComboList.Add("A");
ComboList.Add("B");
ComboList.Add("C");
ComboList.Add("D");
and my ComboBox
<ComboBox Margin="29,40,0,526" Width="212" Height="35" Grid.Row="1" ItemsSource="{Binding Path=ComboList, Mode=OneTime}" SelectedValuePath="Key" DisplayMemberPath="Value"></ComboBox>
but it gives me a empty ComboBox ...
Remove the SelectedValuePath and DisplayMemberPath attributes. They are wrong.
You forget to do that just before the InitializeComponents into the code-behind :
public void MainWindow(){
this.Datacontext = this;
InitializeComponent()
}
Moreover you cannot bind the list directly, you better have to give an ObservableCollection.
This is an example :
public ObservableCollection<NetworkCard> NetworksCards { get { return m_aCards; } }
private ObservableCollection<NetworkCard> m_aCards = null;
m_aCards = new ObservableCollection<NetworkCard>(oHelper.ListNetworkCards());

Categories