combobox selection triggers another combobox selection etc. in WPF - c#

I know this has been asked before, but for some reason it seems like its only working for me to an extent. I set up my XAML like this:
<Grid>
<ComboBox x:Name="cbCategories" ItemsSource="{Binding Categories}" DisplayMemberPath="Name" SelectedIndex="{Binding SelectedCategoryIndex}"/>
<ComboBox x:Name="cbSourceParam" ItemsSource="{Binding SourceParameters}" DisplayMemberPath="Name" SelectedIndex="{Binding SelectedSourceParameterIndex}"/>
<ComboBox x:Name="cbTargetParam" ItemsSource="{Binding TargetParameters}" DisplayMemberPath="Name" SelectedIndex="{Binding SelectedTargetParameterIndex}"/>
</Grid>
Then my ViewModel like this:
public class pmCopyParamToParamViewModel : ViewModelBase
{
public pmModel model;
public ObservableCollection<CategoryWrapper> Categories { get; private set; }
public pmCopyParamToParamViewModel(Document doc)
{
this.model = new pmModel(doc);
this.Categories = model.CollectCategories();
SelectedCategoryIndex = 0;
}
private ObservableCollection<ParameterWrapper> _sourceParameters;
public ObservableCollection<ParameterWrapper> SourceParameters
{
get { return _sourceParameters; }
set
{
if (_sourceParameters == value) return;
_sourceParameters = value;
RaisePropertyChanged(() => SourceParameters);
SelectedSourceParameterIndex = 0;
}
}
private ObservableCollection<ParameterWrapper> _targetParameters;
public ObservableCollection<ParameterWrapper> TargetParameters
{
get { return _targetParameters; }
set
{
if (_targetParameters == value) return;
_targetParameters = value;
RaisePropertyChanged(() => TargetParameters);
SelectedTargetParameterIndex = 0;
}
}
// logic for selected category index
private int _selectedCategoryIndex;
public int SelectedCategoryIndex
{
get { return _selectedCategoryIndex; }
set
{
if (_selectedCategoryIndex == value) return;
_selectedCategoryIndex = value;
RaisePropertyChanged(() => SelectedCategoryIndex);
SourceParameters = model.CollectParameters(Categories[SelectedCategoryIndex].ID, new string[] { "String", "Double", "Integer" });
}
}
private int _selectedSourceParameterIndex;
public int SelectedSourceParameterIndex
{
get { return _selectedSourceParameterIndex; }
set
{
if (_selectedSourceParameterIndex == value) return;
_selectedSourceParameterIndex = value;
RaisePropertyChanged(() => SelectedSourceParameterIndex);
TargetParameters = model.CollectParameters(Categories[SelectedCategoryIndex].ID, new string[] { SourceParameters[SelectedSourceParameterIndex].StorageType });
}
}
private int _selectedTargetParameterIndex;
public int SelectedTargetParameterIndex
{
get { return _selectedTargetParameterIndex; }
set
{
if (_selectedTargetParameterIndex == value) return;
_selectedTargetParameterIndex = value;
RaisePropertyChanged(() => SelectedTargetParameterIndex);
}
}
}
What I was expecting to happen is that on ViewModel initilization, it would collect all Categories. I then call SelectedCategoryIndex and set it to 0. That in turn should trigger SourceParameters to update and set the selected item initially to 0. That in turn would trigger TargetParameters to trigger and set the initial SelectedParameterIndex to 0.
So far, I am only seeing the Categories and Source Parameters getting set, but the Target Paramters combobox doesn't get set until i manually touch/change selection for the source parameters combobox.
Did I miss something here? Thanks!

Could this be the issue?
private int _selectedSourceParameterIndex; // Starts off as 0
public int SelectedSourceParameterIndex
{
set
{
// Setting to zero would not change the value, and this will return
if (_selectedSourceParameterIndex == value) return;
//... nothing here gets executed ...
_selectedSourceParameterIndex = value;
RaisePropertyChanged(() => SelectedSourceParameterIndex);
TargetParameters = model.CollectParameters(Categories[SelectedCategoryIndex].ID, new string[] { SourceParameters[SelectedSourceParameterIndex].StorageType });
}
}
I personally prefer binding SelectedItem instead of SelectedIndex. It'll give you the actual object (or null if none is selected) so you don't have to deal with the intricacies of a combobox/list indexing.

Related

Trying to Filter a bound ObservableCollection to a combobox based on another ComboBox Value not working

I see several other posts about this but I cannot seem to understand exactly how to get this working properly for my usage.
Here is what I have in a nutshell.
I have two Comboboxes--Role and Position.
I have both of these bound to an ObservableCollection which has Enum Values Converted to strings loaded into it on instantiation.
<ComboBox x:Name="empRoleCB" ItemsSource="{Binding Role}" SelectedItem="{Binding RoleStr}"/>
<ComboBox x:Name="empPositionCB" ItemsSource="{Binding Pos}" SelectedItem="{Binding PosStr}"/>
In my ViewModel:
public abstract class EmployeeMenuVMBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
{
if(!EqualityComparer<T>.Default.Equals(field, newValue))
{
field = newValue;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
return true;
}
return false;
}
}
class EmployeeMenuVM : EmployeeMenuVMBase
{
private ObservableCollection<string> _pos = new ObservableCollection<string>(Enum.GetNames(typeof(Global.Positions)));
private ObservableCollection<string> _role = new ObservableCollection<string>(Enum.GetNames(typeof(Global.Roles)));
public ObservableCollection<string> Pos { get => _pos; }
public ObservableCollection<string> Role { get => _role; }
public string RoleStr
{
get => _roleStr;
set => SetProperty(ref _roleStr, value);
}
public string PosStr
{
get => _posStr;
set => SetProperty(ref _posStr, value);
}
}
What I want to happen is when a Role is selected, based on that selection, only certain Positions should be shown. For instance if I select "Customer Service" as a Role, then Position should only contain "Manager", "CSS" and "None". If Role is "Admin" then Position should only contain "None", and so on and so forth.
The struggle I have is how to filter this properly. I see something with using CollectionViewSource but I am unsure how to get this to work with my example.
I have 5 roles and each role will have a different list of positions that need to be shown.
What is the best way to make this work with MINIMAL extra code or XAML?
One of the things I really dislike about WPF is seemingly simple things need huge amounts of code to make them work properly many times.
First, if you think that WPF is complicated. So, you are using it wrongly.
I suggest you to use the Filter of CollectionViewSource as flow:
<ComboBox x:Name="empPositionCB" ItemsSource="{Binding MyPositionFilter}" SelectionChanged="RoleComboBox_SelectionChanged" ....../>
public ICollectionView MyPositionFilter { get; set; }
//ctor
public MyUserControlOrWindow()
{
//Before InitComponent()
this.MyPositionFilter = new CollectionViewSource { Source = MyPosObservableCollection }.View;
InitComponent();
}
public void RoleComboBox_SelectionChanged(object sender,EventArgs e)
{
//Get the selected Role (the ? is to prevent NullException (VS 2015 >))
Role r = empRoleCB.SelectedItem as Role;
//Apply the filter
this.MyPositionFilter.Filter = item =>
{
//Make you sure to convert correcteley your Enumeration, I used it here like a class
Position p = item as Position;
//Put your condition here. For example:
return r.ToLowers().Contains(p.ToLower());
//Or
return (r != null && r.Length >= p.Length);
};
}
The filter does not change your Collection, All hidden item stay in your ObservableCollection.
This can all be done in your ViewModel by changing the value of the Positions (Pos) observable collection when the role changes.
class EmployeeMenuVM : EmployeeMenuVMBase
{
public EmployeeMenuVM()
{
var emptyPositions = new List<Global.Positions>()
{ Global.Positions.None };
_rolePositions.Add(Global.Roles.None, emptyPositions);
var customerServicePositions = new List<Global.Positions>()
{ Global.Positions.None, Global.Positions.CSS, Global.Positions.Manager };
_rolePositions.Add(Global.Roles.CustomerService, customerServicePositions);
}
private Dictionary<Global.Roles, List<Global.Positions>> _rolePositions = new Dictionary<Global.Roles, List<Global.Positions>>();
private string _roleStr;
private string _posStr;
private ObservableCollection<string> _pos = new ObservableCollection<string>(Enum.GetNames(typeof(Global.Positions)));
private ObservableCollection<string> _role = new ObservableCollection<string>(Enum.GetNames(typeof(Global.Roles)));
public ObservableCollection<string> Pos
{
get => _pos;
set
{
SetProperty(ref _pos, value);
}
}
public ObservableCollection<string> Role
{
get => _role;
}
public string RoleStr
{
get => _roleStr;
set
{
if (SetProperty(ref _roleStr, value))
{
Global.Roles role = (Global.Roles)Enum.Parse(typeof(Global.Roles), value);
var positions = _rolePositions[role].Select(p => p.ToString());
Pos = new ObservableCollection<string>(positions);
}
}
}
public string PosStr
{
get => _posStr;
set => SetProperty(ref _posStr, value);
}
}
Here is a working tester code just to see the main idea of how to do the filtering:
MainWindow.xaml
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication3"
x:Name="ThisView"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="600">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding Path=Roles, ElementName=ThisView}"
SelectedItem="{Binding Path=SelectedRole, ElementName=ThisView}"
Width="300" Height="60"/>
<ComboBox ItemsSource="{Binding Path=PositionCollectionView, ElementName=ThisView}" Width="300" Height="60"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window, INotifyPropertyChanged
{
public ICollectionView PositionCollectionView { get; set; }
public ObservableCollection<string> Roles { get; set; } = new ObservableCollection<string>();
public ObservableCollection<string> Positions { get; set; } = new ObservableCollection<string>();
private string _selectedRole = String.Empty;
public string SelectedRole
{
get { return _selectedRole; }
set
{
_selectedRole = value;
OnPropertyChanged();
//This Refresh activates the Filter again, so that every time you select a role, this property will call it.
PositionCollectionView.Refresh();
}
}
public MainWindow()
{
PositionCollectionView = CollectionViewSource.GetDefaultView(Positions);
PositionCollectionView.Filter = PositionsFilter;
//use you enums here
Roles.Add("Role1");
Roles.Add("Role2");
Roles.Add("Role3");
Roles.Add("Role4");
Positions.Add("Position1");
Positions.Add("Position2");
Positions.Add("Position3");
Positions.Add("Position4");
InitializeComponent();
}
private bool PositionsFilter(object position)
{
bool result = true;
//place your code according to the Role selected to decide wheather "position" should be in the position list or not
return result;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Hope it helps..

Using C#/XAML, how do I update the ItemsSourceList of a second combobox based on the selected item of the first combobox?

I have tried numerous approaches based on many examples on StackOverflow and elsewhere, but just can't get this to work. I want the list of choices for ComboBox B to be different based on the selected item in ComboBox A. Could someone please help me determine what I'm doing wrong? (I am using MVVMLight.)
Here are the ItemsSources for the two comboboxes:
private ObservableCollection<SetupSF> _sourceForSFList = new ObservableCollection<SetupSF>();
public ObservableCollection<SetupSF> SourceForSFList
{
get { return _sourceForSFList; }
set
{
_sourceForSFList = value;
}
}
private ObservableCollection<SetupSFE> _sourceForSFEList = new ObservableCollection<SetupSFE>();
public ObservableCollection<SetupSFE> SourceForSFEList
{
get { return _sourceForSFEList; }
set
{
_sourceForSFEList = value;
}
}
Here is the selector. I tried using RelayPropertyChanged even though it's an observable collection, but that had no effect. I've verified that contents of the list is updating by setting a breakpoint. The list updates, but apparently does not notify the second combobox. _selectedSF.OwnedSFEs is itself an ObservalbleCollection.
public SetupSubfactor SelectedSF
{
get { return _selectedSF; }
set
{
_selectedSF = value;
if (_selectedSF != null)
{
SourceForSFEList = _selectedSF.OwnedSFEs;
}
}
}
Here is the code for the SF type. It is defined outside the ViewModel. (Could that be the problem?
public class SetupSF : ViewModelBase
{
private string _iD;
public string Id
{
get { return _iD; }
set
{
_iD = value;
RaisePropertyChanged(nameof(Id));
}
}
private string _sfName;
public string SFName
{
get { return _sfName; }
set
{
_sfName = value;
RaisePropertyChanged(nameof(SFName));
}
}
public ObservableCollection<SetupSFE> OwnedSFEs { get; set; }
}
Here is the XAML for the comboboxes:
<ComboBox x:Name="ComboBox A"
Width="350"
ItemsSource="{x:Bind ViewModel.SourceForSFList}"
SelectedItem="{x:Bind ViewModel.SelectedSF, Mode=TwoWay}"
DisplayMemberPath="SFName"/>
<ComboBox x:Name="Comobox B"
Width="350"
ItemsSource="{x:Bind ViewModel.SourceForSFEList}"
SelectedItem="{x:Bind ViewModel.SelectedSFE, Mode=TwoWay}
DisplayMemberPath="SFEName"/>
I believe you want to change your SourceForSFEList to look like this:
private ObservableCollection<SetupSFE> _sourceForSFEList = new ObservableCollection<SetupSFE>();
public ObservableCollection<SetupSFE> SourceForSFEList
{
get { return _sourceForSFEList; }
set
{
_sourceForSFEList.Clear();
if (value != null)
{
foreach (var item in value)
{
_sourceForSFEList.Add(item);
}
}
}
}
The Binding system is calling your "get" once, and is getting the initial Collection that _sourceForSFEList points to. Later, you are changing _sourceForSFEList to point to another collection, but the Binding system doesn't know anything about that collection, and so the UI doesn't update. Once the binding system binds a UIElement to _sourceForSFEList, you need to update that original collection, instead of changing the value of _sourceForSFEList to point to a new collection.
I've tried to infer some of your original classes. Here is a working example that I used to have one CombBox's selection update another's.
public class ViewModel
{
private ObservableCollection<SetupSF> _sourceForSFList = new ObservableCollection<SetupSF>();
public ViewModel()
{
_sourceForSFList = new ObservableCollection<SetupSF>()
{
new SetupSF() { SFName = "One", OwnedSFEs = new ObservableCollection<SetupSFE> () { new SetupSFE() { SFEName = "Three" }, new SetupSFE() { SFEName = "Four" } } },
new SetupSF() { SFName = "Two", OwnedSFEs = new ObservableCollection<SetupSFE> () { new SetupSFE() { SFEName = "Five" }, new SetupSFE() { SFEName = "Six" } } }
};
_sourceForSFEList = new ObservableCollection<SetupSFE>()
{
new SetupSFE() { SFEName = "One"},
new SetupSFE() { SFEName = "Two"}
};
}
private SetupSF _selectedSF;
public SetupSF SelectedSF
{
get { return _selectedSF; }
set
{
_selectedSF = value;
if (_selectedSF != null)
{
SourceForSFEList = _selectedSF.OwnedSFEs;
}
}
}
public ObservableCollection<SetupSF> SourceForSFList
{
get { return _sourceForSFList; }
set
{
_sourceForSFList = value;
}
}
private ObservableCollection<SetupSFE> _sourceForSFEList = new ObservableCollection<SetupSFE>();
public ObservableCollection<SetupSFE> SourceForSFEList
{
get { return _sourceForSFEList; }
set
{
_sourceForSFEList.Clear();
if (value != null)
{
foreach (var item in value)
{
_sourceForSFEList.Add(item);
}
}
}
}
}
public class SetupSF
{
public String SFName { get; set; }
public ObservableCollection<SetupSFE> OwnedSFEs;
}
public class SetupSFE
{
public String SFEName { get; set; }
}
<Page
x:Class="App7.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App7"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.DataContext>
<local:ViewModel />
</Page.DataContext>
<StackPanel Orientation="Horizontal">
<ComboBox x:Name="ComboBoxA"
Width="350"
ItemsSource="{Binding SourceForSFList}"
SelectedItem="{Binding SelectedSF, Mode=TwoWay}"
DisplayMemberPath="SFName" Margin="10"/>
<ComboBox x:Name="ComoboxB"
Width="350"
ItemsSource="{Binding SourceForSFEList}"
SelectedItem="{Binding SelectedSFE, Mode=TwoWay}"
DisplayMemberPath="SFEName" Margin="10"/>
</StackPanel>
</Page>

Binding Radio Button IsChecked to object's current array of element's state

I am developing a small utility using C#/WPF/MVVM which would allow to set the input state of a controller we are using for testing. The communication between the app I am developing and the hardware/our web service communication to the hardware is only one way, meaning that the app will only be able to set the state of the inputs, but not get the states.
Another point to mention is that some types are already defined for this in some other parts of our solution, which are all in F#. To do my app, I am currently using C#. So I did a Unit class to wrap around the LocalControllerTypes.LocalController type defined in F#, containing a lot of needed information.
In order to do that, I have an enum enumerating the InputState possible (currently there is Active or Normal, but that list could potentially grow with time). Also, the number of inputs present on each unit type is different (some have 2, some have 4, some have more), so I have an ItemControl binded on the selected unit's array of Inputs, which unfortunately only contains the Name of the input which I have to display. The unit has 2 other properties related to the inputs it has, InputWriters, which is an array of a type which is used to send the command to the hardware/web service communicating with that hardware, and InputStates, which is an array of InputState for each input it has, as last set in the app (since we can't get the state from the hardware).
Now I would like to bind the IsChecked property of the radio buttons (which is what I define as ItemTemplate of the ItemsControl) to the InputState of the currently SelectedUnit (in my ViewModel). The problem I am having, is that I would somehow need to know the radio button is for which index of the SelectedUnit's Inputs array, in order to get the item at the same index for the SelectedUnit's InputStates property.
Is there any way to achieve this?
MainWindow.xaml:
...
<ItemsControl Grid.Row="1" ItemsSource="{Binding SelectedUnit.LocalControllerInfo.Inputs}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="10" FontSize="15" Style="{StaticResource TextBlockNormalBase}" Text="{Binding InputName}"/>
<StackPanel Orientation="Horizontal">
<RadioButton Margin="10" Foreground="White" Content="Normal"
IsChecked="{Binding Path=?,
Converter={StaticResource inputToBoolConverter},
ConverterParameter=?}"/>
<RadioButton Margin="10" Foreground="White" Content="Active"
IsChecked="{Binding Path=?,
Converter={StaticResource inputToBoolConverter},
ConverterParameter=?}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
...
Unit.cs:
public class Unit : BindableObject
{
public enum InputState
{
Normal,
Active
}
private LocalControllerTypes.LocalController _localControllerInfo;
private LocalControllerTypes.ArduinoInjector[] _arduinoInjector;
private WebWriter.WebWriter[] _inputWriters;
private SNMPNetworkSwitchConnection.SNMPNetworkSwitchConnection _networkSwitchConnection;
private InputState[] _inputStates;
private bool _isUnitConnected;
public Unit(LocalControllerTypes.LocalController localControllerInfo,
LocalControllerTypes.ArduinoInjector[] arduinoInjector,
WebWriter.WebWriter[] inputWriters,
SNMPNetworkSwitchConnection.SNMPNetworkSwitchConnection networkSwitchConnection)
{
_localControllerInfo = localControllerInfo;
_arduinoInjector = arduinoInjector;
_inputWriters = inputWriters;
_networkSwitchConnection = networkSwitchConnection;
// This assumption might not always be true, but there is no way for now to get the input state
_inputStates = Enumerable.Repeat(InputState.Normal, _inputWriters.Length).ToArray();
// This assumption might not always be true, but there is no way for now to get the connection state
_isUnitConnected = true;
}
public LocalControllerTypes.LocalController LocalControllerInfo
{
get
{
return _localControllerInfo;
}
set
{
if (_localControllerInfo != value)
{
_localControllerInfo = value;
RaisePropertyChanged();
}
}
}
public LocalControllerTypes.ArduinoInjector[] ArduinoInjectors
{
get
{
return _arduinoInjector;
}
set
{
if (_arduinoInjector != value)
{
_arduinoInjector = value;
RaisePropertyChanged();
}
}
}
public WebWriter.WebWriter[] InputWriters
{
get
{
return _inputWriters;
}
set
{
if (_inputWriters != value)
{
_inputWriters = value;
RaisePropertyChanged();
}
}
}
public SNMPNetworkSwitchConnection.SNMPNetworkSwitchConnection NetworkSwitchConnection
{
get
{
return _networkSwitchConnection;
}
set
{
if (_networkSwitchConnection != value)
{
_networkSwitchConnection = value;
RaisePropertyChanged();
}
}
}
public InputState[] InputStates
{
get
{
return _inputStates;
}
set
{
if (_inputStates != value)
{
_inputStates = value;
RaisePropertyChanged();
}
}
}
public bool IsUnitConnected
{
get
{
return _isUnitConnected;
}
set
{
if (_isUnitConnected != value)
{
_isUnitConnected = value;
RaisePropertyChanged();
}
}
}
}
MainViewModel.cs:
public class MainViewModel : INotifyPropertyChanged
{
private Unit _selectedUnit;
private ObservableCollection<Unit> _units;
private string _reader1RawCardData;
private string _reader2RawCardData;
private int _reader1BitsCount;
private int _reader2BitsCount;
public event PropertyChangedEventHandler PropertyChanged;
public MainViewModel(IUnitStore unitStore)
{
UnitStore = unitStore;
// We could use directly the unitstore instead of creating another container and binding on that, but
// not doing so will allow us to add unit filtering further down the road
_units = new ObservableCollection<Unit>(unitStore.Units);
_selectedUnit = _units.First();
_reader1RawCardData = "";
_reader2RawCardData = "";
_reader1BitsCount = 0;
_reader2BitsCount = 0;
}
protected void RaisePropertyChanged([CallerMemberName]string propertName = "")
{
var temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs(propertName));
}
}
protected void RefreshUnitStore(object obj)
{
UnitStore.UpdateStore();
Units = new ObservableCollection<Unit>(UnitStore.Units);
SelectedUnit = Units.First();
}
protected void SendReaderCardSwipe(object obj)
{
int unitReaderNumber = (int)obj;
IPAddress arduinoIp = SelectedUnit.LocalControllerInfo.Readers[unitReaderNumber - 1].InjectorIp;
int injectorNumber = SelectedUnit.LocalControllerInfo.Readers[unitReaderNumber - 1].InjectorNumber;
string serviceUrl = SelectedUnit.ArduinoInjectors.Where(injector => injector.Ip.Equals(arduinoIp)).First().Url;
InjectorInterface.CardSwipe<IPAddress>(serviceUrl, arduinoIp, injectorNumber, Reader1BitsCount, Reader1RawCardData);
}
protected void UpdateSelectedUnitConnectionState(object obj)
{
((INetworkConnection.INetworkConnection)SelectedUnit.NetworkSwitchConnection).SetConnection(SelectedUnit.IsUnitConnected);
}
public IUnitStore UnitStore
{
get;
private set;
}
public Unit SelectedUnit
{
get
{
return _selectedUnit;
}
set
{
if (_selectedUnit != value)
{
_selectedUnit = value;
RaisePropertyChanged();
}
}
}
public ObservableCollection<Unit> Units
{
get
{
return _units;
}
set
{
if (_units != value)
{
_units = value;
RaisePropertyChanged();
}
}
}
public string Reader1RawCardData
{
get
{
return _reader1RawCardData;
}
set
{
if (_reader1RawCardData != value)
{
_reader1RawCardData = value;
RaisePropertyChanged();
}
}
}
public string Reader2RawCardData
{
get
{
return _reader2RawCardData;
}
set
{
if (_reader2RawCardData != value)
{
_reader2RawCardData = value;
RaisePropertyChanged();
}
}
}
public int Reader1BitsCount
{
get
{
return _reader1BitsCount;
}
set
{
if (_reader1BitsCount != value)
{
_reader1BitsCount = value;
RaisePropertyChanged();
}
}
}
public int Reader2BitsCount
{
get
{
return _reader2BitsCount;
}
set
{
if (_reader2BitsCount != value)
{
_reader2BitsCount = value;
RaisePropertyChanged();
}
}
}
public ICommand RefreshSourceCommand
{
get
{
return new RelayCommand(RefreshUnitStore);
}
}
public ICommand SendReaderCardSwipeCommand
{
get
{
return new RelayCommand(SendReaderCardSwipe);
}
}
public ICommand UpdateSelectedUnitConnectionStateCommand
{
get
{
return new RelayCommand(UpdateSelectedUnitConnectionState);
}
}
}
Your ItemsControl is bound to SelectedUnit.LocalControllerInfo.Inputs. What is the type of .Inputs?
As written your bindings will not have access to InputState or InputName. That's not really in the scope of "how to identify what array item goes with what enum"
To address your original issue, one possibility would be to nest some tuples and bind to that, a la
List<Tuple<int,State>> States = new List<Tuple<int,State>>();
States.Add(new Tuple<int, State>(1,State.Bar));
States.Add(new Tuple<int, State>(2, State.Foo));
States.Add(new Tuple<int, State>(3, State.Bar));

Problems binding a DataGrid with an Observable Collection that receive null parameters in WPF

I'm new programming with C# in WPF, and I have an error:
I've bind my WPF DataGRid with an Observable Collection that receive parameters from a DataBase. First, when the Observable Collection receive all the parameters from the Stored Procedure the APP function normally, but when I have a null parameter into my data source (StoredProcedure), so the Observable Collection receive a null parameter, the application crash, and it don´t start.... the page just remain in blank
How to fix that problem ?
First Here I show the class I used as a Dada Context to my Page
class ColeccionDeDatos : INotifyPropertyChanged
{
private RegistroBLL regBll = new RegistroBLL();
private DivisionBLL divBll = new DivisionBLL();
private BrigadaBLL briBll = new BrigadaBLL();
private BatallonBLL batBll = new BatallonBLL();
private TropasBLL tropBll = new TropasBLL();
private CompañiaBLL compBLL = new CompañiaBLL();
private EstudioBLL estBll = new EstudioBLL();
private RegistroFullBLL regFullBll = new RegistroFullBLL();
private ObservableCollection<RegistroFullBO> coleccionFullRegistro = new ObservableCollection<RegistroFullBO>();
public ObservableCollection<RegistroFullBO> ColeccionFullRegistro
{
get { return coleccionFullRegistro; }
set { coleccionFullRegistro = value; }
}
private ObservableCollection<RegistroBO> coleccionRegistro = new ObservableCollection<RegistroBO>();
public ObservableCollection<RegistroBO> ColeccionRegistro
{
get { return coleccionRegistro; }
set { coleccionRegistro = value; }
}
private ObservableCollection<DivisionBO> coleccionDivision = new ObservableCollection<DivisionBO>();
public ObservableCollection<DivisionBO> ColeccionDivision
{
get { return coleccionDivision; }
set { coleccionDivision = value; }
}
private ObservableCollection<BrigadaBO> coleccionBrigada = new ObservableCollection<BrigadaBO>();
public ObservableCollection<BrigadaBO> ColeccionBrigada
{
get { return coleccionBrigada; }
set { coleccionBrigada = value; }
}
private ObservableCollection<BatallonBO> coleccionBatallon = new ObservableCollection<BatallonBO>();
public ObservableCollection<BatallonBO> ColeccionBatallon
{
get { return coleccionBatallon; }
set { coleccionBatallon = value; }
}
private ObservableCollection<TropasBO> coleccionTropas = new ObservableCollection<TropasBO>();
public ObservableCollection<TropasBO> ColeccionTropas
{
get { return coleccionTropas; }
set { coleccionTropas = value; }
}
private ObservableCollection<CompañiaBO> coleccionCompañia = new ObservableCollection<CompañiaBO>();
public ObservableCollection<CompañiaBO> ColeccionCompañia
{
get { return coleccionCompañia; }
set { coleccionCompañia = value; }
}
private ObservableCollection<EstudioBO> coleccionEstudio = new ObservableCollection<EstudioBO>();
public ObservableCollection<EstudioBO> ColeccionEstudio
{
get { return coleccionEstudio; }
set { coleccionEstudio = value; }
}
public ColeccionDeDatos()
{
ColeccionRegistro = regBll.ObtenerFilasRegistro();
ColeccionDivision = divBll.ObtenerFilasDivision();
ColeccionBrigada = briBll.ObtenerFilasBrigada();
ColeccionBatallon = batBll.ObtenerFilasBatallon();
ColeccionTropas = tropBll.ObtenerFilasTropas();
ColeccionCompañia = compBLL.ObtenerFilasCompañia();
ColeccionEstudio = estBll.ObtenerFilasEstudio();
ColeccionFullRegistro = regFullBll.ObtenerFilasRegistro();
}
Then In the code behind of the page a asign an instance of this class as DataContext for the Page element.
private void Page_Loaded(object sender, RoutedEventArgs e)
{
try
{
PagRegistroName.DataContext = colData;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "+++++++++++");
}
}
And for my Data Grid this one:
<DataGrid Name="dgRegistro" Margin="5" SelectionChanged="dgRegistro_SelectionChanged"
ItemsSource="{Binding Path=ColeccionFullRegistro}" AutoGenerateColumns="False">
In each cell template I used a combobox:
<DataGridTemplateColumn.CellEditingTemplate >
<DataTemplate>
<ComboBox x:Name="cmbDivision" Text="{Binding Path=Division, Mode=TwoWay}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Page, AncestorLevel=1},
Path=DataContext.ColeccionDivision}" DisplayMemberPath="Nom_division" SelectionChanged="cmbDivision_SelectionChanged" SelectedValuePath="Nom_division">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
so it is function a well as I want
https://onedrive.live.com/redir?resid=B371651233630F9A!153&authkey=!ADzRW6OvvdMZiMI&v=3&ithint=photo%2c.png
which corresponds to the table in DataBase
BUT, when I put a NULL value directly in the DataBase
http://1drv.ms/RrN5qO
The App start but still in blank everytime, so something is wrong..
Any idea what is the problem ?
Filter like this:
if(MyProperty == null)
{
MyProperty = string.Empty;
]

fill individual combobox in gridview combocolumn from another event

I have create two Combobox column in gridview. Now i want to fill second combobox depending on value of first combobox (On first combobox selectedValueChanged event). Please reply.
General approach may look like this:
private MyType1 _selectedItem1;
public MyType1 SelectedItem1
{
get { return _selectedItem1; }
set
{
if (_selectedItem1 == value) return;
_selectedItem1 = value;
//replace with string implementation, if needed
OnPropertyChanged(() => SelectedItem1);
if (_selectedItem1 == ...)
{
ItemsSource2 = new List<MyClass2> { ... };
}
else if (_selectedItem1 == ...)
{
...
}
}
}
private IList<MyType2> _itemsSource2;
public IList<MyType2> ItemsSource2
{
get { return _itemsSource2; }
set
{
if (_itemsSource2 == value) return;
_itemsSource2 = value;
OnPropertyChanged(() => ItemsSource2);
}
}

Categories