I am trying to populate an Observable Collection Based on What items are selected from the AutoCompleteBox. May I get some guidance towards where I am going wrong. It's not Binding the way I would like it to.
xaml:
<telerik:RadAutoCompleteBox x:Name="RadAmortAutoBox" HorizontalAlignment="Left" Grid.Column="1" Grid.Row="6" VerticalAlignment="Top" SelectedItems="{Binding AmortDates, Mode=OneWay}"
ItemsSource="{Binding Payments}" DisplayMemberPath="PaymentNo" TextSearchPath="PaymentNo" Width="708" />
ViewModel:
public ObservableCollection<int> amortDates;
public ObservableCollection<int> AmortDates
{
get { return amortDates; }
set
{
amortDates = value;
RaisePropertyChanged("AmortDates");
}
}
Related
I am currently learning the MVVM design pattern for WPF and I would like to bind my CheckBoxes based on the SelectedItem of my ComboBox which is data binded to a Dictionary where the key is my device serial number and the value is a ViewModel for that device.
Ideally, my SelectedItem should be the value which is IOBoardViewModel.
<ComboBox Name="io_boards_list"
ItemsSource="{Binding IOBoards}" DisplayMemberPath="Key" SelectedValuePath="Value"
HorizontalAlignment="Left" Margin="361,28,0,0" VerticalAlignment="Top" Width="657" Height="35"/>
This is where I am most unclear: how to bind these bool values in my IOBoard Model.
<CheckBox IsChecked="{ Binding Value.io_board.s0 }" Content="Input 0" Canvas.Left="10" Canvas.Top="10" Height="15"/>
<CheckBox IsChecked="{ Binding Value.io_board.s1 }" Content="Input 1" Canvas.Left="10" Canvas.Top="36" Height="15"/>
<CheckBox IsChecked="{ Binding Value.io_board.s2 }" Content="Input 2" Canvas.Left="10" Canvas.Top="63" Height="15"/>
In my IOBoardViewModel I refer to the actual Model which is where I hold my bool value.
public Dictionary<string, IIOBoardViewModel> IOBoards { get; private set; }
public FullIOBoard io_board
{
get { return _io_board; }
}
Here is a snippet from my IOBoard Model:
public bool s0
{
get
{
return _s0;
}
set
{
_s0 = value;
OnPropertyChanged("s0");
}
}
public bool s1
{
get
{
return _s1;
}
set
{
_s1 = value;
OnPropertyChanged("s1");
}
}
public bool s2
{
get
{
return _s2;
}
set
{
_s2 = value;
OnPropertyChanged("s2");
}
}
I would like to know if I have the right idea on how to bind the data together in the MVVM pattern, and if not, I would greatly appreciate insights or advice.
UPDATE:
I have thought of a method that I could use where I bind the SelectedItem of the ComboBox (which would be the Dictionary's identifying serial number to a variable in my ViewModel):
public string SelectedItem
{
get
{
return _SelectedItem;
}
set
{
_SelectedItem = value;
}
}
Now I believe I should bind my IsChecked for the CheckBox to
<CheckBox IsChecked="{ Binding IOBoards[SelectedItem].s0 }" Content="Input 0" Canvas.Left="10" Canvas.Top="10" Height="15"/>
However I am still unable to get the checkbox to update even though I've hardcoded one of the signals to always be true:
_io_board.s0 = true;
_io_board.s1 = (inputSignal & 0x02) == 0x02;
you can bind directly to SelectedItem of ComboBox by referring to it by name:
<CheckBox IsChecked="{ Binding SelectedItem.Value.io_board.s0, ElementName=io_boards_list }"
I want to bind a ComboBox item to a string, but it does not work. My code is below.
Code in view:
<ComboBox
SelectedValuePath="content"
SelectedItem="{Binding ProductName}"
......
<ComboBoxItem>1111111111</ComboBoxItem>
<ComboBoxItem>2222222222222</ComboBoxItem>
<ComboBoxItem>333333333333</ComboBoxItem>
</ComboBox>
Code in view model:
private string _productName;
public string ProductName
{
get { return _productName; }
set
{
if (_productName != value)
{
_productName = value;
RaisePropertyChangedEvent("ProductName");
}
}
}
I assume you want to get the text from the ComboboxItem and not the ComboBoxItem iteself.
So you are binding the wrong information. This should work.
<ComboBox
SelectedValuePath="content"
Text="{Binding ProductName}"
......
<ComboBoxItem>1111111111</ComboBoxItem>
<ComboBoxItem>2222222222222</ComboBoxItem>
<ComboBoxItem>333333333333</ComboBoxItem>
</ComboBox>
Selected Item is of type ComboBoxItem, it will not accept String.
If you want to display product name in some other place try maybe something like this:
<TextBox Text="{Binding ElementName=my_ComboBox, Path=SelectedItem}"/>
Just a suggestion.
You already use a binding for the SelectedItem, why don't you set up another binding for the Items using the ItemsSource? So you would not need to add them statically in your view.
In addition you would not have the trouble to wonder whether you deal with instances of ComboxItem or String with your SelectedItem binding.
In case of the binding via ItemsSource you can be sure that the SelectedItem is a string.
Here is the code:
<ComboBox
SelectedValuePath="content"
SelectedItem="{Binding ProductName}"
ItemsSource="{Binding ProductNames}"
</ComboBox>
In your view model (or code behind) you define the ProductNames:
public String[] ProductNames
{
get
{
return _productNames;
}
set
{
if (_productNames!= value)
{
_productNames = value;
RaisePropertyChangedEvent("ProductNames");
}
}
}
String[] _productNames;
public NameOfConstructor()
{
List<String> productNames = new List<String>();
productNames.Add("A");
productNames.Add("B");
productNames.Add("C");
ProductNames = productNames.ToArray();
}
If it was possible that the list of names changes during execution, I would use a ObservableCollection<string> instead String[].
It should be like this
Create an observable collection of Product in View Model. Lets Say ProductCollection
Bind to the ComboBox ItemSource as given below
<ComboBox Name="productComboBox" Width="200" Height="30" ItemsSource="{Binding ProductCollection}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ProductName}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
if you want to show in textbox somewhere
use this
<TextBox Text="{Binding ElementName=productComboBox, Path=SelectedItem}"/>
I'm using WPF and have a TreeView on my form binding to model. Objects have attributes and I want to bind a selected item(in tree view) attributes to a listbox but I can't figure out how to this. My code is:
Bar class:
public class Bar
{
string barName;
List<bar> children;
List<Foo> attrs;
public string BarName
{
get { return barName; }
set { barName = value; }
}
public List<Folder> Children
{
get { return children; }
set { children = value; }
}
public List<Foo> Attributes
{
get { return attrs; }
set { attrs = value; }
}
public Bar(string name)
{
barName = name;
children = new List<Bar>();
attrs = new List<Foo>();
attrs.Add(new Foo { Name = "Attr1: " + name });
attrs.Add(new Foo { Name = "Attr2: " + name });
attrs.Add(new Foo { Name = "Attr3: " + name });
}
}
Foo class:
public class Foo
{
public string Name { get; set; }
}
Filling model:
Bar bar = new Folder("bar1");
bar.Children.Add(new Bar("bar1.1"));
bar.Children[0].Children.Add(new Bar("bar1.1.1"));
bar.Children.Add(new Bar("bar2"));
this.DataContext = bar;
And also XAML:
<Window.Resources>
<ResourceDictionary>
<HierarchicalDataTemplate DataType="{x:Type local:Bar}"
ItemsSource="{Binding Children}">
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding BarName}"
Foreground="Black"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Column="1"/>
</Grid>
</HierarchicalDataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<TreeView Height="162" HorizontalAlignment="Left" Margin="203,0,0,0" Name="treeView1" VerticalAlignment="Top" Width="288" ItemsSource="{Binding Children}"/>
<ListBox Height="100" HorizontalAlignment="Left" Margin="203,168,0,0" Name="listBox2" VerticalAlignment="Top" Width="288" ItemsSource="{Binding Name}"/>
</Grid>
Now TreeView binding works fine and I there is a Bar.Name displayed, but ListBox is empty. Please, explain me, what should I do?
You're binding your listbox to Name, so it's trying to find a property called "Name" in your Bar class. What I believe you're actually trying to do is show the attributes for the item that's currently selected in the TreeView. So bind to the TreeView's SelectedItem and set DisplayMemberPath to "Name":
<ListBox Height="100" HorizontalAlignment="Left" Margin="203,168,0,0" Name="listBox2" VerticalAlignment="Top" Width="288" ItemsSource="{Binding SelectedItem.Attributes, ElementName=treeView1}" DisplayMemberPath="Name"/>
This will work, but a better idea would be to create a member in you Bar class for the currently selected item (e.g. "CurrentTreeItem") and bind both the treelist's SelectedItem and the ListBox's source items to that property, that way at least you can put breakpoints in the setter etc and make sure your front end controls are firing properly. The problem with doing this though is that you don't seem to be supporting IPropertyChange notification (if you don't know what that is then drop what you're doing and hit Google before going any further).
You can bind your listbox directly to TreeView selected item by changing xaml to
<TreeView Height="162" HorizontalAlignment="Left" Margin="203,0,0,0" Name="treeView1" VerticalAlignment="Top" Width="288" ItemsSource="{Binding Source}" />
<ListBox DisplayMemberPath="Name" Height="100" HorizontalAlignment="Left" Margin="203,168,0,0" Name="listBox2" VerticalAlignment="Top" Width="288" ItemsSource="{Binding Path=SelectedItem.Attributes, ElementName=treeView1}"/>
Sadly, tree view's selected item is read only property, so you can't easily create a property in you view and bind both listbox and treeview to it.
Also you should change your population to
public ObservableCollection<Bar> Source { get; set; }
public MainWindow()
{
InitializeComponent();
Bar bar = new Bar("bar1");
bar.Children.Add(new Bar("bar1.1"));
bar.Children[0].Children.Add(new Bar("bar1.1.1"));
bar.Children.Add(new Bar("bar2"));
Source = new ObservableCollection<Bar>() { bar };
this.DataContext = this;
}
Be aware thought, that you have to implement INotifyPropertyChanged interface to allow bindings to update automatically
*Intro: *
I'm working with a standard MVVM framework and I have two listboxes from which I want to be able to select one item from. The listboxes are binding to different ObservableCollections of the same class.
After binding to the ViewModel, I want to be able to represent the selected Item on the same window, from either of the Listbox depending on which item I am selecting.
ViewModel -
private KisesaSearchResultViewModel _selectedPerson;
public KisesaSearchResultViewModel SelectedPerson
{
get
{
return _selectedPerson;
}
set
{
_selectedPerson = value;
OnPropertyChanged("SelectedPerson");
}
}
private KisesaSearchResultViewModel _selectedSearch;
public KisesaSearchResultViewModel SelectedSearch
{
get
{
return _selectedSearch;
}
set
{
_selectedSearch = value;
SelectedPerson = value;
OnPropertyChanged("SelectedSearch");
}
}
private KisesaSearchResultViewModel _selectedMatch;
public KisesaSearchResultViewModel SelectedMatch
{
get
{
return _selectedMatch;
}
set
{
_selectedMatch = value;
SelectedPerson = _selectedMatch;
OnPropertyChanged("SelectedMatch");
}
}
XAML -
<ListBox ItemsSource="{Binding Path=MatchedMembers, Mode=OneWay}"
ItemTemplate="{StaticResource SearchResult}"
SelectedItem="{Binding SelectedSearch}">
</ListBox>
<ListBox ItemsSource="{Binding Path=SelectedMatchList, Mode=OneWay}"
ItemTemplate="{StaticResource SearchResult}"
SelectedItem="{Binding SelectedMatch}">
</ListBox>
I want to display information as such:
<TextBlock Grid.Row="1" Text="{Binding Path= SelectedPerson.FullName}" FontSize="18" FontWeight="Bold" Style="{StaticResource PInfo}" />
<TextBlock Grid.Column="0" Grid.Row="2" Style="{StaticResource Info}" Margin="30,0,0,0" Text="{Binding Path=SelectedPerson.Age}"/>
Question:
I need to have SelectedSearch and SelectedPerson because I want to be able to change SelectedPerson independtly. At this point, the SelectedPerson is getting set by the SelectedSearch setter, but it is not binding to the Textblocks. I am using OnPropertyChanged, but do I need to do something else like use an Event Handler? Also, slightly unrelated, but can I restrict a WPF window so that only one item from two different Listboxes is selected at a time?
I am attempting to write my first implementation of databinding in a WPF form.
I have got to the point where I can successfully retrieve data to populate my combobox with the required entries but am stuck on how I would go about populating a dependent ListView given the current selection of the Combobox.
To explain my problem better this is the current view backing my application.
class SchoolBookViewModel
{
public SchoolBookViewModel() { }
//Problem is here... How do I pass in the SelectedSchoolClassID?
public CollectionView ClassBookListEntries(Guid SelectedSchoolClassID)
{
return new CollectionView(SchoolQuoteList.GetSchoolClassQuoteListBySchoolClassID(SelectedSchoolClassID, 2011, "MyConnectionString"));
}
public CollectionView SchoolEntries
{
get
{
return new CollectionView(SchoolList.GetSchoolList("MyConnectionString"));
}
}
}
And this is the XAML
<StackPanel Height="449" HorizontalAlignment="Left" Margin="12,12,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="650" DataContext="{Binding}">
<Label Content="School:" Height="28" Name="lblSchoolName" Width="651" />
<ComboBox Height="23" Name="cmbSchoolNames" Width="644" DisplayMemberPath="SchoolName" ItemsSource="{Binding Path=SchoolEntries}" SelectedValuePath="SelectedSchoolClassID" SelectionChanged="cmbSchoolNames_SelectionChanged" />
<Label Content="Class booklist:" Height="29" Name="label1" Width="651" />
<ListView Height="163" Name="lblClassBookList" Width="645" ItemsSource="{Binding Path=ClassBookListEntries}" DisplayMemberPath="QuoteReference" />
</StackPanel>
And in the Window_Loaded method I call
stackPanel1.DataContext = new Views.SchoolBookViewModel();
Am I even on the right track? Any guidance would be appreciated.
To get the ComboBox's selection back into the ViewModel you need a property to bind to one of its selection properties. You can also get rid of the explicit CollectionViews if you're not doing anything with them. By just binding to the collections directly, ICollectionView instances will be created and managed for you automatically. Try structuring your VM like this:
class SchoolBookViewModel : INotifyPropertyChanged
{
private SchoolList _selectedSchoolClass;
public SchoolList SelectedSchoolClass
{
get { return _selectedSchoolClass; }
set
{
_selectedSchoolClass = value;
ClassBookListEntries = SchoolQuoteList.GetSchoolClassQuoteListBySchoolClassID(_selectedSchoolClass.Id, 2011, "MyConnectionString");
NotifyPropertyChanged("SelectedSchoolClass");
}
}
private SchoolQuoteList _classBookListEntries;
public SchoolQuoteList ClassBookListEntries
{
get { return _classBookListEntries; }
set
{
_classBookListEntries = value;
NotifyPropertyChanged("ClassBookListEntries");
}
}
private SchoolList _schoolEntries;
public SchoolList SchoolEntries
{
get
{
if (_schoolEntries == null)
_schoolEntries = SchoolList.GetSchoolList("MyConnectionString");
return _schoolEntries;
}
}
...
}
In general it's better to not set explicit Width and Height values and instead let the layout system size elements for you. You can also get rid of the DataContext="{Binding}" - this is redundant as DataContext is inherited and {Binding} means the value of the DataContext itself. Here's the XAML cleaned up and bound to the new properties from above:
<StackPanel HorizontalAlignment="Left" Margin="12,12,0,0" x:Name="stackPanel1" VerticalAlignment="Top">
<Label Content="School:" x:Name="lblSchoolName" />
<ComboBox x:Name="cmbSchoolNames" DisplayMemberPath="SchoolName" ItemsSource="{Binding Path=SchoolEntries}"
SelectedItem="{Binding SelectedSchoolClass}" />
<Label Content="Class booklist:" x:Name="label1" />
<ListView x:Name="lblClassBookList" ItemsSource="{Binding Path=ClassBookListEntries}" DisplayMemberPath="QuoteReference" />
</StackPanel>