How to add Item to ComboBox from UI? - c#

Ok maybe i'm a little bit stupid but i can't find a way to Add an Item to my Combobox and get it as SelectedItem. So what do i miss?
Current Code
LoginV.XAML
<ComboBox Height="23" Margin="102,2,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="155"
IsEditable="True"
DisplayMemberPath="Loginname"
ItemsSource ="{Binding alleBenutzer}"
SelectedItem="{Binding selectedBenutzer}"/>
LoginVM.CS
public List<User> alleBenutzer{ get; set; }
public User selectedBenutzer
{
get { return _selectedBenutzer; }
set
{
_selectedBenutzer = value;
if (selectedBenutzer != null)
{
//do stuff
}
RaisePropertyChanged(() => Reg(() => benutzerEinrichtungen));
}
}
User.cs
public class User
{
public int Id { get; set; }
public string Loginname { get; set; }
}
Summary
How can i provide following behavior?
User runes the App added the Word "Admin" in the Combobox Control which will result in an SelectedItem != null so that i can do if(selectedBenutzer.Loginname =="Admin") DoStuff;

Use ObservableCollection instead of List for alleBenutzer:
private ObservableCollection<string> _alleBenutzer;
public ObservableCollection<string> alleBenutzer
{
get
{
return _alleBenutzer;
}
set
{
_alleBenutzer= value;
RaisePropertyChanged("alleBenutzer");
}
}
Add a button Add user.
Add AddUser() method to your ViewModel:
public void AddUser()
{
alleBenutzer.Add(new User {...});
}
Assign a RelayCommand to Click event of the button.
Assign the same RelayCommand to AddUser() method of your ViewModel

ok after some further research it turns out that i need to bind to the Text Property which contains the Value i was looking for
here an simple example
XAML
<ComboBox Height="23" HorizontalAlignment="Left" Margin="89,23,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120"
IsEditable="True"
ItemsSource="{Binding mySimpleItems}"
SelectedItem="{Binding mySimpleItem}"
Text="{Binding myNewSimpleItem}"/>
Code
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new SimpleVM();
}
}
public class SimpleVM
{
private string _mySimpleItem;
private string _myNewSimpleItem;
private bool isNew = true;
#region properties
public ObservableCollection<string> mySimpleItems { get; set; }
public string mySimpleItem
{
get { return _mySimpleItem; }
set
{
_mySimpleItem = value;
if (_mySimpleItem != null)
{
isNew = false;
MessageBox.Show(_mySimpleItem);
}
else
isNew = true;
}
}
public string myNewSimpleItem
{
get { return _myNewSimpleItem; }
set
{
_myNewSimpleItem = value;
//if SelectedItem == null
if (isNew)
if (_myNewSimpleItem == "Super")
{
mySimpleItem = _myNewSimpleItem;
mySimpleItems.Add(_myNewSimpleItem);
}
}
}
#endregion
#region cTor
public SimpleVM()
{
var ObCol = new ObservableCollection<string>();
ObCol.Add("Max");
ObCol.Add("Dennis");
ObCol.Add("Lucas");
mySimpleItems = ObCol;
}
#endregion
}

Related

Populating a WPF ListBox based on a ComboBox Selection

I am trying to populate a WPF ListBox with data from a SQL Stored Procedure based on a ComboBox Selection. I've gotten the ComboBox to work like its supposed to, but I can't get the ListBox to display any data. My naming might be a little weird, but think of it as: the ComboBox gets all Recipes from SQL and the ListBox needs to display a list of Ingredients and their Amounts based on the users selection from that ComboBox. The API and Stored Procedures(...GetAll() for the ComboBox and GetByRationId() for the ListBox...) work, as I can retrieve the correct data using Swagger in the API and I can Populate the ComboBox and the RationId TextBlock in the UI, but I can't get the ListBox to show any data. I am still new to programming and I'm following tutorials etc. and I can't seem to find anything that speaks to my case specifically. I'm guessing I'm missing something. I've added the aforementioned TextBlock just to display the RationId, which is what needs to be used to get the correct data from SQL, as a test, just to make sure that the Id was getting through...and it is.
Here's the Xaml...
<StackPanel Grid.Column="1" Margin="50" Orientation="Vertical">
<ComboBox x:Name="FeedGroup" MinWidth="300" MinHeight="50"
SelectedItem="{Binding SelectedFeedGroup}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FeedGroupName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock x:Name="SelectedFeedGroup_RationId" Height="81"/>
<ListBox x:Name="FeedGroupRation" MinHeight="200" Padding="20" ItemsSource="{Binding SelectedFeedGroupRation}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10" HorizontalAlignment="Center">
<TextBlock Text="{Binding CommodityName}" FontSize="20" FontWeight="Bold"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding CommodityPercentage}" FontSize="16" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
Here is the ViewModel Class...
public class FeedGroupPageViewModel : Screen
{
IFeedGroupEndPoint _feedGroupEndPoint;
IFeedGroupRationEndPoint _feedGroupRationEndPoint;
IMapper _mapper;
private readonly StatusInfoViewModel _status;
private readonly IWindowManager _window;
public FeedGroupPageViewModel(IFeedGroupEndPoint feedGroupEndPoint,
IFeedGroupRationEndPoint feedGroupRationEndpoint,
IConfigHelper configHelper,
IMapper mapper,
StatusInfoViewModel status,
IWindowManager window)
{
_feedGroupEndPoint = feedGroupEndPoint;
_feedGroupRationEndPoint = feedGroupRationEndpoint;
_configHelper = configHelper;
_mapper = mapper;
_status = status;
_window = window;
}
protected override async void OnViewLoaded(object view)
{
base.OnViewLoaded(view);
try
{
await LoadFeedGroup();
}
catch (Exception ex)
{
}
}
private async Task LoadFeedGroup()
{
var FeedGroupList = await _feedGroupEndPoint.GetAll();
var feedGroup = _mapper.Map<List<FeedGroupDisplayModel>>(FeedGroupList);
FeedGroup = new BindableCollection<FeedGroupDisplayModel>(feedGroup);
}
private BindableCollection<FeedGroupDisplayModel> _feedGroup;
public BindableCollection<FeedGroupDisplayModel> FeedGroup
{
get { return _feedGroup; }
set
{
_feedGroup = value;
NotifyOfPropertyChange(() => FeedGroup);
}
}
private FeedGroupDisplayModel _selectedFeedGroup;
public FeedGroupDisplayModel SelectedFeedGroup
{
get { return _selectedFeedGroup; }
set
{
_selectedFeedGroup = value;
NotifyOfPropertyChange(() => SelectedFeedGroup);
}
}
private BindableCollection<FeedGroupRationModel> _feedGroupRation;
public BindableCollection<FeedGroupRationModel> FeedGroupRation
{
get { return _feedGroupRation; }
set
{
_feedGroupRation = value;
NotifyOfPropertyChange(() => FeedGroupRation);
}
}
private BindableCollection<FeedGroupRationModel> _selectedFeedGroupRation;
public BindableCollection<FeedGroupRationModel> SelectedFeedGroupRation
{
get { return _selectedFeedGroupRation; }
set
{
_selectedFeedGroupRation = value;
NotifyOfPropertyChange(() => SelectedFeedGroupRation);
}
}
}
And here are the Model Classes
public class FeedGroupDisplayModel : INotifyPropertyChanged
{
public int Id { get; set; }
public string UserId { get; set; }
public string FeedGroupName { get; set; }
public DateTime CreateDate { get; set; }
public DateTime LastModified { get; set; }
public int RationId { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void CallPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class FeedGroupRationModel : INotifyPropertyChanged
{
public int Id { get; set; }
public string UserId { get; set; }
public int RationId { get; set; }
public string RationName { get; set; }
public int CommodityId { get; set; }
public string CommodityName { get; set; }
public int CommodityPercentage { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void CallPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
And Here are My Endpoint Classes
public class FeedGroupEndPoint : IFeedGroupEndPoint
{
private IAPIHelper _apiHelper;
public FeedGroupEndPoint(IAPIHelper apiHelper)
{
_apiHelper = apiHelper;
}
public async Task<List<FeedGroupModel>> GetAll()
{
using (HttpResponseMessage response = await _apiHelper.ApiClient.GetAsync("/api/FeedGroup"))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<List<FeedGroupModel>>();
return result;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
}
and
public class FeedGroupRationEndPoint : IFeedGroupRationEndPoint
{
private IAPIHelper _apiHelper;
public FeedGroupRationEndPoint(IAPIHelper apiHelper)
{
_apiHelper = apiHelper;
}
public async Task<List<FeedGroupRationModel>> GetRationById()
{
using (HttpResponseMessage response = await _apiHelper.ApiClient.GetAsync("/api/FeedGroup"))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<List<FeedGroupRationModel>>();
return result;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
}
I can add more info if needed. I've been working on this for quite awhile now and I'm just out of ideas. Any help would be greatly appreciated!
Thanks in advance!!
You don't seem to set the FeedGroupRation that the ListBox binds to somewhere.
I guess you want to fetch the items and set the property when the SelectedFeedGroup property is set. You could then hook up an event handler to the PropertyChanged event or override the NotifyOfPropertyChange method. Something like this:
public override async void NotifyOfPropertyChange([CallerMemberName] string propertyName = null)
{
base.NotifyOfPropertyChange(propertyName);
if (propertyName == nameof(FeedGroup))
{
//get the items...
var results = await ...;
//set the source property
FeedGroupRation = results;
}
}
As #Michal Davis comment stated I was missing a method for loading the ration, so I added LoadFeedGroupRation()...
private async Task LoadFeedGroupRation()
{
var _feedGroupRation = await _feedGroupRationEndPoint.GetRation();
var feedGroupRation = _mapper.Map<List<FeedGroupRationDisplayModel>>
(_feedGroupPenList);
FeedGroupRationList = new BindableCollection<FeedGroupRationDisplayModel>
(feedGroupRation);
}
Also based on #EldHasp's comment I updated the SelectedFeedGroup setter...
public FeedGroupDisplayModel SelectedFeedGroup
{
get { return _selectedFeedGroup; }
set
{
_selectedFeedGroup = value;
var FeedGroupRation = LoadFeedGroup
NotifyOfPropertyChange(() => SelectedFeedGroup);
}
}
I Don't know if this was the best way but I worked for my case.

c# UWP binding ComboBox SelectedItem

Hello I can't seem to figure out why my combox stays empty :/
On page load the first combox gets populated with countries (from JSON), the second combobox should populate when a country is selected in the first combobox. I'm trying to fetch the SelectedItem (country) as string in a property ... SelectedItem is of type ComboBoxItem ? I think that is where it goes wrong.
The (view)model where the sorting bindable properties are:
public class LocalityModel : NotifyProp
{
#region properties
private static List<LocalityJSON> dataList;
public List<LocalityJSON> DataList
{
get
{
return dataList;
}
set {
dataList = value;
RaisePropertyChanged("Landen");
RaisePropertyChanged("Gewesten");
}
}
public List<string> Landen
{
get { if (DataList == null) return null; return (from s in DataList orderby s.Land select s.Land).Distinct().ToList<string>(); }
}
public string SelectedLand { get; set; }
public List<string> Gewesten {
get { if (DataList == null) return null; return (from s in DataList where s.Land.Equals(SelectedLand) select s.Gewest).Distinct().ToList<string>(); }
}
#endregion
#region ctor
public LocalityModel()
{
FillDataList();
}
#endregion
#region methodes
public async void FillDataList()
{
if (DataList == null)
{
DataList = await EVNT.Entries();
}
}
#endregion
}
MainPage XAML (the bindings):
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" DataContext="{Binding Source={StaticResource LocalityModel}}">
...
<TextBlock x:Name="txbCountry" Style="{StaticResource InfoLabelCountry}" />
<ComboBox x:Name="cboCountry" Style="{StaticResource CountryBox}" ItemsSource="{Binding Landen}" SelectedItem="{Binding SelectedLand, Mode=TwoWay}" />
<TextBlock x:Name="txbGewest" Style="{StaticResource InfoLabelGewest}" />
<ComboBox x:Name="cboGewest" Style="{StaticResource GewestBox}" ItemsSource="{Binding Gewesten}" />
INotifyPropertyChanged:
public class NotifyProp : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The model for the JSON:
public class LocalityJSON
{
public string FB_ID { get; set; }
public string Land { get; set; }
public string Gewest { get; set; }
public string City { get; set; }
}
The JSON deserialisation (less important for the question):
public class EVNT
{
public async static Task<List<LocalityJSON>> Entries()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(#"http://e-vnt.com/admin/core/api/");
HttpResponseMessage response = await client.GetAsync("localityApi");
if (response.IsSuccessStatusCode)
{
String s = await response.Content.ReadAsStringAsync();
List<LocalityJSON> entries = JsonConvert.DeserializeObject<List<LocalityJSON>>(s);
return entries;
}
else
return null;
}
}
}
In your SelectedLand Property setter you need to fire PropertyChanged event the for both SelectedLand and for Gewesten.
It would probably look something like this
private string _SelectedLand;
public string SelectedLand
{
get
{
return _SelectedLand;
}
set
{
_SelectedLand = value;
RaisePropertyChanged("SelectedLand");
RaisePropertyChanged("Gewesten");
}
}
if you don't fire PropertyChanged event for Gewesten then that combobox will not know to reload is values.

ObservableCollection not binding to combo box

Just wondering as to why my ObservableCollection is not binding to my Combo Box
I don't get any errors it just doesn't populate it.
public class TableList : ObservableCollection<TableName>
{
public TableList() : base()
{
Add(new TableName(1, "Notes"));
Add(new TableName(2, "TemplateNotes"));
}
}
public class TableName
{
private int noteID;
private string noteName;
public TableName(int ID, string name)
{
this.noteID = ID;
this.noteName = name;
}
public int NoteID
{
get { return noteID; }
set { noteID = value; }
}
public string NoteName
{
get { return noteName; }
set { noteName = value; }
}
}
This is my XAML
<ComboBox
x:Name="noteSaveToSelection"
HorizontalAlignment="Left"
Height="35"
Margin="155,932,0,0"
VerticalAlignment="Top"
Width="180"
ItemsSource="{Binding TableList}"
DisplayMemberPath="NoteName"
SelectedValuePath="NoteID"/>
I am new to this so i apologise if i have missed something small.
Apparently you never create an instance of your TableList class that you can actually bind to.
Create a view model class with a TableList property, e.g. like
public class ViewModel
{
public TableList TableList { get; } = new TableList();
}
Then set the DataContext property of your MainWindow to an instance of the view model class:
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}

IDataErrorInfo Issue - Initial property values

i have a ViewModel that implements the IDataErrorInfo interface as usual.
Model
public class Computer : Model
{
public Computer(string name, string ip, string mac, string broadcastIp)
{
Name = name;
Ip = ip;
Mac = mac;
BroadcastIp = broadcastIp;
}
public Computer()
{
Name = "neuer Computer";
Mac = string.Empty;
Ip = string.Empty;
BroadcastIp = string.Empty;
}
[NotMapped]
public ComputerState ComputerState { get; set; }
public string Name { get; set; }
public string Ip { get; set; }
public string Mac { get; set; }
public string BroadcastIp { get; set; }
public virtual Room Room { get; set; }
}
ViewModel
public class ComputerViewModel : ViewModel<Computer>, IListItem
{
private bool _IsSelected;
private ComputerOperationMessage _OperationMessage = ComputerOperationMessage.NO_MESSAGE;
public ComputerViewModel(Computer computer) : base(computer)
{
}
public string Name
{
get { return Model.Name; }
set
{
Model.Name = value;
RaisePropertyChanged(nameof(Name));
}
}
public RoomViewModel Room
{
get { return App.EntityManager.Get<RoomViewModel>().FirstOrDefault(r => r.Model.Equals(Model.Room)); }
set
{
Model.Room = value.Model;
RaisePropertyChanged(nameof(Room));
}
}
public ComputerState State
{
get { return Model.ComputerState; }
set
{
if (value.Equals(Model.ComputerState))
return;
Model.ComputerState = value;
RaisePropertyChanged(nameof(State));
}
}
public string Ip
{
get { return Model.Ip; }
set
{
Model.Ip = value;
RaisePropertyChanged(nameof(Ip));
}
}
public string Mac
{
get { return Model.Mac; }
set
{
Model.Mac = value;
RaisePropertyChanged(nameof(Mac));
}
}
public string BroadcastIp
{
get { return Model.BroadcastIp; }
set
{
Model.BroadcastIp = value;
RaisePropertyChanged(nameof(BroadcastIp));
}
}
/// <summary>
/// UI indicator when a operation like shutdown, reboot, ping etc. is running
/// </summary>
public ComputerOperationMessage OperationMessage
{
get { return _OperationMessage; }
set
{
if (value.Equals(_OperationMessage))
return;
_OperationMessage = value;
RaisePropertyChanged(nameof(OperationMessage));
}
}
public bool IsSelected
{
get { return _IsSelected; }
set
{
_IsSelected = value;
RaisePropertyChanged(nameof(IsSelected));
}
}
public override string ToString()
{
return Name;
}
protected override string ValidateProperty(string property)
{
var computers = App.EntityManager.Get<ComputerViewModel>().ToList();
switch (property)
{
case nameof(Name):
if (string.IsNullOrEmpty(Name))
{
return "Bezeichnung erwartet";
}
if (computers.Any(c => c.Name == Name))
{
return "Bezeichnung bereits vergeben";
}
break;
case nameof(Ip):
if (string.IsNullOrEmpty(Ip))
{
return "Ip erwartet";
}
if (!NetworkCommand.ValidateIp(Ip))
{
return "Ip ungültig";
}
if (computers.Any(c => c.Ip == Ip))
{
return "Ip bereits vergeben";
}
break;
case nameof(Mac):
if (string.IsNullOrEmpty(Mac))
{
return "Mac erwartet";
}
if (!NetworkCommand.ValidateMac(Mac))
{
return "Mac ungültig";
}
if (computers.Any(c => c.Mac == Mac))
{
return "Mac bereits vergeben";
}
break;
case nameof(BroadcastIp):
if (string.IsNullOrEmpty(BroadcastIp))
{
return "Broadcast Ip erwartet";
}
if (!NetworkCommand.ValidateIp(Ip))
{
return "Broadcast Ip ungültig";
}
break;
case nameof(Room):
if (Room == null)
return "Raum wählen";
break;
}
return string.Empty;
}
public abstract class ViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private string _ErrorMessage;
private bool _HasErrors;
public ViewModel()
{
SaveCommand = new RelayCommand(SaveAction);
}
public bool HasErrors
{
get { return _HasErrors; }
set
{
_HasErrors = value;
RaisePropertyChanged(nameof(HasErrors));
}
}
public ICommand SaveCommand { get; }
public Model Model { get; protected set; }
public string this[string property]
{
get
{
_ErrorMessage = ValidateProperty(property);
RaisePropertyChanged(nameof(Error));
HasErrors = !string.IsNullOrEmpty(Error);
return Error;
}
}
public string Error
{
get { return _ErrorMessage; }
}
public event PropertyChangedEventHandler PropertyChanged;
private void SaveAction(object obj)
{
if (Model != null && Model.Id == 0)
{
App.EntityManager.Add(Model);
}
App.EntityManager.Save();
}
protected virtual string ValidateProperty(string property)
{
return string.Empty;
}
protected void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
public abstract class ViewModel<T> : ViewModel where T : Model
{
protected ViewModel(T model)
{
Model = model;
base.Model = model;
}
public new T Model { get; }
public long Id => Model.Id;
}
XAML:
<Label Content="{StaticResource NameString}" />
<TextBox Text="{Binding Path=Name, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
<Label Content="{StaticResource IpString}" />
<TextBox Text="{Binding Path=Ip,ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
<Label Content="{StaticResource MacString}" />
<TextBox Text="{Binding Path=Mac, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
<Label Content="{StaticResource BroadcastIpString}" />
<TextBox Text="{Binding Path=BroadcastIp, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
<Label Content="{StaticResource RoomString}" />
<ComboBox ItemsSource="{Binding Path=Rooms}" SelectedItem="{Binding Path=Room, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
<GridSplitter Height="25" />
<Button x:Name="SaveButton"
HorizontalAlignment="Right"
Command="{Binding Path=SaveCommand}"
Content="{StaticResource SaveIcon}"
IsEnabled="{Binding Path=CanSave,
Converter={StaticResource TrueToFalseConverter},
UpdateSourceTrigger=PropertyChanged}" />
Calling code in class that implements ICommand interface:
var viewModel = parameter as ComputerViewModel;
_Editor = new ComputerEditor();
_Editor.CloseButtonCommand = new RelayCommand(CloseCommand);
_Editor.SaveButton.Click += (s, e) =>
{
App.EntityManager.Add(_Editor.ComputerEditViewModel.Model);
App.EntityManager.Save();
_Editor.IsOpen = false;
(Application.Current.MainWindow.Content as Grid).Effect = null;
};
if (viewModel == null)
{
_Editor.DataContext = new ComputerEditViewModel(new Computer());
_Editor.Title = Application.Current.FindResource("ComputerAddString").ToString();
}
else
{
_Editor.DataContext = new ComputerEditViewModel(viewModel.Model);
_Editor.Title = Application.Current.FindResource("ComputerEditString").ToString();
}
OpenChildWindow(_Editor);
My problem:
When i create a new entity without any initial values the IDataErrorInfo is executed all the time but the error (red border and label) is only shown when the new entity properties has valid initial values.
Control images
The (1) is the initial controlstate. The first textbox ('Name') has a default value that comes from the entity contructor. All other values (Textboxes) are just empty.
At this point my validation is working in my viewmodel for all textboxes/properties but only the first textbox get the red border and label when the validation fails, cause of the valid start value!
For the other properties i have to set a valid (initial) value before the red border and label is shown (when validation fails, cause of property change) although i check if the textbox/property is empty.
As i said, the validation is working in the viewmodel all the time but the view only shows the red border and label when the initial value is valid against my implementation.
Hoping this question is not to weird.
Feel free to ask anything if something is just unclear
Best regards
Dustin

MVVM populating a combobox (WinRT and C#)

I have a ComboBox in my XAML. It is populated with the following code:
PopulateColors.cs
public class PopulateColors
{
public ObservableCollection<ItemsColors> itemsColors { get; set; }
public PopulateColors()
{
this.itemsColors = new ObservableCollection<ItemsColors>();
this.itemsColors.Add(new ItemsColors{ ItemColumn = "Blue", IdItemColumn = 0 });
this.itemsColors.Add(new ItemsColors{ ItemColumn = "Red", IdItemColumn = 1 });
this.itemsColors.Add(new ItemsColors{ ItemColumn = "Pink", IdItemColumn = 2 });
}
}
public class ItemsColors
{
public string ItemColumn { get; set; }
public int IdItemColumn { get; set; }
}
pagedemo.xaml.cs:
ClothingViewModel ClothVM = null;
public pagedemo()
{
this.comboColors.DataContext = new PopulateColors();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
ClothVM = new ClothingViewModel();
ClothVM = ClothVM.GetData(1);
this.DataContext = ClothVM ;
navigationHelper.OnNavigatedTo(e);
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
string result = ClothVM .Save( ClothVM );
if (result.Contains("OK"))
{
//to do
}
}
pagedemo.xaml (XAML design)
<TextBox x:Name="txtJersey"
Text="{Binding Jersey, Mode=TwoWay}"/>
<ComboBox Name="comboColors"
ItemsSource="{Binding itemsColors}"
DisplayMemberPath="ItemColumn"
SelectedValuePath="ItemColumn"/>
Ok. items are display fine in ComboBox.
QUESTION:
I need to save the selected color in a table of the database, using MVVM pattern. But how? I have this code. But I do not know how to link it with the ComboBox:
Model: Clothing.cs
Public class Clothing
{
public string Color { get; set; }
public string Jersey { get; set; }
}
ViewModel: ClothingViewModel.cs
public class ClothingViewModel : ViewModelBase
{
public string Save (ClothingViewModel cloth)
{
string result = string.Empty;
using (var db = new SQLite.SQLiteConnection(App.DBPath))
{
string change = string.Empty;
try
{
var existing = (db.Table<Clothing>().Where(
c => c.id == 1)).SingleOrDefault();
if (existing!= null)
{
existing.Color = cloth.Color;
existing.Jersey = cloth.Jersey;
int success = db.Update(existing);
}
}
catch
{ }
}
}
private int id = 1;
public int ID
{
get
{ return id; }
set
{
if (id == value)
{ return; }
id= value;
RaisePropertyChanged("ID");
}
}
private string color = string.Empty;
public string Color
{
get
{ return color; }
set
{
if (color == value)
{ return; }
color = value;
isDirty = true;
RaisePropertyChanged("Color");
}
}
private string jersey = string.Empty;
public string Jersey
{
get
{ return jersey; }
set
{
if (jersey == value)
{ return; }
jersey = value;
isDirty = true;
RaisePropertyChanged("Jersey");
}
}
}
Actually, there are plenty of options. Let's demonstrate just a few of them.
1. Use Binding with RelativeSource to find Ancestor with appropriate DataContext
XAML-code:
<!-- Please use Page instead of Window. -->
<Window>
<StackPanel>
<TextBox x:Name="txtJersey"
Text="{Binding Jersey, Mode=TwoWay}"/>
<!-- Use {x:Type Page} instead of {x:Type Window}. -->
<ComboBox Name="comboColors" ItemsSource="{Binding itemsColors}"
DisplayMemberPath="ItemColumn"
SelectedValue="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},
Path=DataContext.Color}"
SelectedValuePath="ItemColumn" />
</StackPanel>
</Window>
2. Use Binding with ElementName to the UI-element with appropriate DataContext
XAML-code:
<StackPanel>
<TextBox x:Name="txtJersey"
Text="{Binding Jersey, Mode=TwoWay}"/>
<ComboBox Name="comboColors" ItemsSource="{Binding itemsColors}"
DisplayMemberPath="ItemColumn"
SelectedValue="{Binding
ElementName=txtJersey,
Path=DataContext.Color}"
SelectedValuePath="ItemColumn" />
</StackPanel>
3. Use "one" ViewModel that contains another ViewModel
public class ClothingViewModel : ViewModelBase
{
private readonly PopulateColors colors = new PopulateColors();
public PopulateColors Colors
{
get { return this.colors; }
}
...
}
Page:
// This is a Page (Window in case of using WPF).
public class ClothingWindow
{
public ClothingWindow()
{
InitializeComponent();
// Note: no need to set the DataContext for the ComboBox.
DataContext = new ClothingViewModel();
}
}
XAML-code:
<StackPanel>
<TextBox Text="{Binding Jersey, Mode=TwoWay}"/>
<ComboBox ItemsSource="{Binding Colors.itemsColors}"
DisplayMemberPath="ItemColumn"
SelectedValue="{Binding Color}"
SelectedValuePath="ItemColumn" />
</StackPanel>
References
Data Binding (WPF), MSDN.
Data Binding in WPF, John Papa, MSDN Magazine.

Categories

Resources