Friends,
I am using MVVM to bind ListBox SelectedItem but seems it doesn't work. The list is binded successfully, but No item is selected.
XAML Page
<ListBox x:Name="lsbReadingChapter" SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
ItemsSource="{Binding QuranText}" Style="{StaticResource ListBoxStyle1}"
Grid.Row="1">
....
</ListBox>
MVVM Code
public class QuranTextViewModel : INotifyPropertyChanged
{
DataSource ds = null;
ObservableCollection<ArabicTextWithTranslation> _quranText;
public QuranTextViewModel(Chapter c)
{
ds = new DataSource();
QuranText = new ObservableCollection<ArabicTextWithTranslation>();
List<ArabicTextWithTranslation> texts = ds.getArabicTextWithTranslation(c);
Recent r = DataSource.Recents;
SelectedItem = (from grp in texts
where grp.ArabicText.ChapterID == r.ChapterID && grp.ArabicText.AyaID == r.AyaID
select grp).FirstOrDefault();
foreach (ArabicTextWithTranslation t in texts)
{
QuranText.Add(t);
}
}
public ObservableCollection<ArabicTextWithTranslation> QuranText
{
get { return _quranText; }
set
{
if (_quranText != value)
{
_quranText = value;
OnPropertyChanged("QuranText");
}
}
}
ArabicTextWithTranslation _selectedItem;
public ArabicTextWithTranslation SelectedItem
{
get {
return _selectedItem;
}
set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
}
}
The SelectedItem is not working, though in debug mode I can see the value in SelectedItem.
How to set SelectedItem and Highlight the SelectedItem?
Related
I want to get selected Item from ListView. My view is:
<ListView Name="StudentGrid" Grid.Row="1" Margin="1,1,1,1" ItemsSource="{Binding studentList}" SelectedItem="{Binding selectedItem}">
The ViewModel is:
public ObservableCollection<Student> selectedItem { get; set; }
private void DeleteStudent()
{
ObservableCollection<Student> item = selectedItem;
if(selectedItem != null)
{
int a = item.Count;
}
}
I want to get index of the selected item. How can I do that?
The SelectedItem is an object in the bound collection, so it is of type Student and not ObservableCollection<Student> like the list itself. Furthermore, if you want the property to be bound two-way, meaning you can also change the index in the view model and the ListView will update the selected index accordingly, you have to implement INotifyPropertyChanged.
public class YourViewModel : INotifyPropertyChanged
{
private Student _selectedItem;
// ...other code.
public Student SelectedItem
{
get => _selectedItem;
set
{
if (_selectedItem == value)
return;
_selectedItem = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
To get the index, bind the SelectedIndex property, to a property of type int in your view model.
private int _selectedIndex;
public int SelectedIndex
{
get => _selectedIndex;
set
{
if (_selectedIndex == value)
return;
_selectedIndex = value;
OnPropertyChanged();
}
}
<ListView Name="StudentGrid" Grid.Row="1" Margin="1,1,1,1" ItemsSource="{Binding studentList}" SelectedIndex="{Binding SelectedIndex}"/>
You could also bind both or get the student by index from your list.
var student = studentList[SelectedIndex];
I am binding a combobox with a varaible on my PLC so when i change the combobox the changed value transmitted to my PLC but when i change on my PLC the combobox wont change even if the field is changed
I put a brakepoint on the field(the one i bind to SelectedItem) to check if it changes and it did but didn't affect the combobox
Here is my ViewModel
List<string> _temperatureList = new List<string> { "80 °C", "100 °C", "120 °C" };
public List<string> TemperatureList
{
get { return _temperatureList; }
}
public string Temperature
{
get
{
return (TemperatureGS != 0) ? string.Format("{0} °C", TemperatureGS) : "80 °C";
}
set
{
TemperatureGS = Convert.ToSByte(value.Replace(" °C", ""));
OnPropertyChanged();
WriteTemperature(TemperatureGS);
}
}
private short _temperature ;
public short TemperatureGS
{
get { return _temperature; }
set { SetProperty(ref _temperature, value); }
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
TemperatureGS = PLCread(0);
OnPropertyChanged(Temperature);
}
My Xaml code
<ComboBox SelectedItem="{Binding Temperature, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged }"
ItemsSource="{Binding TemperatureList }" />
I'm new to WPF.
I'm trying to make the SelectedItem for all the comboboxes to generic as there are a lot of ComboBox in my form.
When I use different SelectedItem for each ComboBox it works fine.
C# Code:
private DropDownModel _mySelectedItem_DeviceType;
public DropDownModel MySelectedItem_DeviceType
{
get { return _mySelectedItem_DeviceType; }
set
{
if (_mySelectedItem_DeviceType != value)
{
_mySelectedItem_DeviceType = value;
OnNotifyPropertyChanged("MySelectedItem_DeviceType");
}
}
}
private DropDownModel _mySelectedItem_All;
public DropDownModel MySelectedItem_All
{
get { return _mySelectedItem_All; }
set
{
if (_mySelectedItem_All != value)
{
_mySelectedItem_All = value;
OnNotifyPropertyChanged("MySelectedItem_All");
}
}
}
private DropDownModel _mySelectedItem_Status;
public DropDownModel MySelectedItem_Status
{
get { return _mySelectedItem_Status; }
set
{
if (_mySelectedItem_Status != value)
{
_mySelectedItem_Status = value;
OnNotifyPropertyChanged("MySelectedItem_Status");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnNotifyPropertyChanged(string propertyName)
{
var propertyChangedEvent = PropertyChanged;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
var myListDropDown = (from b in _entities.DeviceTypes
select new DropDownModel
{
ID = b.ID,
Name = b.Name
}).Distinct().ToList();
myListDropDown.Add(new DropDownModel
{
ID = -1,
Name = "Select Device"
});
myListDropDown = myListDropDown.OrderBy(x => x.Name).ToList();
//DisplayDeviceType = new ObservableCollection<DropDownModel>(myListDropDown);
DisplayDeviceType = new ObservableCollection<DropDownModel>(myListDropDown);
MySelectedItem_DeviceType = (from b in myListDropDown
where b.ID == (singleDevice == null ? -1 : singleDevice.DeviceTypeID)
select b).FirstOrDefault();
var allStatus = (from b in _entities.DeviceStatuses
select new DropDownModel
{
ID = b.ID,
Name = b.Status
}).Distinct().ToList();
allStatus.Add(new DropDownModel
{
ID = -1,
Name = "Select Status"
});
allStatus = allStatus.OrderBy(x => x.Name).ToList();
Status = new ObservableCollection<DropDownModel>(allStatus);
MySelectedItem_Status = (from b in allStatus
where b.ID == (singleDevice == null ? -1 : singleDevice.StatusID)
select b).FirstOrDefault();
XAML:
<ComboBox Name="DeviceTypeComboBox"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="143.917"
Grid.Row="1"
ItemsSource="{Binding DisplayDeviceType}"
SelectedItem="{Binding MySelectedItem_DeviceType}"
SelectedValue="ID"
SelectedValuePath="ID"
DisplayMemberPath="Name"
/>
<ComboBox Name="StatusTypeComboBox"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="143.917"
Grid.Column="4"
Grid.Row="1"
ItemsSource="{Binding Status}"
SelectedItem="{Binding MySelectedItem_Status}"
SelectedValue="ID"
SelectedValuePath="ID"
DisplayMemberPath="Name"
/>
// Works Fine
But when I try to replace MySelectedItem_Status & MySelectedItem_DeviceType with MySelectedItem_All in my XAML. It throws an Exception.
Thanks,
It sounds like you need to abstract a bit more and have a class that wraps up all these properties you are trying to set through combo box selected item.
For example
public class DeviceInfo
{
private DeviceDisplayType deviceType;
public DeviceDisplayType DeviceType
{
get { return deviceType; }
set { deviceType = value; }
}
private DeviceStatus deviceStatus
public DeviceStatus DeviceStatus
{
get { return deviceStatus; }
set { deviceStatus = value; }
}
}
And then have one of these DeviceInfo objects in your viewmodel, and make the xaml bind to those properties directly.
<ComboBox SelectedItem={Binding MyDeviceInfo.DeviceType} />
You will still need the properties somewhere, but rather than a disparate range of VM properties you are recognising that those properties are all part of a larger cohesive class.
Tried all the solutions for similar issues around here, still no go. I have a ComboBox that should work for selection of existing items and/or for adding new ones. Only the selected item part works. Category is just an object with a Name and Id.
Thanks in advance!
XAML
<ComboBox Name="CbCategory" ItemsSource="{Binding Categories}"
SelectedItem="{Binding SelectedCategory.Name, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding NewCategory.Name}" DisplayMemberPath="Name"
IsEditable="True"/>
Code behind
private Category _selectedCategory;
public Category SelectedCategory
{
get { return _selectedCategory; }
set
{
if (Equals(_selectedCategory, value)) return;
_selectedCategory = value;
SendPropertyChanged("SelectedCategory");
}
}
private Category _newCategory;
public Category NewCategory
{
get { return _newCategory; }
set
{
if (Equals(_newCategory, value)) return;
_newCategory = value;
SendPropertyChanged("NewCategory");
}
}
Your Text Binding doesn't work because you're binding against a null Category property. Instantiate it instead.
public Category NewCategory
{
get { return _newCategory ?? (_newCategory = new Category()); }
set
{
if (Equals(_newCategory, value)) return;
_newCategory = value;
SendPropertyChanged("NewCategory");
}
}
Edit: Elaborating as per your comment:
Your ComboBox.Text binding is set to "{Binding NewCategory.Name}", so no matter what the value of SelectedCategory is, the Text property will always reflect the name of the NewCategory.
When NewCategory is null, the Text property has nothing to bind to, and therefore the 2-way binding cannot be executed (that is, the value of the Text property cannot be passed back to NewCategory.Name, because that will cause an NullReferenceException (because the NewCategory is null).
This does not affect the case of the SelectedItem, because that's binding directly to the SelectedCategory property, and not a sub-property of that.
Create new varible to keep text of combobox. If the selectedItem having null value get the text of combobox as new Item,
Code :
<ComboBox Name="CbCategory" ItemsSource="{Binding Categories}"
SelectedItem="{Binding SelectedCategory.Name, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding Name}" DisplayMemberPath="Name"
IsEditable="True"/>
private String _name;
public Category Name
{
get { return _name; }
set
{
_name = value
SendPropertyChanged("Name");
}
}
public ICommand ItemChange
{
get
{
`return new RelayCommand(() =>`{
try{string item = this.SelectedCategory.Code;}
catch(Exception ex){string item = this.Name;}
}, () => { return true; });
}
}
I am using MVVM light in conjunction with EF4 and SQL CE 4, but I am having issues with my observable collection. My application doesn't neccessarily need to use the mvvm pattern, but since I need the benefits of an observablecollection I have decided to learn how to integrate it. I can successfully link my database of property entitites to my listbox and display them, I can also link some properties of these entities to textboxes, but where I am stuck is when I try to update these properties by typing in the textbox. Here is my xaml code for a textbox and the listbox:
<TextBox Text="{Binding SaleTitle, ValidatesOnDataErrors=true, Mode=TwoWay}"
<ListBox Height="424"
Margin="24,80,0,0"
x:Name="listBoxProperties"
VerticalAlignment="Top"
ItemTemplate="{StaticResource propertySummaryTemplate}"
IsSynchronizedWithCurrentItem="True"
Width="216" BorderThickness="0" Background="{x:Null}"
FontFamily="Segoe UI"
ItemsSource="{Binding PropertyList}"
SelectedItem="{Binding CurrentProperty, Mode=TwoWay}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
UseLayoutRounding="True"
HorizontalAlignment="Left"
ScrollViewer.VerticalScrollBarVisibility="Disabled" >
</ListBox>
Here is the code of part of my MainViewModel:
private string _SaleTitle;
public string SaleTitle
{
get
{
if (CurrentProperty != null)
return CurrentProperty.SaleTitle;
else
return "";
}
set
{
_SaleTitle = value;
RaisePropertyChanged("SaleTitle");
}
}
private RelayCommand loadCommand;
public ICommand LoadCommand
{
get
{
if (loadCommand == null)
loadCommand = new RelayCommand(() => Load());
return loadCommand;
}
}
private void Load()
{
PropertyList = new ObservableCollection<Property>((from property in entities.Properties.Include("Images")
select property));
propertyView = CollectionViewSource.GetDefaultView(PropertyList);
if (propertyView != null)
propertyView.CurrentChanged += new System.EventHandler(propertyView_CurrentChanged);
RaisePropertyChanged("CurrentContact");
RaisePropertyChanged("SaleTitle");
RaisePropertyChanged("Address");
RaisePropertyChanged("AuctioneerName");
RaisePropertyChanged("AgentName");
RaisePropertyChanged("Price");
RaisePropertyChanged("NextBid");
RaisePropertyChanged("Status");
}
void propertyView_CurrentChanged(object sender, System.EventArgs e)
{
RaisePropertyChanged("CurrentContact");
RaisePropertyChanged("SaleTitle");
RaisePropertyChanged("Address");
RaisePropertyChanged("AuctioneerName");
RaisePropertyChanged("AgentName");
RaisePropertyChanged("Price");
RaisePropertyChanged("NextBid");
RaisePropertyChanged("Status");
}
private Property _CurrentProperty;
public Property CurrentProperty
{
get
{
if (propertyView != null)
return propertyView.CurrentItem as Property;
return null;
}
set
{
_CurrentProperty = value;
RaisePropertyChanged("CurrentProperty");
}
}
public ObservableCollection<Property> PropertyList
{
get
{
return propertyList;
}
set
{
if (propertyList == value)
{
return;
}
var oldValue = propertyList;
propertyList = value;
// Update bindings, no broadcast
RaisePropertyChanged(PropertiesPropertyName);
}
}
public MainViewModel()
{
if (IsInDesignMode)
{
// Code runs in Blend --> create design time data.
}
else
{
// Code runs "for real"
entities = new Model1Container1();
}
}
////public override void Cleanup()
////{
//// // Clean up if needed
//// base.Cleanup();
////}
}
}
The listbox is populated successfully with the content from current selected item, but when I type in it and click out of it or do anything to lose focus it simply goes back to what was there before.
Take a look at your SaleTitle property definition. It Reads value from CurrentProperty.Saletitle but sets value to local field which is not used anythere.