ListView Observable Collection Will Not Show Members - c#

Cannot get my listview to display data.
XAML
<Grid>
<DockPanel>
<ListView Name="lstDetectedComputers"
MinWidth="200"
DockPanel.Dock="Left"
ItemsSource="{Binding ComputersList}" DisplayMemberPath="ComputerName">
</ListView>
<DataGrid x:Name="ViewNetworkCardInformation"
ItemsSource="{Binding NetworkCardInformation}"/>
</DockPanel>
</Grid>
Code:
private ObservableCollection<Object> _ComputersList;
public ObservableCollection<Object> ComputersList
{
get
{
return _ComputersList;
}
set
{
_ComputersList = value; NotifyPropertyChanged("ComputersList");
}
}
private DataTable _NetworkCardInformation;
public DataTable NetworkCardInformation
{
get
{
return _NetworkCardInformation;
}
set
{
_NetworkCardInformation = value; NotifyPropertyChanged("NetworkCardInformation");
}
}
Strange thing is that NetworkCardInformation shows in my datagrid so this indicates that the datacontext is working as expected.
now im under the impression with a ObservableCollection i do not need a INotifyPropertyChange, if this is wrong please advised.
i have also tried just ItemsSource="{Binding ComputersList}"
I have put a break point into the code to ensure that the observable collection has data, and it is there .
ComputersList Count = 2 System.Collections.ObjectModel.ObservableCollection
[0] {AdminUltimate.Model.NetworkModel.ComputerNode} object {AdminUltimate.Model.NetworkModel.ComputerNode}
ComputerName "ASUS-PC" string
Could someone please assist.
Thank you

You have set DisplayMemberPath as ComputerName but Object doesn't have any such property so it shows nothing on view.
This can be validated by removing DisplayMemberPath, you will see fully qualified class name of your object since ToString() gets called on your object if no ItemTemplate and DisplayMemberPath is set on ListBox.
So, solution would be to change ObservableCollection<Object> to type of more concrete object containing property ComputerName i.e. ObservableCollection<ComputerNode>.

Related

OneWay/TwoWay binding in XAML using Lambda expression and MVVM pattern

I can not bind the Combobox.SelectedItemin XAML in my ViewModel using the MVVM pattern with lambdaexpressions.
In my MainWindow.xaml i have:
<ComboBox ItemsSource="{Binding Products}" IsEnabled="{Binding ProductsIsEnabled}" SelectedItem="{Binding SelectedProduct}" />
In my MainWindow.xaml.cs I have the DataContext correctly set (all other pieces of my code in xaml work just fine).
In my MainWindowViewModel.cs I have:
...
public string TitleText => Title.Text;
...
public ObservableCollection<object> Products => MyConverter.GetCollection(ProductList);
public bool ProductsIsEnabled => MyProduct.IsEnabled;
public object SelectedProduct => ProductList.SelectedItem; // --> this does not work
...
The error i receive when running is
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Private.CoreLib.dll
A TwoWay or OneWayToSource binding cannot work on the read-only property 'SelectedProduct' of type 'MyNamespace.MainWindowViewModel'.
All my objects implement INotifyPropertyChanged.
Does anybody know what am I missing or doing wrong here?
Thanks in advance!
public object SelectedProduct => ProductList.SelectedItem; is a short form for
public object SelectedProduct
{
get
{
return ProductList.SelectedItem;
}
}
That means a property with a lambda Expression is a property without a setter; it is a read-only property. SelectedItem of the combo box can be changed by the user, that means the user can change the value of the SelectedProduct property.
To fix it, you'll have either to at a setter to the property or you'll have to change the binding two one way:
<ComboBox ItemsSource="{Binding Products}" IsEnabled="{Binding ProductsIsEnabled}" SelectedItem="{Binding SelectedProduct, Mode=OneWay}" />
One-Way-Binding means that the property stays unchanged if the user changes it. Only if you change the property, the UI element will change.
Addendum: After I read your comment: Your property ProductList.SelectedItem can have a getter and a setter, but from that it does not mean that your property SelectedProduct will have a setter and a getter. Change it to
public object SelectedProduct
{
get
{
return ProductList.SelectedItem;
}
set
{
ProductList.SelectedItem = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedProduct)));
}
}
and it should work.

WinRT apps: ComboxBox and ListBox does not display anything when ItemsSource is List<Type>

I tried to use ListBox to display a set of Type names
in XAML:
<ListBox x:Name="box"></ListBox>
and in code behind
box.ItemsSource= new List<Type>(){typeof(double), typeof(int)};
But the ListBox is displays empty string, although I can feel that there are indeed two items in the Items list and can click.
Even if I change the ItemTemplate to the following, the FullName property of class Type is not shown
<ListBox x:Name="box">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=FullName}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What is going on here? The following shows the name, but is not what I want. I want Type to be stored.
box.ItemsSource= new List<string>(){typeof(double).FullName, typeof(int).FullName};
(I tried ComboBox, which has the same problem)
This is really strange, there are no binding errors at all. I don't know why it happens when you bind to a Type object directly (maybe it has something to do with the System namespace), but there is a workaround which is to create a wrapper class:
public class TypeWrapper
{
private Type _type;
public TypeWrapper(Type type)
{
_type = type;
}
public Type Type { get { return _type; } }
}
Then you create the ItemsSource as following:
box.ItemsSource = new List<TypeWrapper>()
{
new TypeWrapper(typeof (double)),
new TypeWrapper(typeof (int))
};
And in your XAML you use
<TextBlock Text="{Binding Type.FullName}"></TextBlock>
instead of
<TextBlock Text="{Binding FullName}"></TextBlock>

Prevent DataGrid from updating selected item in MVVM

I have a Datagrid with a list binded to ItemsSource and the SelectedItem is binded a single object of this list. My ViewModel implements INotifyPropertyChanged.
The binding works fine, except when there's a variable (canSelectOtherObject = false) that prevents myObject of changing it's value. Even thought myObject doesn't modify it's value, the datagrid on the View selects other object. How can I prevent this?
View:
<DataGrid ItemsSource="{Binding MyObjectList}" SelectedItem="{Binding MyObjectSelected, Mode=TwoWay}">
ViewModel:
private ObservableCollection<MyObject> myObjectList;
private MyObject myObjectSelected;
private bool canSelectOtherObject;
public ObservableCollection<MyObject> MyObjectList
{
get { return myObjectList; }
set { myObjectList = value; }
}
public MyObject MyObjectSelected
{
get { return myObjectSelected; }
set
{
if(canSelectOtherObject)
{
myObjectSelected = value;
OnPropertyChanged("MyObjectSelected");
}
}
}
Thanks!
INotifyPropertyChanged is used to notify the UI to update bindings when the properties of an object change, I think you are describing a situation where the object itself changes.
Given your binding:
<DataGrid ItemsSource="{Binding MicrophoneList}" SelectedItem="{Binding MicrophoneSelected, Mode=TwoWay}">
It's the difference between updating one of the properties of the selected microphone (would require INotifyPropertyChanged), and changing SelectedItem to a different microphone altogether (binding updates whether you notify or not).

Unable to clear selection in a combobox

Simple enough requirement - trying to reset a WPF combobox on user press of a "clear" button. Everything else on the form clears as expected, with the exception of this ComboBox.
<ComboBox ItemsSource="{Binding Members}" DisplayMemberPath="MemberName" SelectedValue="{Binding RequestingMember, Mode=TwoWay}" SelectedValuePath="MemberID" IsEditable="{Binding FixedRequestingMember }"></ComboBox>
Here's the property it's bound to:
public int RequestingMember
{
get { return _requestingMember; }
set
{
if (_requestingMember != value)
{
_requestingMember = value;
}
}
}
And here's what I'm using to clear the box:
this.RequestingMember = -1;
Worth mentioning that there's nothing in the Members collection which corresponds to a key of -1. The value doesn't change from its selection when you press clear, anyway.
I've tried setting the int to 0 and also setting UpdateSourceTrigger=PropertyChanged in the XAML, to no avail. I'm loathe to change RequestingMemeber to a type of int? as it'll need fixes that cascade a long way into other parts of the application.
What am I doing wrong?
Please read the Use SelectedValue, SelectedValuePath, and SelectedItem page on MSDN for the full information on this, but in short, you will have more luck by data binding to the SelectedItem property, rather than using the SelectedValue and SelectedValuePath properties. Try adding a property of the same type as the items in the collection and data binding that to the SelectedItem property instead:
public Member SelectedMember // Implement the INotifyPropertyChanged Interface here!!
{
get { return selectedMember; }
set
{
if (selectedMember != value)
{
selectedMember = value;
NotifyPropertyChanged("SelectedMember");
}
}
}
You will also need to implement the INotifyPropertyChanged Interface in your class with the properties. Your XAML should now look like this:
<ComboBox ItemsSource="{Binding Members}" DisplayMemberPath="MemberName"
SelectedItem="{Binding SelectedMember, Mode=TwoWay}"
IsEditable="{Binding FixedRequestingMember }" />
Now all you need to do to clear the selection is this:
SelectedMember = null;

WPF ComboBox Binding To Object On Initial Load

I have a combo box that is bound to a list of model objects. I've bound the combo box SelectedItem to a property that is the model type. All of my data binding works beautifully after the window has been loaded. The SelectedItem is set properly and I'm able to save the object directly with the repository.
The problem is when the window first loads I initialize the SelectedItem property and my combobox displays nothing. Before I moved to binding to objects I was binding to a list of strings and that worked just fine on initialization. I know I'm missing something but I can't figure it out.
Thanks in advance for any guidance you can provide.
(One note about the layout of this page. The combo boxes are actually part of another ItemTemplate that is used in a ListView. The ListView is bound to an observable collection in the main MV. Each item of this observable collection is itself a ModelView. It is that second ModelView that has the SelectedItem property.)
Here is my Model:
public class DistributionListModel : Notifier, IComparable
{
private string m_code;
private string m_description;
public string Code
{
get { return m_code; }
set { m_code = value; OnPropertyChanged("Code"); }
}
public string Name
{
get { return m_description; }
set { m_description = value; OnPropertyChanged("Name"); }
}
#region IComparable Members
public int CompareTo(object obj)
{
DistributionListModel compareObj = obj as DistributionListModel;
if (compareObj == null)
return 1;
return Code.CompareTo(compareObj.Code);
}
#endregion
}
Here the pertinent code in my ModelView:
public MailRoutingConfigurationViewModel(int agencyID)
: base()
{
m_agencyID = agencyID;
m_agencyName = DataManager.QueryEngine.GetAgencyName(agencyID);
IntializeValuesFromConfiguration(DataManager.MailQueryEngine.GetMailRoutingConfiguration(agencyID));
// reset modified flag
m_modified = false;
}
private void IntializeValuesFromConfiguration(RecordCheckMailRoutingConfiguration configuration)
{
SelectedDistributionList = ConfigurationRepository.Instance.GetDistributionListByCode(configuration.DistributionCode);
}
public DistributionListModel SelectedDistributionList
{
get { return m_selectedDistributionList; }
set
{
m_selectedDistributionList = value;
m_modified = true;
OnPropertyChanged("SelectedDistributionList");
}
}
And finally the pertinent XAML:
<UserControl.Resources>
<DataTemplate x:Key="DistributionListTemplate">
<Label Content="{Binding Path=Name}" />
</DataTemplate>
</UserControl.Resources>
<ComboBox
ItemsSource="{Binding Source={StaticResource DistributionCodeViewSource}, Mode=OneWay}"
ItemTemplate="{StaticResource DistributionListTemplate}"
SelectedItem="{Binding Path=SelectedDistributionList, Mode=TwoWay}"
IsSynchronizedWithCurrentItem="False"
/>
#SRM, if I understand correctly your problem is binding your comboBox to a collection of objects rather than a collection of values types ( like string or int- although string is not value type).
I would suggest add a two more properties on your combobox
<ComboBox
ItemsSource="{Binding Source={StaticResource DistributionCodeViewSource},
Mode=OneWay}"
ItemTemplate="{StaticResource DistributionListTemplate}"
SelectedItem="{Binding Path=SelectedDistributionList, Mode=TwoWay}"
SelectedValuePath="Code"
SelectedValue="{Binding SelectedDistributionList.Code }"/>
I am assuming here that DistributionListModel objects are identified by their Code.
The two properties I added SelectedValuePath and SelectedValue help the combobox identify what properties to use to mark select the ComboBoxItem by the popup control inside the combobox.
SelectedValuePath is used by the ItemSource and SelectedValue by for the TextBox.
don't call your IntializeValuesFromConfiguration from the constructor, but after the load of the view.
A way to achieve that is to create a command in your viewmodel that run this method, and then call the command in the loaded event.
With MVVM light toolkit, you can use the EventToCommand behavior... don't know mvvm framework you are using but there would probably be something like this.

Categories

Resources