In my Previous Question, I got a solution how to manually check the Validation Result https://stackoverflow.com/questions/39031783/screen-validation-with-data-annotations-on-button-click-in-using-inotifydataerro/39033124#39033124
I'm having a Model Person, it contains three properties FirstName (required), MiddleName (optional) and LastName (required).
Now I changed My Code slightly
public class PersonViewModel : BaseViewModel, INotifyDataErrorInfo {
private string _personObj = string.Empty;
public Person PersonObj
{
get { return _personObj; }
set { _personObj= value; OnPropertyChanged(); }
}
public bool IsValidObject
{
get
{
var context = new ValidationContext(EmpInfo, null, null);
bool flag = Validator.TryValidateObject(EmpInfo, context, null, true);
return flag;
}
}
public ICommand SaveDataCommand
{
get
{
return new DelegatingCommand(SaveData);
}
}
public void SaveData
{
// Validate Data;
}
}
The Model Class: Person
public class Person
{
[Required]
public string FirstName { get; set; }
public string MiddleName { get; set; }
[Required]
public string LastName { get; set; }
}
My XAML is
<TextBox Text="{Binding PersonObj.FirstName, UpdateSourceTrigger=PropertyChanged,
,ValidatesOnNotifyDataErrors=True}" />
<TextBox Text="{Binding PersonObj.MiddleName, UpdateSourceTrigger=PropertyChanged,
,ValidatesOnNotifyDataErrors=True}" />
<TextBox Text="{Binding PersonObj.LastName, UpdateSourceTrigger=PropertyChanged,
,ValidatesOnNotifyDataErrors=True}" />
<Button Content="Save" IsDefault="True" IsEnabled="{Binding IsValidObject}" Command="{Binding SaveDataCommand}" />
The Property IsValidObject Initially works fine. If I update the Value in FirstName and LastName, then the property IsValidObject is not updating the result in UI.
I used one more approach
public class PersonViewModel : BaseViewModel, INotifyDataErrorInfo {
private string _personObj = string.Empty;
public Person PersonObj
{
get { return _personObj; }
set { _personObj= value; OnPropertyChanged(); }
}
public bool IsValidObject
{
get
{
var context = new ValidationContext(EmpInfo, null, null);
bool flag = Validator.TryValidateObject(EmpInfo, context, null, true);
return flag;
}
}
public ICommand SaveDataCommand
{
get
{
return new DelegatingCommand(SaveData, ValidateEmployeeObject);
}
}
public bool ValidateEmployeeObject()
{
var context = new ValidationContext(EmpInfo, null, null);
bool flag = Validator.TryValidateObject(EmpInfo, context, ErrorResult, true);
return flag;
}
public void SaveData
{
// Validate Data;
}
}
Here I introduced a Method ValidateEmployeeObject(), it returns TRUE / FALSE as similar to the Property IsValidObject. I binded this Method in CanExecute Block of SaveDataCommand as proposed by #adminSoftDK in the comment part. This approach too fails...
How could I update the Save Button to make Enable based on the above validation.
If you try something like this
public PersonViewModel()
{
SaveDataCommand = new DelegatingCommand(SaveData, ()=> flag);
}
bool flag;
public bool IsValidObject
{
get
{
var context = new ValidationContext(EmpInfo, null, null);
flag = Validator.TryValidateObject(EmpInfo, context, null, true);
SaveDataCommand.RaiseCanExecute() // don't know what type of command you have but you should have a method which you can call something with Canexecute
return flag;
}
}
public bool ValidateEmployeeObject()
{
return IsValidObject;
}
public ICommand SaveDataCommand { get; }
I'm not very familiar with INotifyDataErrorInfo and I don't know at what point is your IsValidObject is called, but i think something like the above should work.
Related
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.
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
So I have a page that has a TabControl that uses multiple UserControls (each user control represents the contents of a TabItem).
I have a ComboBox in both user controls that share the same ItemsSource (OrganizationSource) and SelectedValue(OrganizationSelected) properties,
I however cannot seem to bind to ComboBox within the EventDetails UserControl, but it works flawlessly inside of the OrganizationDetails UserControl.
The OutreachMVVM is set to the DataContext for the parent page that the tabs reside in. I still have to set the datacontexts for the user controls themselves for it to work properly.
I just need to figure out how to set the binding for the ComboBox inside of the EventDetails. I saw something about dependency property but I do not understand it. I thought I would be able to set the binding for the ComboBox inside of EventDetails as the same for the ComboBox inside of OrganizationDetails, but that's not the case.
internal class OutreachMVVM : ViewModelBase
{
public OutreachMVVM()
{
EventDetails = new EventDetailsVMB();
OrganizationDetails = new OrganizationDetailsVMB();
}
public EventDetailsVMB EventDetails { get; set; }
public OrganizationDetailsVMB OrganizationDetails { get; set; }
}
EventDetailsVMB:
class EventDetailsVMB : ViewModelBase
{
private string _eventTypeSelected;
private string _zipSelected;
private readonly UserListTableAdapter _userListTableAdapter = new UserListTableAdapter();
private readonly EventTypeListTableAdapter _eventTypeListTableAdapter = new EventTypeListTableAdapter();
private readonly CityListTableAdapter _cityListTableAdapter = new CityListTableAdapter();
private readonly LocationInfoByZipTableAdapter _locationInfoByZipTableAdapter = new LocationInfoByZipTableAdapter();
public string User { get; set; }
public string EventName { get; set; }
public string Location { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string County { get; set; }
public string ServiceArea { get; set; }
//Set EventType CombBox
public ObservableCollection<string> EventTypeSource
{
get
{
var eventTypeList = _eventTypeListTableAdapter.GetEventTypeList();
var eventTypeSource = new ObservableCollection<string>();
eventTypeSource.AddRange(from DataRow row in eventTypeList.Rows select row.ItemArray[0].ToString());
return eventTypeSource;
}
}
//Set User ComboBox
public ObservableCollection<string> UserSource
{
get
{
var userList = _userListTableAdapter.GetUserList();
var userSource = new ObservableCollection<string>();
foreach (var username in Enumerable.Where(userList, username => username.Username == Environment.UserName))
{
User = username.FullName;
}
userSource.AddRange(from DataRow row in userList.Rows select row.ItemArray[0].ToString());
OnPropertyChanged("User");
return userSource;
}
}
//Set City RadAutoCompleteBox
public ObservableCollection<string> CitySource
{
get
{
var cityList = _cityListTableAdapter.GetCityList();
var citySource = new ObservableCollection<string>();
citySource.AddRange(from DataRow row in cityList.Rows select row.ItemArray[0].ToString());
return citySource;
}
}
public string EventTypeSelected
{
get { return _eventTypeSelected; }
set
{
_eventTypeSelected = value;
OnPropertyChanged("EventTypeSelected");
}
}
public string ZipSelected
{
get { return _zipSelected; }
set
{
_zipSelected = value;
var locationInfo = _locationInfoByZipTableAdapter.GetLocationInfoByZip(_zipSelected);
if (locationInfo.Rows.Count != 0)
{
City = locationInfo.Rows[0].ItemArray[0].ToString();
State = locationInfo.Rows[0].ItemArray[1].ToString();
County = locationInfo.Rows[0].ItemArray[2].ToString();
ServiceArea = locationInfo.Rows[0].ItemArray[3].ToString();
}
else if (ZipSelected.Length == 5) {}
else
{
City = "";
State = "TX";
County = null;
ServiceArea = null;
}
OnPropertyChanged("City");
OnPropertyChanged("State");
OnPropertyChanged("County");
OnPropertyChanged("ServiceArea");
}
}
}
OrganizationDetailsVMB:
class OrganizationDetailsVMB : ViewModelBase
{
private string _organizationName;
private string _street1;
private string _street2;
private string _city;
private string _state;
private string _zip;
private string _county;
private string _serviceArea;
private bool _cbo;
private bool _fbo;
private bool _mo;
private bool _sbo;
private bool _sno;
private readonly OrganizationListTableAdapter _organizationListTableAdapter = new OrganizationListTableAdapter();
private readonly OrgByNameTableAdapter _orgByNameTableAdapter = new OrgByNameTableAdapter();
private readonly OrgTypeByOrgNameTableAdapter _orgTypeByOrgNameTableAdapter = new OrgTypeByOrgNameTableAdapter();
public string OrganizationSelected
{
get { return _organizationName; }
set
{
_organizationName = value;
var organizationQueryResults = _orgByNameTableAdapter.GetOrganizationByName(_organizationName);
var orgTypeQueryResults = _orgTypeByOrgNameTableAdapter.GetOrgTypeByName(_organizationName);
if (organizationQueryResults.Rows.Count != 0)
{
OrgStreet1Value = organizationQueryResults.Rows[0].ItemArray[1].ToString();
OrgStreet2Value = organizationQueryResults.Rows[0].ItemArray[2].ToString();
OrgCityValue = organizationQueryResults.Rows[0].ItemArray[3].ToString();
OrgStateValue = organizationQueryResults.Rows[0].ItemArray[4].ToString();
OrgZipValue = organizationQueryResults.Rows[0].ItemArray[5].ToString();
OrgCountyValue = organizationQueryResults.Rows[0].ItemArray[6].ToString();
OrgServiceAreaValue = organizationQueryResults.Rows[0].ItemArray[7].ToString();
CBO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[1]);
FBO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[2]);
SBO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[3]);
MO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[4]);
SNO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[5]);
}
else
{
OrgStreet1Value = "";
OrgStreet2Value = "";
OrgCityValue = "";
OrgStateValue = "";
OrgZipValue = "";
OrgCountyValue = "";
OrgServiceAreaValue = "";
CBO = false;
FBO = false;
SBO = false;
MO = false;
SNO = false;
}
}
}
public ObservableCollection<string> OrganizationSource
{
get
{
var organizationList = _organizationListTableAdapter.GetOrganizationList();
var organizationSource = new ObservableCollection<string>();
organizationSource.AddRange(from DataRow row in organizationList.Rows select row.ItemArray[0].ToString());
return organizationSource;
}
}
public string OrgStreet1Value
{
get { return _street1; }
set
{
if (_street1 != value)
{
Validator.ValidateProperty(value,
new ValidationContext(this, null, null) { MemberName = "OrgStreet1Value" });
_street1 = value;
OnPropertyChanged("OrgStreet1Value");
}
}
}
public string OrgStreet2Value
{
get { return _street2; }
set
{
if (_street2 != value)
{
Validator.ValidateProperty(value,
new ValidationContext(this, null, null) { MemberName = "OrgStreet2Value" });
_street2 = value;
OnPropertyChanged("OrgStreet2Value");
}
}
}
public string OrgCityValue
{
get { return _city; }
set
{
if (_street1 != value)
{
Validator.ValidateProperty(value,
new ValidationContext(this, null, null) { MemberName = "OrgCityValue" });
_city = value;
OnPropertyChanged("OrgCityValue");
}
}
}
public string OrgStateValue
{
get { return _state; }
set
{
if (_state != value)
{
Validator.ValidateProperty(value,
new ValidationContext(this, null, null) { MemberName = "OrgStateValue" });
_state = value;
OnPropertyChanged("OrgStateValue");
}
}
}
public string OrgZipValue
{
get { return _zip; }
set
{
if (_zip != value)
{
Validator.ValidateProperty(value,
new ValidationContext(this, null, null) { MemberName = "OrgZipValue" });
_zip = value;
OnPropertyChanged("OrgZipValue");
}
}
}
public string OrgCountyValue
{
get { return _county; }
set
{
if (_county != value)
{
Validator.ValidateProperty(value,
new ValidationContext(this, null, null) { MemberName = "OrgCountyValue" });
_county = value;
OnPropertyChanged("OrgCountyValue");
}
}
}
public string OrgServiceAreaValue
{
get { return _serviceArea; }
set
{
if (_serviceArea != value)
{
Validator.ValidateProperty(value,
new ValidationContext(this, null, null) { MemberName = "OrgServiceAreaValue" });
_serviceArea = value;
OnPropertyChanged("OrgServiceAreaValue");
}
}
}
public bool CBO
{
get { return _cbo; }
set
{
_cbo = value;
OnPropertyChanged("CBO");
}
}
public bool FBO
{
get { return _fbo; }
set
{
_fbo = value;
OnPropertyChanged("FBO");
}
}
public bool SBO
{
get { return _sbo; }
set
{
_sbo = value;
OnPropertyChanged("SBO");
}
}
public bool MO
{
get { return _mo; }
set
{
_mo = value;
OnPropertyChanged("MO");
}
}
public bool SNO
{
get { return _sno; }
set
{
_sno = value;
OnPropertyChanged("SNO");
}
}
}
EventDetailsTab:
<TabItem Header="Event Details" x:Name="EventDetailsTab"
Style="{StaticResource TabStyle}"
DataContext="{Binding EventDetails}">
<eventTabs:_1_EventDetailsTab />
</TabItem>
OrganizationDetailsTab:
<TabItem Header="Organization" x:Name="OrganizationTab"
Style="{StaticResource TabStyle}"
DataContext="{Binding OrganizationDetails}">
<eventTabs:_2_OrganizationTab />
</TabItem>
As I said the bindings work flawlessly overall, but I want to reference a binding associated with OrganizationDetails for a control that resides in both the EventDetailsTab and OrganizationDetailsTab.
The code for that item is as follows...
<ComboBox Name="OrgNameComboBox" ItemsSource="{Binding OrganizationSource}"
SelectedValue="{Binding OrganizationSelected,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
You're setting the DataContext for your event details tab to {Binding EventDetails} and the DataContext for your organization tab to {Binding OrganizationDetails}, but the OrganizationSource and OrganizationSelected fields that your ComboBoxes are binding to only exist in the OrganizationDetailsVMB class. A quick hack would be to change your event details ComboBox to point to the correct place with a RelativeSource binding back to the TabItem's DataContext and down again to the OrganizationDetails:
<ComboBox Name="OrgNameComboBox" ItemsSource="{Binding OrganizationSource}"
DataContext="{Binding RelativeSource={RelativeSource AncestorType=TabControl}, Path=DataContext.OrganizationDetails}"
SelectedValue="{Binding OrganizationSelected,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
To be perfectly honest though I think you need to clean up your architecture. Your view model appears very tightly coupled to your underlying data model instead of the view, to the point where you're even accessing your table adapters in your getters which means A) you have no way of doing session management, B) your view performance will now be throttled by your DAL and you'll start having performance issues, and C) trying to introduce any type of multi-threading will cause all manner of access conflicts in your ORM.
A)
This way is good when you want have some data (like a combobox info) across an App or Multi Window:
Create 3 ViewModel (all inherited from INotifyPropertyChanged).
OrganizationViewModel: INCLUDE OrganizationSource and OrganizationSelected
OrganizationDetailsViewModel: WHITHOUT OrganizationSource and OrganizationSelected
OrganizationEventsViewModel: WHITHOUT OrganizationSource and OrganizationSelected
Now you can create a simple Static class named GeneralData & make a static property in it of OrganizationViewModel type like this:
public static class GeneralData{
public static OrganizationViewModel Organization {get;set;}
}
In the App.xaml.cs fill the Organization property of the GeneralData class with a new instance of OrganizationViewModel.
Ok... Now we have every things we need to start playing....
Every time you want to fill the ComboBox you should use the Organization [static property] of GeneralData class like this:
<ComboBox Name="OrgNameComboBox"
DataSource="{Binding Source={x:Static GeneralData.Organization}}"
ItemsSource="{Binding Source={x:Static GeneralData.Organization.OrganizationSource}}"
SelectedValue="{Binding Source={x:Static GeneralData.Organization.OrganizationSelected,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
And every time you want check which item of the Combobox is selected in code-behind (such as inside the ViewModels) you can easily check it like this:
var selectedOrganisation = GeneralData.Organization.OrganizationSelected;
Note: i recommend to you before closing the window that include the ComboBox run this code (to make sure there is not any alive reference to the static property):
BindingOperations.ClearAllBindings(OrgNameComboBox);
B)
If you have just 1 window include 2 UserControl then prevent static properties and instead of above way use this way:
Create 3 ViewModel (all inherited from INotifyPropertyChanged).
OrganizationViewModel: INCLUDE OrganizationSource and OrganizationSelected
OrganizationDetailsViewModel: WHITHOUT OrganizationSource and OrganizationSelected
OrganizationEventsViewModel: WHITHOUT OrganizationSource and OrganizationSelected
Now easily implement this scenario:
In Window1.xaml.cs:
Window1.DataSource= new OrganizationViewModel();
In EventUserControl.xaml.cs:
EventUserControl.DataSource= new OrganizationEventsViewModel();
In OrganizationDetailsUserControl.xaml.cs:
EventUserControl.DataSource= new OrganizationDetailsViewModel();
Now create a DependencyProperty in both EventUserControl and OrganizationDetailsUserControl to give them the SelectedItem of ComboBox. Your property type should be string. you can create the DependencyPropertys base on this tutorial.
For example use this name for your DependencyPropertys in both UserControls: SelectedOrganisation
OK, put the Combobox in the Window1.xaml (NOT inside any UserControl).
Now we fill these SelectedOrganisations from outer their UserControls like the following codes.
In Window1.xaml
<uc.OrganizationDetailsUserControl
SelectedOrganisation="{Binding ElementName=OrgNameComboBox, Path=SelectedItem}"/>
<uc.EventUserControl
SelectedOrganisation="{Binding ElementName=OrgNameComboBox, Path=SelectedItem}"/>
Now you have the SelectedItem of the ComboBox inside your UserControl you can play with it inside the UserControls and call some methods of the ViewModels with SelectedOrganisation as method parameter.
The route I took is the MVVM Light Toolkit.
I'm having trouble displaying the results in the AutoSuggestBox on Windows Phone 8.1. I'm using MVVM Light to bind my itemsource to the Autosuggestbox.
<AutoSuggestBox Header="Van" Text="{Binding SearchTextFrom, Mode=TwoWay}" ItemsSource="{Binding suggestionFrom}">
<AutoSuggestBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding description}"/>
</DataTemplate>
</AutoSuggestBox.ItemTemplate>
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="TextChanged">
<core:InvokeCommandAction Command="{Binding SearchChangedFrom}">
</core:InvokeCommandAction>
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</AutoSuggestBox>
My ViewModel
private RelayCommand _SearchChangedFrom;
public RelayCommand SearchChangedFrom
{
get
{
return _SearchChangedFrom ?? (_SearchChangedFrom = new RelayCommand(
async () =>
{
if (string.IsNullOrWhiteSpace(user.countrycode))
{
Debug.WriteLine("Could not autocomplete the country because there was no country code provided.");
return;
}
var predictions = await _Service.GetGoogleMapsSuggestionFromQuery(user.countrycode, SearchTextFrom);
suggestionFrom = predictions;
}));
}
}
private List<Prediction> _suggestionFrom;
public List<Prediction> suggestionFrom
{
get { return _suggestionFrom; }
set
{
Set<List<Prediction>>(() => suggestionFrom, ref _suggestionFrom, value);
Debug.WriteLine(suggestionFrom.Count + " were received. Displayong them in the autosuggestbox");
foreach (Prediction prediction in _suggestionFrom)
{
Debug.WriteLine(("Predicition: " + prediction.description));
}
}
}
The objects are set and are not null.
So why don't they show up?
UPDATE
My Model
public class Prediction : ObservableObject
{
private string _description;
public string description
{
get { return _description; }
set{Set<string>(() => description, ref _description, value);}
}
private string _id;
public string id
{
get { return _id; }
set { Set<string>(() => id, ref _id, value); }
}
private List<MatchedSubstring> _matchedSubstrings;
public List<MatchedSubstring> matched_substrings
{
get { return _matchedSubstrings; }
set{Set<List<MatchedSubstring>>(() => matched_substrings, ref _matchedSubstrings, value);}
}
private string _place_id;
public string place_id
{
get { return _place_id; }
set { Set<string>(() => place_id, ref _place_id, value); }
}
private string _reference;
public string reference
{
get { return _reference; }
set { Set<string>(() => reference, ref _reference, value); }
}
private List<Term> _terms;
public List<Term> terms
{
get { return _terms; }
set { Set<List<Term>>(() => terms, ref _terms, value); }
}
private List<string> _types;
public List<string> types
{
get { return _types; }
set { Set<List<String>>(() => types, ref _types, value); }
}
public override string ToString()
{
return this.description;
}
}
Use
public ObservableCollection<Prediction> SuggestionFrom { get; set; }
instead
public List<Prediction> SuggestionFrom { get; set; }
ObservableCollection is notify user interface about any changes of your Predictions (add or delete)
In WPF, I have a static "Customer" object in the definition for MainWindow.xaml.cs. This customer has a publicly accessible string Name property. In expression blend 4, I click on the "Advanced Options" box beside the "Text" property for the TextBox that I would like to bind to the customer name. I then click "Data Binding..." -> "Element Property" -> "window" under "scene elements" -> click the expander arrow beside "ActiveCustomer" -> then click "Name" -> "OK". The binding is to a readonly TextBox, so One Way binding is acceptable as the default. But when I run my app, it doesn't display the customer's name. Any Suggestions?
<TextBox x:Name="AIAHNameTextBox" Height="26" Canvas.Left="90" TextWrapping="Wrap" Canvas.Top="8" Width="100" IsReadOnly="True" VerticalContentAlignment="Center" Text="{Binding ActiveCustomer.Name, ElementName=window, Mode=OneWay}" />
ActiveCustomer is an instance of my Customer class:
namespace WPFBankingSystem
{
public enum CustomerStatus
{ Open, Closed }
public enum TransferType
{ CheckingToSaving, SavingToChecking }
[Serializable]
public class Customer
{
private string address;
private Checking chkAcc;
private string name;
private int pin;
private Saving savAcc;
private string ssn;
private AccountStatus status;
private string tel;
public string Address
{
get { return address; }
set { address = value; }
}
public Checking ChkAcc
{
get { return chkAcc; }
set { chkAcc = value; }
}
public string Name
{ get { return name; } }
public int Pin
{
get { return pin; }
set { pin = value; }
}
public Saving SavAcc
{
get { return savAcc; }
set { savAcc = value; }
}
public string Ssn
{ get { return ssn; } }
public AccountStatus Status
{
get { return status; }
set { status = value; }
}
public string Tel
{
get { return tel; }
set { tel = value; }
}
public void create(string Name, string Address, string TelephoneNumber, string SSN, int PIN)
{
this.address = Address;
this.name = Name;
this.pin = PIN;
this.ssn = SSN;
this.status = AccountStatus.Open;
this.tel = TelephoneNumber;
}
public void delete()
{
if (this.chkAcc != null)
{ chkAcc.close(); }
if (this.savAcc != null)
{ savAcc.close(); }
}
public bool hasChkAcc()
{ return (this.chkAcc != null) ? true : false; }
public bool hasSavAcc()
{ return (this.savAcc != null) ? true : false; }
public void show()
{ }
public void transfer(double Amount, TransferType Type)
{
if(this.hasChkAcc() && this.hasSavAcc())
{
switch(Type)
{
case TransferType.CheckingToSaving:
this.chkAcc.Balance -= Amount;
this.savAcc.Balance += Amount;
break;
case TransferType.SavingToChecking:
this.savAcc.Balance -= Amount;
this.chkAcc.Balance += Amount;
break;
}
}
else
{ throw new Exception("You do not have both a checking account and a saving account."); }
}
public Customer()
{ }
~Customer()
{ this.delete(); }
}
}
Inside MainWindow.xaml.cs, the customer is defined just as a public Customer object:
public Customer ActiveCustomer
{ get; set; }
You cannot bind to static properties like you can to instance properties. The property ActiveCustomer then does not exist on the element named window it exists in the class MainWindow. You should be able to fix the binding by using a Source in conjunction with x:Static:
{Binding Name, Source={x:Static local:MainWindow.ActiveCustomer}}
Note that x:Static has a very specific syntax, it does not allow an arbitrary path or the like.
Even if the binding works this is problematic though as you cannot implement INPC for static properties, so if you assign a new object to ActiveCustomer there will be no update.