Populating a WPF ListBox based on a ComboBox Selection - c#

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.

Related

MVVM WPF ViewModel DispatcherTimer not updating view?

I have a DispatcherTimer in my ViewModel that i can see firing every interval, but the view is not being updated?
the feed data comes from a xml url and i am trying to refresh the form every x seconds. Maybe more or less lables / differnt status
heres the code snippets:
ViewModel.cs
public class Nodes
{
public string name { get; set; }
public string id { get; set; }
public string status { get; set; }
public string last { get; set; }
public int level { get; set; }
public string parent { get; set; }
}
public ObservableCollection<CI> CIs
{
get;
set;
}
DispatcherTimer LogTimer;
public void LoadCIs()
{
ObservableCollection<CI> cis = new ObservableCollection<CI>();
LogTimer = new DispatcherTimer();
LogTimer.Interval = TimeSpan.FromMilliseconds(10000);
LogTimer.Tick += (s, e) =>
{
//pull node list
List<Nodes> SortedList = PopulateNodes();
foreach (Nodes Node in SortedList)
{
//create labels for all top level nodes
if (Node.level == 3)
{
cis.Add(new CI { NodeName = Node.name, NodeStatus = Node.status });
}
}
CIs = cis;
};
LogTimer.Start();
}
Model.cs
public class CI : INotifyPropertyChanged {
private string nodeName;
private string nodeStatus;
public string NodeName {
get {
return nodeName;
}
set {
if (nodeName != value) {
nodeName = value;
RaisePropertyChanged("NodeName");
}
}
}
public string NodeStatus
{
get
{
return nodeStatus;
}
set
{
if (nodeStatus != value)
{
nodeStatus = value;
RaisePropertyChanged("NodeStatus");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
view.xaml
<Grid>
<ItemsControl ItemsSource = "{Binding Path = CIs}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Label Content = "{Binding Path = NodeName, Mode = OneWay}"
Background = "{Binding Path = NodeStatus, Mode = OneWay}"
Foreground="White"
FontFamily="Arial Black"
HorizontalContentAlignment="Center"
BorderBrush="Black"
BorderThickness="1,1,1,1"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
how the form should look without timer enabled / commented out:
with the timer code enabled nothing is added to grid:
Thanks for looking
The problem:
You are changing the Collection CIs but do not notify it is changed. ObservableCollections report their changes but you're overwriting it, it will not report that.
Option 1:
Because you use an ObservableCollection you can add it to the bound collection directly and it will notify the UI automatically.
So instead of:
cis.Add(new CI { NodeName = Node.name, NodeStatus = Node.status });
Do this:
CIs.Add(new CI { NodeName = Node.name, NodeStatus = Node.status });
if you do this you have to initialize CIs first:
public ObservableCollection<CI> CIs
{
get;
set;
} = new ObservableCollection<CI>(); // < initialize it
Option 2:
Add the INotifyPropertyChanged interface to the Nodes class and notify like this:
this.PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( nameof( this.CIs ) ) );
in the setter of CIs

C# datagrid is not updating itemsource when get added

when typing in the textbox and click "Add Employee", i want it to update and display to the datagrid, i've implemented INotifyPropertyChanged and RelayCommand. what am i missing that's not populating the data. thanks in advance
here is my model
public class EmployeeModel
{
public string Name { get; set; }
public int Pedicure { get; set; }
public int Tip { get; set; }
public int Total { get; set; }
}
this is my ViewModel
List<EmployeeModel> employeeModel = new List<EmployeeModel>() { };
private ICommand _addEmployeeCommand;
public ICommand AddEmployeeCommand
{
get
{
return _addEmployeeCommand ?? (_addEmployeeCommand = new RelayCommand(x => { AddNewEmployee(); }));
}
}
public List<EmployeeModel> Employee
{
get { return employeeModel; }
set
{
if(value != employeeModel)
{
employeeModel = value;
OnPropertyChanged("Employee");
}
}
}
private string employeeName;
public string EmployeeName
{
get { return employeeName; }
set
{
if (value != employeeName)
{
employeeName = value;
OnPropertyChanged("EmployeeName");
}
}
}
public void AddNewEmployee()
{
Employee.Add(new EmployeeModel { Name = EmployeeName });
}
here is my View
<TabItem Header="Employee">
<StackPanel Orientation="Vertical">
<DataGrid ItemsSource="{Binding Employee}">
</DataGrid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name: "/>
<TextBox Text="{Binding EmployeeName}"
Width="40"
Height="15"
VerticalAlignment="Top"/>
<Button Content="Add"
Command="{Binding AddEmployeeCommand}"
Height="20"
VerticalAlignment="Top"/>
</StackPanel>
</StackPanel>
(I pluralized the name Employee to Employees in this answer for future readers)
The problem is with the Source of the DataGrid
Bear in mind that OnPropertyChanged("Employees") only notifies about the changes made to the Employees and is not responsible for any changes made within Employees.
To be clear, it only works when you do employeeModels = new List<EmployeeModel>()
And won't be called when Employees.Add(employee)
Hopefully WPF has its own ObservableCollection type that will take care of that:
private ObservableCollection<Employee> _employees = new ObservableCollection<Employee>;
public ObservableCollection<Employee> Employees { get { return _employees; } }

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.

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

How to add Item to ComboBox from UI?

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
}

Categories

Resources