I've been searching for a while and haven't been able to find a solution.
My goal is to bind a property in my ViewModel to the selected item of a listbox in my custom control.
First off - This calendar control has been sourced from Jarloo Custom Calendar. I have merely been modifying it for custom personal use.
The calendar control (abbreviated) is as below:
<ResourceDictionary>
<Style TargetType="{x:Type Neptune:Calendar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Neptune:Calendar}">
<!--Some header items and other misc controls....-->
<DockPanel>
<!--Calendar-->
<ListBox ItemsSource="{Binding Days}" Background="{x:Null}"
SelectedItem="{Binding SelectedDay, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And the local (abbreviated):
public class Calendar : Control
{
public ObservableCollection<Day> Days { get; set; }
//SelectedDay Property
public static readonly DependencyProperty SelectedDayProperty =
DependencyProperty.Register("SelectedDay", typeof(Day), typeof(Calendar),
new PropertyMetadata(null, OnSelectedDayChanged));
public Day SelectedDay
{
get { return (Day)GetValue(SelectedDayProperty); }
set { SetValue(SelectedDayProperty, value); }
}
private static void OnSelectedDayChanged(DependencyObject pager, DependencyPropertyChangedEventArgs e)
{
Calendar d = pager as Calendar;
//MessageBox.Show(d.SelectedDaDateString());///THIS SHOWS CORRECT SELECTED DATE!!!!
d.SetValue(ThisDayProperty, d.SelectedDay);
}
In the window that utilizes this control, I have tried binding to this SelectedDay Property and even made another DP to pass the value to just for testing. Neither values are binding correctly.
<Neptune:Calendar Grid.Row="1" x:Name="Calendar" Margin="0,10,0,0"
ThisDay="{Binding DaySelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
I don't understand... Why is this not working?
All I want to do is expose a property that reflects the selected item in the calendar list of Days.
I posted the question on the Microsoft forums and received the correct answer from Magnus.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/d0d8362e-8341-410c-8364-557c5b4345d0/binding-to-nested-listbox-selecteditem-in-custom-control?forum=wpf
Related
I have a DataGrid that is bound to an ICollectionView "Employees" in my ViewModel, which I want to filter for each column.
Here's what the XAML looks like:
<DataGrid ItemsSource="{Binding Employees}"
attachedBehaviors:DataGridColumnsBehavior.BindableColumns="{Binding EmployeeColumns}">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding}" Grid.Column="0"/>
<Button Content="v" Grid.Column="1" Click="ButtonClick"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
</DataGrid>
This works fine and when calling ButtonClick I could pass the data context along to my ViewModel and search for this string. However, what I would prefer is to bind the button to an event in my ViewModel, so I can get a reference to the column from which this event originated and appropriately handle my data there.
My ViewModel looks like this:
class ViewModel : ChangeNotifier
{
public ICollectionView Employees { get; private set; }
public ViewModel()
{
var _employees = new List<Employee>{...
Employees = CollectionViewSource.GetDefaultView(_employees);
EmployeeColumns = new ObservableCollection<DataGridColumn>();
EmployeeColumns.Add(new DataGridTextColumn { Header = "First Name", Binding = new Binding("FirstName") });
EmployeeColumns.Add(new DataGridTextColumn { Header = "Last Name", Binding = new Binding("LastName") });
FilterMenu = new RelayCommand(new Action<object>(FilterContextMenu));
}
private ICommand filtermenu;
public ICommand FilterMenu
{
get
{
return filtermenu;
}
set
{
filtermenu = value;
}
}
public static void FilterContextMenu(object obj)
{
MessageBox.Show("Event Fired!");
}
public ObservableCollection<DataGridColumn> EmployeeColumns { get; private set; }
}
So my question is: How do I bind to the FilterContextMenu event?
I've tried:
<Button Content="v" Grid.Column="1" Command="{Binding FilterMenu}"/>
And also:
<Button Content="v" Grid.Column="1" Command="{Binding FilterMenu, RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"/>
None of which triggered the event.
Edit: I probably should add that the greater goal is to create a button that, when clicked, creates a dynamically populated context menu. I may be on the completely wrong track here.
I don't follow your description of the greater goal and dynamically populated context menu.
That sounds like it will have it's own set of somewhat more challenging problems getting a reference to any datacontext in the window. A contextmenu usually relies on placement target to get anything contextual because it isn't part of the window.
If you intend passing commands through from that then this could well get quite complicated.
But... that's a different question entirely.
Binding a button to the command which is in the datacontext of the datagrid.
My datagrid is called dg ( I'm a minimalist at heart ).
I got a bit wordy with my command and it's called ColHeaderCommand.
This works for me:
<DataGridTextColumn.Header>
<Button Content="Title" Command="{Binding DataContext.ColHeaderCommand, ElementName=dg}"/>
</DataGridTextColumn.Header>
My viewmodel is the datacontext of the window, which is inherited down to the datagrid.
You will want some sort of a parameter for that command to pass in what column or whatever you're doing whatever with.
I'm developing an App for Windows Phone 8.1. In that App I want to bind the Items of an ObservableCollection<DisruptionDisplayElement> to a ListView. DisruptionDisplayElement has a property named bool IsFavorite. In the ListView I want to hide all items, where IsFavorite is false.
If I do it by using ItemContainerStyle and set the Visibility-Property to collapsed by using a Converter, it is not working. If I define the Backgroundcolor the same way for testing, it works.
I can also hide the Grid, where everything of the ListViewItem is in, but in that case I still have the the decoration of the ListViewItem, that takes round about 50 pixels of space.
Here is what I've got:
XAML:
<Page
x:Class="myApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:myApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converter="using:myApp.Converter"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
>
<Page.Resources>
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConv"/>
</Page.Resources>
<Grid>
<Hub Header="{Binding CityName}"
SectionsInViewChanged="Hub_SectionsInViewChanged"
Grid.Row="1"
>
<HubSection Header="My Lines" Name="hubFavorites">
<DataTemplate>
<Grid Margin="0,-25,0,0">
<ListView
ItemsSource="{Binding DisruptionDisplayList}"
Grid.Row="1"
>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<!-- This seems not to work -->
<Setter Property="Visibility" Value="{Binding IsFavorite, Converter={StaticResource BoolToVisibilityConv}}"/>
<!-- For testing -->
<Setter Property="Background" Value="Aqua"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<!-- The Visibility-Property is just for testing as described -->
<Grid
Margin="0,0,0,10"
Visibility="{Binding IsFavorite, Converter={StaticResource BoolToVisibilityConv}}"
>
<!-- Content here -->
<TextBlock Text="{Binding Message}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</HubSection>
</Hub>
</Grid>
</Page>
The Converter:
namespace myApp.Converter
{
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string culture)
{
return (bool) value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string culture)
{
throw new NotImplementedException();
}
}
}
DisruptionDisplayElement:
public class DisruptionDisplayElement
{
public string Message { get; set; }
public bool IsFavorite { get; set; }
}
Code Behind:
namespace myApp
{
public sealed partial class MainPage
{
public MainPage()
{
InitializeComponent();
DataContext = new ViewModel;
}
}
}
My "ViewModel"-Class:
namespace myApp
{
public class ViewModel
{
public ObserverableCollection<DisruptionDisplayElement> DisruptionDisplayList {get;set;}
public ViewModel()
{
DisruptionDisplayList = new ObservableCollection<DisruptionDisplayElement>();
DisruptionDisplayList.Add(new DisruptionDisplayElement() { IsFavorite = true, Message = "Message 1"});
DisruptionDisplayList.Add(new DisruptionDisplayElement() { IsFavorite = false, Message = "Message 2" });
DisruptionDisplayList.Add(new DisruptionDisplayElement() { IsFavorite = true, Message = "Message 3" });
}
}
}
What can I do to hide the ListViewItem without wasting all the space for emtpy ListViewItems if I hide the grid inside?
Edit:
Advanced the Code providing
Without a good, minimal, complete code example, it's not possible to provide an actual code example that shows the correct technique in your exact scenario.
However, the basic answer is that you should be using ICollectionView to filter the visual presentation based on some property.
There are a variety of ways to go about doing this. One of the simplest is to apply the filtering to the default view for your data source. Such a view always exists, and if you are only binding your data source to a single visual object, or you want all visual objects that present that data source to be filtered in the same way, then getting and modifying this view is the correct approach.
As an example:
ICollectionView view = CollectionViewSource.GetDefaultView(DisruptionDisplayList);
view.Filter = item => ((MyClass)item).IsFavorite;
You would configure this view in your code-behind at the appropriate time, e.g. when the user indicates through whatever input mechanism you've provided that they want to show only the favorite items.
Note that this approach avoids altogether trying to use the DataTemplate as the mechanism for showing or hiding the items. Instead, the items are filtered before they ever reach the ListView object.
if you are looking for UWP, just set MinHeight Property to 0 (zero):
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="MinHeight" Value="0" />
</Style>
</ListView.ItemContainerStyle>
I've got some troubles with a custom control I need to create. I try to explain you my needs first
I need to have a combobox that permits to check more than one item at time (with checkbox) but I want it to be smart enought to bind to a specific type.
I've found some MultiSelectionComboBox but none reflects my need.
Btw my main problem is that I wish to have a generic class as
public class BaseClass<T> : BaseClass
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable<T>), typeof(BaseClass<T>), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(BaseClass<T>.OnItemsSourceChanged)));
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
int i = 0;
//MultiSelectComboBox control = (MultiSelectComboBox)d;
//control.DisplayInControl();
}
public IEnumerable<T> ItemsSource
{
get { return (IEnumerable<T>)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
}
}
}
public class BaseClass : Control
{
}
and a more context specific item for example
public class MultiCurr : BaseClass<Currency>
{
static MultiCurr()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiCurr), new FrameworkPropertyMetadata(typeof(MultiCurr)));
}
}
In my App.xaml I've defined a resource as
<ResourceDictionary>
<Style TargetType="local:MultiCurr">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MultiCurr">
<ComboBox Width="120" Background="Red" Height="30" ItemsSource="{Binding ItemsSource}" DisplayMemberPath="Description" ></ComboBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
In my MainWindow I've created an object as
<Grid>
<local:MultiCurr x:Name="test" ItemsSource="{Binding Currencies}"></local:MultiCurr>
</Grid>
and the MainWindow.cs is defined as
public partial class MainWindow : Window, INotifyPropertyChanged
{
private IList currencies;
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var lst = new List<Currency>();
for (int i = 0; i < 10; i++)
{
var curr = new Currency
{
ID = i,
Description = string.Format("Currency_{0}", i)
};
lst.Add(curr);
}
Currencies = lst;
}
public IList<Currency> Currencies
{
get
{
return this.currencies;
}
set
{
this.currencies = value;
NotifyPropertyChanged("Currencies");
}
}
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And here's the result ...
I was wondering what am I doing wrong? is it possible what am I tring to achieve?
Thanks
UPDATE #1:
I've seen that the main problem is the datacontext of the custom usercontrol
<Application.Resources>
<ResourceDictionary>
<Style TargetType="local:MultiCurr">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MultiCurr">
<ComboBox Width="120" Background="Red" Height="30" ItemsSource="{Binding **Currencies**}" DisplayMemberPath="{Binding **DisplayMemeberPath**}" ></ComboBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
If I put ItemsSource as Currency (which is a property of the MainWindow) it shows.
If I put ItemsSource and DisplayMemberPath (which are defined in the BaseClass no.. how can I set the context of the usercontrol to itself?)
UPDATE #2
I've added a GoogleDrive link to the project here if anyone wants to try the solution
Thanks
Combobox is not suitable control for multiselection, because it has given behaviour, that when yo select item, Combobox closes itself. That's why Combobox doest not have SelectionMode property like ListBox. I think that ListBox inside expander is what you need.
Generic Types are not a way to go. WPF handles this different, better way. Take listbox as an example. If you bind listbox.itemssource to generic observable collection, and you try to define e.g ItemTemplate, you get full intellisense when writing bindings and warning if you bind to not existing property. http://visualstudiomagazine.com/articles/2014/03/01/~/media/ECG/visualstudiomagazine/Images/2014/03/Figure8.ashx WPF designer automatically recognizes type parameter of your observable collection. Of cousre you need to specify type of datacontext in your page by using something like this: d:DataContext="{d:DesignInstance search:AdvancedSearchPageViewModel}". However your control dont have to be and shouldn't be aware of type of items.
Following example demonstrates control that meets your requirements:
<Expander>
<Expander.Header>
<ItemsControl ItemsSource="{Binding ElementName=PART_ListBox, Path=SelectedItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Mode=OneWay}" />
<Run Text=";" />
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Expander.Header>
<Expander.Content>
<ListBox x:Name="PART_ListBox" SelectionMode="Multiple">
<ListBox.ItemsSource>
<x:Array Type="system:String">
<system:String>ABC</system:String>
<system:String>DEF</system:String>
<system:String>GHI</system:String>
<system:String>JKL</system:String>
</x:Array>
</ListBox.ItemsSource>
</ListBox>
</Expander.Content>
</Expander>
I reccomend you to create control derived from ListBox (not usercontrol).
I have hardcoded datatemplates, but you should expose them in your custom dependency properties and use TemplateBinding in you control template. Of course you need to modify expander so it looks like combobox and ListBoxItem style so it looks like CheckBox, but it is ease.
I have ContentPresenter with DataTemplateSelector:
...
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var model = item as ItemControlViewModel;
if (model.CurrentStatus == PrerequisitesStatus.Required)
{
return RequiredTemplate;
}
if (model.CurrentStatus == PrerequisitesStatus.Completed)
{
return FinishedTemplate;
}
...
return InProgressTemplate;
}
When CurrentStatus is changed, OnPropertyChanged is called.
I need somehow to trigger this DataTemplateSelector when the property is changed and change ContentPresenter DataTemplate. Any suggestions?
Threre are similar questions:
1
2, but I don't want to use any DataTriggers, because of too much states.
Tried to play with DataTriggers
<ContentPresenter
Grid.Column="1"
Height="16"
Width="16"
Margin="3">
<ContentPresenter.Triggers>
<DataTrigger Binding="{Binding Path=CurrentStatus}" Value="0">
<Setter Property="ContentPresenter.ContentTemplate" Value="{StaticResource ResourceKey=_requiredStatusTemplate}" />
</DataTrigger>
</ContentPresenter.Triggers>
</ContentPresenter>
But got an error:
Triggers collection members must be of type EventTrigger :(
As you requested an example with datatriggers in the comments, here you are:
A FrameworkElement can only have EventTriggers, therefore you get the error Message Triggers collection members must be of type EventTrigger
And also don't use a ContentPresenter directly, it is meant to be used inside a ControlTemplate. Better use a ContentControl when you want to have dynamic content.
See What's the difference between ContentControl and ContentPresenter?
And finally here's a suggestion to your DataTrigger issue. I have put it inside a style for reusability ....
XAML :
<Window x:Class="WpfApplication88.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="requiredTemplate">
<TextBlock Text="requiredTemplate"></TextBlock>
<!--your stuff here-->
</DataTemplate>
<DataTemplate x:Key="completedTemplate">
<TextBlock Text="CompletedTemplate"></TextBlock>
<!--your stuff here-->
</DataTemplate>
<Style x:Key="selectableContentStyle" TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CurrentStatus}" Value="Required">
<Setter Property="ContentTemplate" Value="{StaticResource requiredTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CurrentStatus}" Value="Completed">
<Setter Property="ContentTemplate" Value="{StaticResource completedTemplate}" />
</DataTrigger>
<!-- your other Status' here -->
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ContentControl Width="100" Height="100" Style="{StaticResource selectableContentStyle}"/>
</Grid>
</Window>
I could be wrong, but I believe the DataTemplateSelector is only used when the ItemContainerGenerator creates a container for an item added to the collection. Because a new container isn't generated when a property value changes, a new DataTemplate is never going to be applied via the selector.
As suggested in the comments, I would recommend you look at the VisualStateManager or data triggers, otherwise you're going to have to recreate the container for every item when one or more properties change value.
Just as an extra choice - if you want to stick to your templates, just use s binding with converter.
I came up with a behavior that would theoretically do this.
C#:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
public class UpdateTemplateBehavior : Behavior<ContentPresenter>
{
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(object), typeof(UpdateTemplateBehavior), new FrameworkPropertyMetadata(null, OnContentChanged));
public object Content
{
get => GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
static void OnContentChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (sender is UpdateTemplateBehavior behavior)
behavior.Update();
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(object), typeof(UpdateTemplateBehavior), new FrameworkPropertyMetadata(null, OnValueChanged));
public object Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (sender is UpdateTemplateBehavior behavior)
behavior.Update();
}
public UpdateTemplateBehavior() : base() { }
protected override void OnAttached()
{
base.OnAttached();
Update();
}
void Update()
{
if (Content != null)
{
BindingOperations.ClearBinding(AssociatedObject, ContentPresenter.ContentProperty);
AssociatedObject.Content = null;
BindingOperations.SetBinding(AssociatedObject, ContentPresenter.ContentProperty, new Binding() { Path = nameof(Content), Source = this });
}
}
}
XAML:
<ContentPresenter ContentTemplateSelector="{StaticResource MySelector}">
<i:Interaction.Behaviors>
<Behavior:UpdateTemplateBehavior Content="{Binding SomeContent}"
Value="{Binding SomeValue}"/>
</i:Interaction.Behaviors>
</ContentPresenter>
The content is "updated" (by clearing and then resetting the binding) when the content (in this example, "SomeContent") and an arbitrary value (in this example, "SomeValue") is changed, as well as when the behavior is first attached.
An update is not made unless the content is not null (my project-specific requirement). Not updating upon attaching may avoid unintentionally updating twice at once, but if the value is initially null, an update wouldn't occur until the value changes at least once.
Note: In the above example, I am not sure if the behavior has the same data context as the ContentPresenter. I use a helper class that I did not include here for brevity. Keep that in mind when testing...
I have a really weird issue with Combobox in WPF. I have used it before in a simpler implementation and thought I knew how it works, but apparently not. The scenario is as follows... I have three classes which are in a parent/child relationship, I have a list of a type AnswerViewModel which I populate in a Combobox. I want the IsSelected property on the class to be the value that is get/set in the Combobox. Below is some of the code, hopefully enough to see what I am referring to.
These are the models.
public class Quiz
{
public string QuizName {get;set;}
public List<Question> Questions {get;set;}
}
public class Question
{
public int QuestionId {get;set;}
public string QuestionText {get;set;}
public List<Answer> {get;set;}
}
public class Answer
{
public int AnswerId {get;set;}
public string AnswerText {get;set;}
public bool IsSelected {get;set;}
}
These are the ViewModels
QuizViewModel.cs
// This will create QuestionViewModel for each question.
ObservableCollection<QuestionViewModel> Questions {get;set;}
QuestionViewModel.cs
// This will create AnswerViewModel for each answer
ObservableCollection<AnswerViewModel> Answers {get;set;}
AnswerViewModel.cs
Answer answer;
// ctor
public AnswerViewModel(Answer answer...)
{
this.answer = answer;
...
}
public string AnswerText
{
get { return answer.AnswerText; }
set
{
answer.AnswerText = value;
NotifyPropertyChanged("AnswerText");
}
}
public bool IsSelected
{
get { return _answer.IsSelected; }
set
{
answer.IsSelected = value;
NotifyPropertyChanged("IsSelected"); // <--- Breakpoint
}
}
These are the XAMLs
Quiz.xaml
<ItemsControl ItemsSource="{Binding Questions}" />
Question.xaml
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding Path=IsSelected}"
SelectedValuePath="IsSelected"/>
The Combobox is populated correctly (It is bound to the Collection of AnswerViewModel), but when I make a selection what I expect is to see at the breakpoint is two events. One for the false on the item no longer selected, and true for the new item selected. But instead it never gets hit.
So I scour the web looking for help and found some interesting information and tried a number of things but, so far nothing seems to be complete. For example:
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding Path=IsSelected}"
SelectedValuePath="IsSelected">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ComboBox.ItemContainerStyle>
</Combobox>
But this only selects the correct item in the Combobox when drop-down. Which I understand is correct for this markup.
So, in short, I would like to have the IsSelected Property on the AnswerViewModel updated when I select an item in the Combobox. Any help would be greatly appreciated.
If more information is required just let me know.
Thank you,
Obscured
** Update **
Ok, I think I actually resolved it, but still If anyone has suggestions, or thoughts on this, I would still like to hear them.
Here is what I did, I only changed the Combobox xaml as follows:
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding Path=ItemsSource/, RelativeSource={RelativeSource Self}}">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ComboBox.ItemContainerStyle>
</Combobox>
Basically this sets the selectedvalue to the current item, and since the itemcontainerstyle handles the case when drop-down it binds the IsSelected property of the combobox to the IsSelected property of my ViewModel. And this appears to do the trick.
Just remove the SelectedValue and SelectedValuePath properties, it's not how they work. SelectedValuePath indicates which property of the selected item will be the SelectedValue of the ComboBox; if you say that the SelectedValuePath is "IsSelected", the SelectedValue will be SelectedItem.IsSelected, which is clearly not what you want... And your binding for SelectedValue refers to a property that doesn't exist (QuestionViewModel.IsSelected)
This should work for you:
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ComboBox.ItemContainerStyle>
</Combobox>
have you try:
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding IsSelected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="IsSelected"/>