I have a combobox with rules in a view and it works well, but I want another field of the model from the itemsource to be used to bind to (or as I used it) update another field score.
E.g. if you select rule 1 in the combobox it should update the score field in the view with 1 and if you change the selecteditem to rule 2 it should show 2 in the score field.
My code might be a bit crippled because I experimented 'on the way here' to achieve the desired result, I have a ScoreView with a datagrid which itemsource is scores:
SelectionChangedCommand = new RelayCommand<string>((_score) => SelectedRuleChanged(_score));
private void SelectedRuleChanged(string _score)
{
int _tmpint;
_tmpint = this.SelectedScore.Model.score;
int.TryParse(_score, out _tmpint);
this.SelectedScore.Model.score = _tmpint;
//Todo weghalen lokale rules collectie en get_rules voids
//get_rules_by_ruleset(this.SelectedMatch.Model.ruleset);
}
<ComboBox
Height="23" HorizontalAlignment="Left"
Name="cmbRules" VerticalAlignment="Top" Width="100" ItemsSource="{Binding MatchVM.Rules}" SelectedValue="{Binding Model.ruleid, Mode=TwoWay}"
DisplayMemberPath="Model.name" SelectedValuePath="Model.ruleid">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding MainScore.SelectionChangedCommand, Mode=OneWay,
Source={StaticResource Locator}}" CommandParameter="{Binding Model.score}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
I try to pass the elements selecteditem (which I bound to model.score) as a command parameter..
Maybe I should use the selecteditem of MatchVMRule but the score text field is bound to the Scores ViewModel instead of the Rules ViewModel?
Thanks in advance,
Mike
UPDATE SOLVED
I finally solved it by creating two separate props rules collection and selected rule in my MainScoreViewModel.
I got rid of the eventocommand and handled the update of the score field in my Score Model based on the score of the Rule Model in the setter of the SelectedRule:
/// <summary>
/// Gets the SelectedRule property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public RuleViewModel SelectedRule
{
get
{
return _selectedRule;
}
set
{
if (_selectedRule == value)
{
return;
}
_selectedRule = value;
this.SelectedScore.Model.score = this.SelectedRule.Model.score;
RaisePropertyChanged(SelectedRulePropertyName);
}
}
<ComboBox
Height="23" HorizontalAlignment="Left"
Name="cmbRules" VerticalAlignment="Top" Width="100" ItemsSource="{Binding ScoreVM.Rules,
Mode=TwoWay}" SelectedValue="{Binding Model.ruleid, Mode=TwoWay}"
DisplayMemberPath="Model.name" SelectedValuePath="Model.ruleid" SelectedItem="{Binding
ScoreVM.SelectedRule, Mode=TwoWay}">
</ComboBox>
What about using the PropertyChange notification on your ViewModel to handle the SelectionChanged event instead of trying to handle it from the View?
public ParentViewModel()
{
this.Model.PropertyChanged += Model_PropertyChanged;
}
void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "ruleid":
this.SelectedScore.Model.Score = Model.Score;
}
}
Related
I've got a really simple UserControl I'm trying to create that contains a list of US states. I am trying to expose the selected state via a "SelectedState" property. However, I'm having trouble trying to get this binding to fire once it's hooked up in another UserControl / form.
The XAML for the user control looks like this:
<UserControl x:Class="Sample.Desktop.UserControls.StateDropdown"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Sample.Desktop.UserControls"
mc:Ignorable="d"
Width="170" Height="28"
d:DesignHeight="28" d:DesignWidth="170">
<ComboBox x:Name="cboState"
ItemsSource="{Binding StateList, RelativeSource={RelativeSource AncestorType=UserControl}}"
SelectedValue="{Binding SelectedState, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=UserControl}}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Abbreviation}"></Label>
<Label> - </Label>
<Label Content="{Binding Name}"></Label>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
In the code-behind, I have this code:
public static readonly DependencyProperty SelectedStateProperty = DependencyProperty.Register("SelectedState",
typeof(USState),
typeof(StateDropdown),
new UIPropertyMetadata(null,
new PropertyChangedCallback(OnSelectedStateChanged),
new CoerceValueCallback(OnCoerceSelectedState)));
private static object OnCoerceSelectedState(DependencyObject o, object value)
{
StateDropdown stateDropdown = o as StateDropdown;
if (stateDropdown != null)
return stateDropdown.OnCoerceSelectedState((USState)value);
else
return value;
}
private static void OnSelectedStateChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
StateDropdown stateDropdown = o as StateDropdown;
if (stateDropdown != null)
stateDropdown.OnSelectedStateChanged((USState)e.OldValue, (USState)e.NewValue);
}
protected virtual USState OnCoerceSelectedState(USState value)
{
// TODO: Keep the proposed value within the desired range.
return value;
}
protected virtual void OnSelectedStateChanged(USState oldValue, USState newValue)
{
// TODO: Add your property changed side-effects. Descendants can override as well.
}
public USState SelectedState
{
// IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
get
{
return (USState)GetValue(SelectedStateProperty);
}
set
{
SetValue(SelectedStateProperty, value);
}
}
I wasn't able to get the SelectedValue bound property of SelectedState to fire, so I ended up hooking up the SelectionChanged event.
private void cboState_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems?.Count > 0)
{
SelectedState = (USState)e.AddedItems[0];
}
}
In my other user control, I have this in the XAML:
<uc:StateDropdown Margin="10,0,0,0" SelectedState="{Binding SelectedState}" ></uc:StateDropdown>
And the ViewModel (I'm using Caliburn Micro), I have this property:
protected USState _selectedState;
public USState SelectedState
{
get { return _selectedState; }
set
{
_selectedState = value;
NotifyOfPropertyChange(() => SelectedState);
}
}
The combo is populated as expected. However, SelectedState is never fired/updated when I change the selection.
I had also previously tried using SelectedItem instead of SelectedValue, with the same results.
I'm sure I'm missing something obvious, but I'm having trouble seeing where I went wrong.
EDIT: Here's what fixed the binding.
I removed the SelectionChanged event. Then I modified my "hosting page" usercontrol to set TwoWay binding:
<uc:StateDropdown Margin="10,0,0,0" SelectedState="{Binding SelectedState, Mode=TwoWay}" ></uc:StateDropdown>
As soon as I added that, SelectedState started being updated when I changed the ComboBox value.
The only things I see, is this line :
SelectedValue="{Binding SelectedState, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=UserControl}}"
You don't need it, because of the SelectionChanged event. And it can cause the problem.
Also I would bind the SelectedState of the UserControl using a TwoWay binding.
Hope that will help you.
Below is the code
<ComboBox Name="cmbRegisteredDriveList"
Width="150" HorizontalAlignment="Center"
ItemsSource="{Binding Path=DriveList}"
SelectedItem="{Binding Path=SelectedDrive, Mode=TwoWay}"
IsEnabled="{Binding IsBusy, Converter={StaticResource NotConverter}}"
ItemContainerStyle="{StaticResource xxxx.ComboBoxItem.Style}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="tbTemplate" Width="250" Visibility="Collapsed"/>
<TextBlock TextWrapping="NoWrap"
Text="{Binding VolumeLabel, Converter={StaticResource CenterEllipsisConverter}, ConverterParameter={x:Reference tbTemplate}}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
When ever we change the Volume Label for drive we are getting notification. But Selected item in combo box is not get refreshed. Can anyone help me on this. I want to display changed Volume Label for selected item in combo box.
public ObservableCollection<DiskDrive> _driveList;
public ObservableCollection<DiskDrive> DriveList { get { return _driveList; } }
private DiskDrive _selectedDrive;
public DiskDrive SelectedDrive
{
get { return _selectedDrive; }
set { _selectedDrive = value; NotifyPropertyChanged(() => SelectedDrive); } }
Also we are notifying it whenever it is needed.
NotifyPropertyChanged(() => DriveList);
NotifyPropertyChanged(() => SelectedDrive);
In class DiskDrive, the property VolumeLabel is defined like this:
/// <summary>
/// Get the volume name of this disk. This is the friendly name ("Stick").
/// </summary>
/// <remarks>
/// When this class is used to identify a removed USB device, the Volume
/// property is set to String.Empty.
/// </remarks>
private string _volumeLabel;
public string VolumeLabel
{
get { return _volumeLabel; }
set { _volumeLabel = string.IsNullOrWhiteSpace(value) ? string.Format(LocalizationManager.Instance["XXXX"], SerialNumber) : value; }
}
DiskDrive must implement INotifyPropertyChanged and VolumeLabel must raise the PropertyChanged event when changed. Otherwise the binding will not be updated.
Also, please notice that you will most probably leak memory when binding to a property of a class which does not implement INotifyPropertyChanged. See here.
Have a WPFDatagrid binded to combobox using Datagridtemplatecolumn. Finding difficult to get the selectedItem of the combobox binding. Have found similar examples around but that's not resolving my problem.
Please find the code snippet of my XAML and the data structure below:
public class X
{
public X ()
{
abc = new ObservableCollection<P>();
}
public ObservableCollection<P> Y
{
get { return abc; }
set { abc = value; PropertyChanged("Y"); }
}
}
public class P
{
private string id;
private string name;
public string ID
{
get
{
return id;
}
set
{
id = value;
InvokePropertyChanged("ID");
}
}
public string Name
{
get
{
return name;
}
set
{
name = value;
InvokePropertyChanged("Name");
}
}
}
I have a datastructure defined above that implements the INotifyPropertychanged interface.
<controls:DataGrid Name="datagrid" AutoGenerateColumns="False" ItemsSource="{Binding XList}" Grid.Row="0"
SelectedItem="{Binding SelectedX, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<controls:DataGrid.Columns>
<controls:DataGridTemplateColumn Header="Yl">
<controls:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Y}"
IsSynchronizedWithCurrentItem="False" DisplayMemberPath="Name"
SelectedValue="{Binding Path=SelectedY, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnTargetUpdated=True}"
SelectedValuePath="SelectedY"
SelectedItem="{Binding SelectedY, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</controls:DataGridTemplateColumn.CellTemplate>
</controls:DataGridTemplateColumn>
</controls:DataGrid.Columns>
</controls:DataGrid>
Now, in view model, have a observablecollection of List of X i.e., XList and that is binded to the datagrid in the XAML. and have Y within each row of the datagrid binded to the Combobox. Have a property as SelectedY, binded to the SelectedItem of the combobox.
Have also a property as SelectedX binded to the selectedItem of the datagrid, which works fine.
Issue is not able to get the Selected Item binding of the Combobox. Not able to set the selected item for the combobox when the selection has changed.
Can anybody help me out to set the selecteditem binding of the combo box?
Where is set your datacontext ?
You can do something like that :
<controls:UserControl x:Name=MainControl>
<controls:UserControl.DataContext>
<classpath:X/>
</controls:UserControl.DataContext>
<controls:DataGrid ItemsSource={Binding YourItemsContainer}>
<controls:DataGrid.Columns>
<controls:DataGridComboBoxColumn ItemsSource={Binding ElementName=MainControl,Path=DataContext.Y}
SelectedItem={Binding ElementName=MainControl,Path=DataContext.SelectedY}
DisplayMemberPath=Name />
</controls:DataGrid.Columns>
</controls:DataGrid>
</controls:UserControl>
The idea is to set a name to the root element connected to your datacontext, then you can access to it's datacontext property easily by the path. When you are inside of a template, the datacontext is the ItemsSource objects.
Hope it will help you a little !
Below is the XAML snippet for my combo-box in a datagrid.
<data:DataGridTemplateColumn Header="Entry Mode">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=EntryModeCombo,Mode=TwoWay}" DisplayMemberPath="Name" SelectedValuePath="Id" SelectedValue="{Binding Path=selectedEntryMode,Mode=TwoWay}" ></ComboBox>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
Entrymode is an entity in the system and the Id and Name properties of this entity are used to set the DisplayMemberPath and SelectedValuePath of the combo.
public class A
{
private ObservableCollection<EntryMode> _EntryModeCombo;
public ObservableCollection<EntryMode> EntryModeCombo
{
get { return _EntryModeCombo; }
set
{
_EntryModeCombo = value;
RaisePropertyChanged("EntryModeCombo");
}
}
private string _selectedEntryMode;
public string selectedEntryMode
{
get { return _selectedEntryMode; }
set
{
_selectedEntryMode = value;
RaisePropertyChanged("selectedEntryMode");
}
}
}
In my viewModel, I am making an observable collection of the class A, and using that to bind a grid. All works well in the ADD mode, but in the edit mode, when I try to set the selected value of the combobox in the grid, it does not work. The population of the combo-box happens, but it remains unselected. Not sure why the selectedEntryMode property is getting set, but not affecting the combo selection in the grid.
Any suggestions will be appreciated.Thanks.
SelectedValue can only be used for getting value. not setting. use SelectedItem insted
I have on checkbox inside telerik combo control. If User click on "All" option from checkbox list then I want select all checkboxs.
checkbox values.
My Sample code is below.
<telerik:RadComboBox Name="rcbDays" Grid.Row="1" Grid.Column="1" Width="200" HorizontalAlignment="Left" ItemsSource="{Binding MonthDaysList}" VerticalAlignment="Center" >
<telerik:RadComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="chkDays" Content="{Binding DaysText}"
Tag="{Binding DaysValue}" Checked="chkDays_Checked" />
</StackPanel>
</DataTemplate>
</telerik:RadComboBox.ItemTemplate>
</telerik:RadComboBox>
private void chkWeeks_Checked(object sender, RoutedEventArgs e)
{
//Here I want code for selecting all checkboxes.
}
The items that you bound the ComboBox to should have a property like IsSelected, then you should bind IsChecked of the data-template CheckBox to that. Then you just need to iterate over the source collection and set IsSelected=true on all items.
e.g.
public class MyClass : MyBaseClass // Whatever you may have called it,
{
public bool IsSelected { ... }
public string DaysText { ... }
//...
}
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" Content="{Binding DaysText}" Tag="{Binding DaysValue}" />
</StackPanel>
</DataTemplate>
//In the handler that is supposed to select all
foreach (var item in MonthDaysList) item.IsSelected = true;
Of course the property needs to have change notifications.
(Also a note on usability: I do not thing that ComboBoxes should contain CheckBoxes, if you need multiple item selection use a ListBox)
You need to take one more property isSelected as said by H.B.
add IsChecked="{Binding IsSelected}" to CheckBox tag in xaml file. Create one property in the appropriate class i.e. public bool isSeleted.......
When you get in to event chkWeeks_Checked() in this function get reference of the ComboBox item source like objList = (TypeCastYourClassType)YourComboBox.ItemSource;... Now the objList contains all checkbox items. Iterate through objList collection and get isSeleted property for each and every single item and that's done....
In your case
MonthDayList = (TypeCastYourClassType)rcbDays.ItemSource;
for(int i=0;i<MonthDayList.Count;i++)
{
MonthDayList[i].isSelected = true;
}
Here is some good discussion for allowing multiple values to be selected in the telerik combobox.
It uses checkbox within combobox
http://codedotnets.blogspot.in/2012/02/checkboxes-in-comboxes-to-allow.html
Thanks :)