I have a user control (WaypointInfoControl) that I wrote that has a dependency property named TheGraphic as shown here:
public Graphic TheGraphic
{
get { return (Graphic)GetValue(TheGraphicProperty); }
set { SetValue(TheGraphicProperty, value); }
}
public static readonly DependencyProperty TheGraphicProperty =
DependencyProperty.Register("TheGraphic", typeof(Graphic), typeof(WaypointInfoControl), new PropertyMetadata(default(Graphic)));
I have a viewmodel that has a Waypoints property defined like this:
private ObservableCollection<Graphic>_Waypoints = new GraphicCollection();
public ObservableCollection<Graphic> Waypoints
{
get { return _Waypoints; }
set { RaiseAndSetIfChanged(ref _Waypoints, value); }
}
In my xaml, I have a ListView that I want to populate with Waypoints:
<ListView ItemsSource="{Binding Waypoints}" >
<ListView.ItemTemplate >
<DataTemplate >
<controld:WaypointInfoControl TheGraphic="????" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
How do I bind TheGraphic to the individual item in the ListView that it represents?
Your ItemsSource is bound to a collection of Graphic objects which means that the DataContext for each item in your ListView will be a single Graphic object. Since the DependencyProperty that you are looking to bind to is looking for the Graphic object you will just want to bind to the entire DataContext, you achieve this by using the binding markup extension without specifying a path (this just causes the binding to pull in the entire DataContext which in your case is the Graphic object that you are looking for).
So this should work:
<ListView ItemsSource="{Binding Waypoints}" >
<ListView.ItemTemplate >
<DataTemplate >
<controld:WaypointInfoControl TheGraphic="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Related
I Have a listbox with DataTemplate assigned to its' ItemTemplate as below:
<ListBox Name="DayOverview">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Width="125" Background="Transparent" Orientation="Horizontal" MouseLeftButtonDown="DayOverview_MouseLeftButtonDown">
<Label Content="{Binding Owner}"/>
<Label Content="{Binding Subject}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I want to set some of its' Items Visiblity to collapse in codebehind like below:
(DayOverview.Items[i] as ListBoxItem).Visibility = Visibility.Collapsed;
but I can't convert Its' Items to ListBoxItem or any other control, Items are type of a class. Is it possible to hide Items of a ListBox with datatemplate in C#?
The DayOverview.Items collection will contain the items you bound the ItemsSource property to. It is the data not the Visual container. A ListBox will generate a ListBoxItem Container for each of your Items using ItemContainerGenerator.
You can get the visual Container from data item using ItemContainerGenerator's ContainerFromIndex method.
Try this:
DayOverview.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem).Visibility = Visibility.Collapsed;
That’s looks like a job for the CollectionViewSource.
var cvs = CollectionViewSource.GetDefaultView(listbox.Items);
cvs.Filter = item => ((ItemType) item).Name == "Bob"; // assign a Filtermethode like this
cvs.Filter = FilterMethod; // or like this
private bool FilterMethod(object obj)
{
var item = (ItemType) obj;
return item.Name == "Bob";
}
the CollectionViewSource uses a Predicate with determines if an item should be shown or not.
I am working with a ListView in WPF which is bound an observable collection. I then bound the SelectedItem-Property to a property of the ViewModel.
When I select an item in the ListView via GUI "SelectedItem" is changed.
When I change "SelectedItem" in the ViewModel, the ListView only changes, when I set the SelectedItem to NULL.
When I set any other (valid!) object (like the first entry of the ObservableCollection) the ListView just ignores it.
Furthermore: When I want to "Veto" a SelectedItem Change (because data is not saved), the ListView highlights the new selected item instead of the SelectedItem-Property of the ViewModel.
I already tried to change the Binding to Mode=TwoWay - doesn't work as well (otherwise the "NULL" change to SelectedItem wouldn't work as well)
This is the code from the view:
<ListView ItemsSource="{Binding Configurations}" SelectedItem="{Binding SelectedUserConfiguration}" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Header="User Configuration" DisplayMemberBinding="{Binding ConfigurationName}" Width="200" />
</GridView>
</ListView.View>
</ListView>
And my ViewModel:
public ObservableCollection<UserConfigurationViewModel> Configurations { get; private set; }
private UserConfigurationViewModel _selectedUserConfiguration;
public UserConfigurationViewModel SelectedUserConfiguration
{
get {
return this._selectedUserConfiguration;
}
set
{
if (this._selectedUserConfiguration != null && this._selectedUserConfiguration.WasChanged)
{
if (ask-user)
{
this._selectedUserConfiguration.Reset();
this._selectedUserConfiguration = value;
}
}
else
{
this._selectedUserConfiguration = value;
}
NotifyOfPropertyChange(() => this.SelectedUserConfiguration);
}
}
In order to select the selected item in any collection control from code, the selected item must be an actual item from the collection that is bound to the ItemsSource property. This can be achieved easily enough with LinQ if your collection items have at least one unique property:
SelectedUserConfiguration = Configurations.Where(c => c.UniqueProperty ==
valueOfItemToSelect).FirstOrDefault();
If your data type objects do not have a unique property, you can simply add an int Id property for this purpose.
I was just having the same issue with a TabControl.
I've tried to create a int property and bind it to SelectedIndex, but no success.
Strangely enough this did the trick:
In your ListView set IsSynchronizedWithCurrentItem="True"
Set a ListView.Resources like this:
<ListView.Resources>
<Style TargetType="ListViewItem" x:Key="ListViewTemplate">
<Setter Property="IsSelected" Value="True" />
</Style>
</ListView.Resources>
I am using WPF and Mvvm and my ListView has its ItemSource bound to an ICollectionView. How do I handle selected item change event?
Originally I had a DataGrid's ItemSource bind to the same ICollectionView and setup the collection's CurrentChanged event. Everything works fine, but not the case for a ListView.
All you have to do, as Thomas mentioned is to bind the SelectedItem Attribute of the listbox to a property in the viewmodel. To make it clear, here's an example.
Here's my view
<Grid x:Name="LayoutRoot" Background="White">
<ListView ItemsSource="{Binding Contacts}" SelectedItem="{Binding SelectedContact, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
And here's my ViewModel
public class MainViewModel: ViewModelBase
{
ObservableCollection<ContactViewModel> contacts;
ContactViewModel selectedContact;
public ContactViewModel SelectedContact
{
get { return selectedContact; }
set {
selectedContact = value;
base.OnPropertyChanged("SelectedContact");
}
}
public ObservableCollection<ContactViewModel> Contacts
{
get { return contacts; }
set {
contacts = value;
base.OnPropertyChanged("Contacts");
}
}
}
Everytime you try changing the selection in the listbox you'll step into the setter of the SelectedContact.
set
{
contacts = value;
base.OnPropertyChanged("Contacts");
}
Through this, you'll know that the selected contact has changed.
Using the property SelectedContact, you'll also know which of the item in your collection is selected.
You can also bind a Collection property in the ViewModel to the SelectedItems attribute of the ListView if you want to implement multiple selection.
Just bind the SelectedItem of the ListView to a property of your ViewModel
I have a WPF user control with a list box. I want to pass the selected item in the list box to the calling control through binding. How can I achieve this?
You can expose a new property for SelectedItem on your user control and bind it to the child control ListBox.
Code for your user control (I inherited from Control though):
public class CustomListControl : Control
{
static CustomListControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomListControl), new FrameworkPropertyMetadata(typeof(CustomListControl)));
SelectedItemProperty = ListBox.SelectedItemProperty.AddOwner(typeof(CustomListControl));
}
public static readonly DependencyProperty SelectedItemProperty;
public Object SelectedItem
{
get { return this.GetValue(SelectedItemProperty); }
set { this.SetValue(SelectedItemProperty, value); }
}
}
And add the binding from the inner ListBox to your UserControl in the Generic.xaml markup:
<ListBox
SelectedItem="{Binding RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type local:CustomListControl},Mode=FindAncestor},Path=SelectedItem, Mode=TwoWay}"
</ListBox>
I need to implement CheckBoxList control with ItemsSource and CheckedItems properties. Items from ItemsSource should be displayed as checked checkboxes if CheckedItems contains these values or unchecked otherwise. Also I need two-way databinding support for CheckedItems property (value of this property should be updated when user clicks on checkboxes).
Here some code which probably can help to understand my problem
XAML:
<UserControl x:Class="Namespace.Controls.CheckBoxList" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox x:Name="LayoutRoot">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
Code behind:
public partial class CheckBoxList : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(CheckBoxList), null);
public static readonly DependencyProperty CheckedItemsProperty = DependencyProperty.Register("CheckedItems", typeof(IEnumerable), typeof(CheckBoxList), null);
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public IEnumerable CheckedItems
{
get { return (IEnumerable)GetValue(CheckedItemsProperty); }
set { SetValue(CheckedItemsProperty, value); }
}
public CheckBoxList()
{
InitializeComponent();
LayoutRoot.SetBinding(ItemsControl.ItemsSourceProperty, new Binding("ItemsSource") { Source = this });
}
}
I think that I need to bind ListBox to UserControl with custom converter, which will return collection of items with additional IsChecked property, but it works only in case of one-way data binding.
Looks like I need two-way binding to two properties at one time, but I don't know how to implement it and will appreciate any help with this issue.
Thanks in advance.
First of all you should consider deriving from ListBox rather than UserControl. The ListBox already does most of what you want.
Secondly consider one way binding to an IList. You can then add and remove entires to that IList as the respective items are selected.
Rather than try to bind a CheckBox control in an Item Template you make a copy of the ListBox styles, place them in Generic.xaml as the style of your new control. Then modify the unselected and selected visual states using a checked and unchecked check box as part of the visual appearance.
Now you can attach to the SelectionChanged event and use the Event args AddedItems list to add to the bound IList and the RemovedItems list to remove items from the bound list.
You would need to clear and re-add the set of items to the list box SelectedItems list when either your CheckedItems is assigned or the ItemsSource is changed.
There are probably a number gotchas that you will need to work round but this seems like a more direct path to your goal than starting from scratch with a UserControl base.
Add an observable collection for your list box datasource to your datacontext:
private ObservableCollection<MyItem> _myItems;
public ObservableCollection<MyItem> MyItems
{
get { return _searchByFields; }
set
{
_myItems = value;
}
}
Add a class to hold the data about your checkboxes:
public class MyItem
{
public bool Checked {get; set; }
public string MyItemValue { set ; set; }
}
Then in your data template bind listbox to the collection and your data template checkboxes to the respective MyItem properties:
<UserControl x:Class="Namespace.Controls.CheckBoxList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox x:Name="LayoutRoot"
DataContext="[Dataconext here]"
ItemsSource={Binding MyItems}>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Checked, Mode=TwoWay}"
Content="{Binding MyItemValue}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
Don't forget to set the DataContext of the binding to the appropriate class (you might be doing this in the XAML or the code behind perhaps)