In my main window I have a class where I store all my data in ( called "Measconsettings"). This class ("Measconsettings") contains an ObservableCollection "DeviceDefinitionList" of an other class "DeviceDefinition"
ObservableCollection<DeviceDefinition> DeviceDefinitionList.
When I press a button in my MainWindow a new window is created with datacontex = Measconsettings.
In this new window there is a combobox which ItemsSource is bound to "Measconsettings.DeviceDefinitionList".
<ComboBox Grid.Row="2" Grid.Column="2" Margin="2,0" Name="CboDeviceDefinitionList" ItemsSource="{Binding Path=DeviceDefinitionList}"/>
My problem now is that the combobox does not update automaticly when an item is added.
I need to close the new window and press the button again to open it and only then it shows the items in the combobox.
I tried adding CboDeviceDefinitionList.Items.Refresh(); but it does not work..
Only when I add CboDeviceDefinitionList.ItemsSource = orgMeasConSettings.DeviceDefinitionList; right after adding items to the ObservableCollection then they show up right away.
Any ideas or tips on how to properly bind to a combobox? PS: I'm wpf beginner
This is my solution after implementing INotifyPropertyChanged as suggested by manish.
EDIT: It now works!
public class MeasConSettings : INotifyPropertyChanged
{
private ObservableCollection<DeviceDefinition> mDeviceDefinitionList;
private DeviceDefinition mSelectedDeviceDefinition;
public ObservableCollection<DeviceDefinition> DeviceDefinitionList
{
get
{
return mDeviceDefinitionList;
}
set
{
mDeviceDefinitionList = value;
}
}
public DeviceDefinition SelectedDeviceDefinition
{
get
{
return mSelectedDeviceDefinition;
}
set
{
mSelectedDeviceDefinition = value;
NotifyPropertyChanged("SelectedDeviceDefinition");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
XAML CODE:
<ComboBox Grid.Row="2" Grid.Column="2" Margin="2,0" Name="CboDeviceDefinitionList" ItemsSource="{Binding Path=DeviceDefinitionList}" SelectedItem="{Binding Path=SelectedDeviceDefinition}"/>
CODE for adding item:
orgMeasConSettings.DeviceDefinitionList.Clear();
foreach (DeviceDefinition deviceDefinition in newSettings.DeviceDefinitionList)
{
orgMeasConSettings.DeviceDefinitionList.Add(deviceDefinition);
}
orgMeasConSettings.SelectedDeviceDefinition = newSettings.DeviceDefinitionList.FirstOrDefault();
Related
I am on a MVVM C# project.
I want to display a list of objects.
I want to add and remove items in this list and ALSO change items in this list.
So I choosed the BindingList<> over the ObservableCollection<>, which would not get noticed if an item has changed.
(I also tested the ObservableCollectionEx which is out there in the web, but this has the same behavior like the BindingList for me).
But the Listbox is not changing when items are changed.
(Adding and removing items is updated in the Listbox)
In my XAML
<ListBox DisplayMemberPath="NameIndex" ItemsSource="{Binding Profiles}" SelectedItem="{Binding SelectedProfile}">
or alternative with the ItemTemplate
<ListBox DockPanel.Dock="Right" ItemsSource="{Binding Profiles}" SelectedItem="{Binding SelectedProfile}" Margin="0,10,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding NameIndex}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In my ViewModel (ViewModelBase is implementing INotifyPropertyChanged etc)
public class ProfileListViewModel : ViewModelBase
{
private BindingList<Profile> profiles;
public BindingList<Profile> Profiles
{
get
{
return profiles;
}
set
{
profiles = value;
RaisePropertyChanged();
}
}
My items are also implementing INotifyPropertyChanged and I am calling OnPropertyChanged("Name") in my Setters.
My model
public class Profile : INotifyPropertyChanged
{
public Profile(){}
public int ProfileID { get; set; }
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
OnPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Wiring the View with the ViewModel (BindingList is initialized before View)
ProfileListViewModel plvw= new ProfileListViewModel(message.Content);
var profileView = new ProfileListView(plvw);
profileView.ShowDialog();
In the View.xaml.cs
public ProfileListView(ProfileListViewModel plvw)
{
InitializeComponent();
DataContext = plvw;
}
When I am changing the name of an object then I get the ListChanged event to which I have subscribted in my ViewModel (Profiles.ListChanged += Profiles_ListChanged;) for testing BUT the items in the ListBox are NOT changing.
What am I doing wrong?
How can I get a updated Listbox?
Since your DisplayIndex is the computed property NameIndex, you need to call OnPropertyChanged("NameIndex") when its value changes due to a change in other properties, e.g.:
public string Name
{
get
{
return name;
}
set
{
name = value;
OnPropertyChanged("Name");
OnPropertyChanged("NameIndex");
}
}
Use
Profiles.ResetBindings() to bind it again.
this is my first project in WPF and I am currently stuck on my Shopping Cart.
I create an object newbasketItem with the member ItemQuantity with the value "1". My listview works perfectly fine through Binding. I can add items, remove items and clear my Collection. Now to my problem:
I want to select an item in my viewlist and increment the ItemQuantity with a button.
Is there any way to edit the ItemQuantitywhen it has already been added to the Collection?
BasketItem newBasketItem = new BasketItem();
newBasketItem.ItemQuantity = 1;
basketitems.Add(newBasketItem);
newBasketItem is my ObservableCollection.
Thank you!
Your BasketItem class should implement the INotifiedPropertyChange interface and the listview content will be automatically updated (provided you have a binding on ItemQuantity).
For example:
public class BasketItem : INotifyPropertyChanged
{
private int quantity = 0;
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public int ItemQuantity
{
get
{
return this.quantity;
}
set
{
if (value != this.quantity)
{
this.quantity = value;
NotifyPropertyChanged();
}
}
}
}
The ObservableCollection already implements this interface but it is not enough since it only allows to trigger event when items are added, deleted or moved. But if you want the UI to be notified when an item is modified, this item must also implements the INotifyPropertyChanged interface.
About your click event, you should use an ICommand as suggested by #Sir Rufo. You can also do the following with a XAML like this:
<ListView ItemsSource="{Binding Items}" IsItemClickEnabled="True" ItemClick="ListView_ItemClick" Margin="0,50,0,0" >
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemQuantity}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and in your code behind:
private void ListView_ItemClick(object sender, ItemClickEventArgs e)
{
var item = e.ClickedItem as BasketItem;
item.ItemQuantity++;
}
I have a ListBox control in the WPF form which contains the Button control.
Button control has the int values like 65.
I want to display seven buttons which is divided of the 65.
Also I want to put the content on the button which says 1 - 10, 11 - 20, 21 - 30, etc.. and 65 value comes from the database.
You can use ListBox.ItemTemplate to create the listbox which contains the buttons.
Here is the sample which I have created which binds the ObservalbleCollection as the ItemSource of the listbox:
<ListBox ItemsSource="{Binding ListDiv}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Content="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The .cs File for the same is:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<string> listDiv;
public ObservableCollection<string> ListDiv
{
get { return listDiv; }
set
{
listDiv = value;
OnNotifyPropertyChanged("ListDiv");
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
GetList();
}
private void GetList()
{
ListDiv = new ObservableCollection<string>();
ListDiv.Add("1-10");
ListDiv.Add("2-20");
ListDiv.Add("3-30");
ListDiv.Add("4-40");
ListDiv.Add("5-50");
ListDiv.Add("6-60");
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnNotifyPropertyChanged(string S)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(S));
}
}
You can use your own logic part to Get the Observable Collection in GetList() Method.
Don't Forget to set the DataContext of the Class.
Hope this will help you, Thank you.
I got a sample mvvm app. The UI has a textbox, a button and a combobox. when I enter something in the textbox and hit the button, the text I enter gets added to an observablecollection. The Combobox is bound to that collection. How do I get the combobox to display the newly added string automaticly?
As I understand correctly, you want to add an item and select it.
Here is the example how it can be done using ViewModel and bindings.
Xaml:
<StackPanel>
<TextBox Text="{Binding ItemToAdd}"/>
<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" />
<Button Content="Add" Click="Button_Click"/>
</StackPanel>
ViewModel:
public class MainViewModel:INotifyPropertyChanged
{
public ObservableCollection<string> Items { get; set; }
public string ItemToAdd { get; set; }
private string selectedItem;
public string SelectedItem
{
get { return selectedItem; }
set
{
selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
public void AddNewItem()
{
this.Items.Add(this.ItemToAdd);
this.SelectedItem = this.ItemToAdd;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The MainViewModel has 3 properties (one for the TextBox and two other for the ComboBox) and the method AddNewItem without parameters.
The method can be triggered from a command, but there is no standard class for commands, so I will call it from the code-behind:
((MainViewModel)this.DataContext).AddNewItem();
So you must explicitly set an added item as selected after you add it to a collection.
Because the method OnItemsChanged of the ComboBox class is protected and can't be used.
If the ComboBox is bound to an ObservableCollection, the ComboBox will be updated as soon as the collection is changed.
That's the advantage of using an ObservableCollection - you don't need to do any extra coding to update the UI.
If this is not the behavior you're seeing, perhaps you can post some code/xaml.
In WPF I have a collection of bool? values and I want to bind each of these to a separate checkbox programmatically. I want the bindings to be TwoWay so that changing the value of the individual item in the collection in code updates the check box and vice versa.
I have spent ages trying to figure out how to do this and I am completely stuck. With the following code the checkbox only gets the right value when the window is loaded and that's it. Changing the check box doesn't even update the value in the collection. (UPDATE: this appears to be a bug in .NET4 as the collection does get updated in an identical .NET3.5 project. UPDATE: Microsoft have confirmed the bug and that it will be fixed in the .NET4 release.)
Many thanks in advance for your help!
C#:
namespace MyNamespace
{
public partial class MyWindow : Window, INotifyPropertyChanged
{
public MyWindow()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public List<bool?> myCollection = new List<bool?>
{ true, false, true, false, true, false };
public List<bool?> MyCollection
{
get { return myCollection; }
set { myCollection = value; }
}
}
}
XAML:
<CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}">
There are a few things that need changing here to get this to work. Firstly you'll need to wrap your boolean value in an object that implements the INotifyPropertyChanged interface in order to get the change notification that you are looking for. Currently you are binding to boolean values in your collection which do not implement the interface. To do this you could create a wrapper class like so :
public class Wrapper: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool val = false;
public bool Val
{
get { return val; }
set
{
val = value;
this.OnPropertyChanged("Val");
}
}
public Wrapper(bool val)
{
this.val = val;
}
}
You'll then want to create these objects in your form instead of a list of booleans. You may also want to use an observable collection instead of a list so that notification of items being added and removed are sent. This is shown below:
public Window1()
{
InitializeComponent();
this.DataContext = this;
}
private ObservableCollection<Wrapper> myCollection = new ObservableCollection<Wrapper>()
{new Wrapper(true), new Wrapper(false), new Wrapper(true)};
public ObservableCollection<Wrapper> MyCollection
{
get { return myCollection; }
}
The next thing to do is to display a list of check boxes in your ui. To do this WPF provides itemscontrols. ListBox is an itemscontrol so we can use this as a starting point. Set the itemssource of a listbox to be MyCollection. We then need to define how each Wrapper object is going to be displayed in the list box and this can be done with a datatemplate which is created in the windows resources. This is shown below :
<Window.Resources>
<DataTemplate x:Key="myCollectionItems">
<CheckBox IsChecked="{Binding Path=Val, Mode=TwoWay}"></CheckBox>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Path=MyCollection}" ItemTemplate="{StaticResource myCollectionItems}"></ListBox>
</Grid>
This should get you up and running with a simple demo of checkboxes that have values bound to a list of booleans.
What makes you think it's not working? It's working for me :)
Here's my test XAML:
<UniformGrid>
<CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}"/>
<ListBox ItemsSource="{Binding MyCollection}"/>
<Button Content="Test" Click="Button_Click"/>
</UniformGrid>
Here's my code behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
}
(the rest is the same as yours)
I placed a breakpoint on Button_Click and checked MyCollection[0] it was updated according to the IsChecked value of the CheckBox.
Try changing your collection type from List<bool?> to ObservableCollection<bool?> perhaps that is the reason you think it's not working for you (the fact that changes to the collection are not reflected anywhere else in your view).
Change your List<bool?> to an ObservableCollection<bool?>. A List does not raise the change notifications that WPF needs to update the UI. An ObservableCollection does. This handles the case where the list entry is changed and the CheckBox needs to update accordingly.
In the other direction, it works for me even with a List<bool?> -- i.e. toggling the checkbox modifies the value in the collection. Your binding syntax is certainly correct.