WPF ComboBox will not trigger an event on initializing - c#

I have the following situation:
1. I have Window Load event - which gets the SourceItems for a ComboBox
2. ComboBox have EventTrigger for Selection Changed and the following XAML:
<ComboBox x:Name="uxEnvironmentsComboBox"
ItemsSource="{Binding Environments}" Width="90" Margin="0,10,160,0"
HorizontalAlignment="Right"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
IsSynchronizedWithCurrentItem="True" SelectedIndex="0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectEnvironment}"
CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ComboBox}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
Everything works, the Window Load properly, the List is populated in the ComboBox, but when the default selection is made my <i:EventTrigger EventName="SelectionChanged"> does not trigger and the rest of the application configuration is not triggered unless I make a manual selection change ?!

SelectEnvironment should be a property that you bind to:
<ComboBox x:Name="uxEnvironmentsComboBox"
ItemsSource="{Binding Environments}" Width="90" Margin="0,10,160,0"
SelectedItem="{Binding SelectEnvironment}"
HorizontalAlignment="Right"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
IsSynchronizedWithCurrentItem="True" SelectedIndex="0">
</ComboBox>
You can invoke any command in the setter of this property if you want to:
private Environment _selectEnvironment;
public Environment SelectEnvironment
{
get { return _selectEnvironment; }
set
{
_selectEnvironment = value;
//invoke command
YourCommand.Execute(_selectedEnvironment);
}
}
And if you want to invoke the command or set the property initially, you could for example do this in the constructor of the view model. You don't need to use an InvokeCommandAction.

Related

Bind same command to datagrid double click

I have a menu item that is configured to execute a command using binding:
<MenuItem Margin="2"
Header="Process something"
Command="{Binding SomethingCommand}"
IsEnabled="{Binding SomethingIsEnabled}">
</MenuItem>
It also configure if this item is enabled or not.
Now, I need to execute the same command when user double click a row in datagrid and only when "SomethingisEnabled" is true.
How to configure datagrid to do that?
setup xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" in xaml
<DataGrid x:Name="dataGrid" ItemsSource="{Binding DataList}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding SomethingCommand}" CommandParameter="{Binding ElementName=dataGrid, Path=SelectedItem}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
This will call a relaycommand SomethingCommand and pass the selected item (if any, otherwise null) on the doubleclicked grid.

Passing objects in ItemsControl using a DataTemplate

So basically I have a class Step.
public class Step : INotifyPropertyChanged
{
public int Index { get; set; }
public int Time { get; set; }
}
In my xaml, I want to represent Steps using one DataTemplate and an ItemsControl. My DataTemplate looks like this:
<DataTemplate x:Key="StepTemplate" DataType="data:Step">
<Label Content="{Binding Index}"/>
<Label Content="{Binding Time}"/>
</DataTemplate>
And my ItemsControl looks like this.
<ItemsControl Name="ListSteps" ItemsSource="{Binding Steps}" Grid.IsSharedSizeScope="True" ItemTemplate="{StaticResource StepTemplate}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding Path=DataContext.StepClick, ElementName=ListSteps}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ItemsControl>
So pretty much what should happen: Whenever I click on a Step, the method StepClick gets called and the Step object that I clicked on is passed as a parameter.
What is actually happening: Whenever I click on a Step, the method StepClick gets called, but not the Step Object gets passed as a parameter but an object of my view gets passed. Which is not at all what I want.
How can I pass an object of Step whenever I click on a Step?
Move the interaction trigger to the root element of the ItemTemplate:
<DataTemplate x:Key="StepTemplate" DataType="data:Step">
<StackPanel Background="Transparent">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding Path=DataContext.StepClick, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Label Content="{Binding Index}"/>
<Label Content="{Binding Time}"/>
</StackPanel>
</DataTemplate>

Binding cascading combobox itemsource in wpf datagrid using mvvm

How to bind a 2nd dropdown based on first dropdown selected value of first dropdown using mvvm
Here is the class strcture
List<Location> Locations; //Application global cached data
List<Room> Room; //Application global cached data
class Location {LocationId, Name ....}
class Room{RoomId, Name, LocationId...}
XAML
<DataGridTemplateColumn Header="Property Name">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="LocationsComboBox"
ItemsSource="{Binding Path=DataContext.Locations, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
DisplayMemberPath="Name" SelectedValuePath="Id"
SelectedValue="{Binding PropertyId, UpdateSourceTrigger=PropertyChanged}">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<!--Room Number-->
<DataGridTemplateColumn Header="Room Number">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="RoomComboBox"
ItemsSource="{Binding Path=DataContext.Rooms, RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
DisplayMemberPath="RoomName" SelectedValuePath="RoomId"
SelectedValue="{Binding NewRoomId, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction
Command="{Binding DataContext.PropertyChangedCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
Did you use INotifypropertychanged ? you should implement INotifyPropertyChanged and change your child list when parent was changed
Use ObservableCollection<Room> instead of List (this will cause the second combobox to update when the first combo box changes the location which in turn causes the room collection to change.
Use ObservableCollection<Location> also. Your locations might not ever change, but this is simply good MVVM form.
I prefer Master Slave/Details way of combo box.
U can find Here
But in your Case
The binding for Room ComboBox should be from Code Behind on the basis of selected LocationID.
the below binding
ItemsSource="{Binding Path=DataContext.Rooms..
should be something like this
ItemsSource="{Binding Path=DataContext.RoomsInSelectedLocation
and in ViewModel
IEnumerable<Room> RoomsInSelectedLocation
{
return Rooms.where(r => r.LocationId == SelectedLocationId);
}
evaluate this every time the Location Combo selected item changes.

Listbox selection hides other mouse event

Hello Stackoverflowers,
I have a System.Windows.Control.ListBox. It's doing a great job but i would like to had a few behaviours when i select certain types of items.
I can't do it in the bind property for SelectedItem because my Listbox's View Model (Foo) doesn't know all the needed datas for the work i want (some coming from another ViewModel : Bar).
My two mentioned ViewModel are field of a bigger class Zot, in order for Zot to access the content of both Foo and Bar
I foward click event in Foo and Bar to Zot using Interaction.Triggers, EventTrigger and InvokeCommandAction. It's working great for Bar (which is a canvas). However i have trouble with the Listbox.
After testing events SelectionChanged, MouseDown and Click, it appears that MouseDown is triggered if I click on the grid wrapping the listbox but not when i click on the ListBox. It feels like the embedded selection in the Listbox is conflicting with other events.
Anyone got any idea to do specific actions depending on the selected item, in a different viewmodel ?
Thanks a lot
EDIT :
Here is the XAML for the Listbox (in ToolboxView.xaml)
d:DataContext="{d:DesignInstance viewModels:ToolboxViewModel}">
<Grid>
<ListBox
ItemsSource="{Binding Tools}"
SelectedItem="{Binding SelectedTool}"
x:Name="ToolView" >
<ListBox.ItemTemplate>
<DataTemplate DataType="interfaces:IBuilder">
<TextBlock
FontWeight="DemiBold"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Here is the event on the Listbox, from the main window xaml (which view model holds the listbox view model, i explain why below). However the event is never triggered. Later in the same file, 3 similar event works perfectly (on a canvas). I tried to use MouseDown instead of SelectionChanged, it is triggered when i click in the grid containing the listbox but isn't trigger when i click listbox.
(in MainWindow.xaml)
<DockPanel>
<views:ToolboxView DockPanel.Dock="Left"
Width="120"
IsHitTestVisible="True"
DataContext="{Binding ToolBoxViewModel}"
x:Name="ToolboxView">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding Path=DataContext.SelectionChangedCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding ElementName=ToolboxOverlayView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Now what i called "embeded selection" is the behaviour of the Listbox where i can highlight an element inside the listbox and select it. This works perfectly with the code above (i can select my tools, the property binded in ViewModel change accordingly). What i'm trying to do is firing the SelectionChanged event to do special work when a certain category of elements inside the listbox are selected.
I could do this in the setter of the property binded to Listbox's ItemSelected but the work to do need datas unknown from the listbox view model, which is why i have a mainwindow view model that holds the view model of the listbox and i try to get the SelectionChanged event in the main window view model (and another view model).
Tell me if it's not clear please.
You're trying to set a SelectionChanged event in your ToolboxView that does not know any SelectionChanged event.
You could create two DP in ToolboxView that stores the command and its parameter:
#region SelectionChangedCommand
public ICommand SelectionChangedCommand
{
get { return (ICommand)GetValue(SelectionChangedCommandProperty); }
set { SetValue(SelectionChangedCommandProperty, value); }
}
private readonly static FrameworkPropertyMetadata SelectionChangedCommandMetadata = new FrameworkPropertyMetadata {
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
public static readonly DependencyProperty SelectionChangedCommandProperty =
DependencyProperty.Register("SelectionChangedCommand", typeof(ICommand), typeof(ToolboxView), SelectionChangedCommandMetadata);
#endregion
#region SelectionChangedCommandParameter
public Object SelectionChangedCommandParameter
{
get { return (Object)GetValue(SelectionChangedCommandParameterProperty); }
set { SetValue(SelectionChangedCommandParameterProperty, value); }
}
private readonly static FrameworkPropertyMetadata SelectionChangedCommandParameterMetadata = new FrameworkPropertyMetadata {
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
public static readonly DependencyProperty SelectionChangedCommandParameterProperty =
DependencyProperty.Register("SelectionChangedCommandParameter", typeof(Object), typeof(ToolboxView), SelectionChangedCommandParameterMetadata);
#endregion
Then in the ToolboxView.xaml:
<Grid>
<ListBox
ItemsSource="{Binding Tools}"
SelectedItem="{Binding SelectedTool}"
x:Name="ToolView" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding Path=SelectionChangedCommand, RelativeSource={RelativeSource AncestorType={x:Type ToolboxView}}}"
CommandParameter="{Binding Path=SelectionChangedCommandParameter, RelativeSource={RelativeSource AncestorType={x:Type ToolboxView}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate DataType="interfaces:IBuilder">
<TextBlock
FontWeight="DemiBold"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
And use it in MainWindow.xaml:
<views:ToolboxView DockPanel.Dock="Left"
Width="120"
IsHitTestVisible="True"
DataContext="{Binding ToolBoxViewModel}"
x:Name="ToolboxView"
SelectionChangedCommand="{Binding Path=DataContext.SelectionChangedCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
SelectionChangedCommandParameter="{Binding ElementName=ToolboxOverlayView}"/>

WPF MVVM Checkbox stop Command from firing on Data Bind

I have WPF MVVM application and I am currently trying to use a Checkbox that is bound to a column in a list that it is bound to. I have a EventTriggers set and the command bound to the VM. Everything fires great....Except I do NOT want the events to fire when populated from the list, ONLY when the user checks or unchecks the checkbox. See Code:
<StackPanel Orientation="Vertical" Background="Transparent" DockPanel.Dock="Right" Margin="2,0" VerticalAlignment="Center">
<Label Content="Active" />
<CheckBox x:Name="CbArchiveAoi" VerticalAlignment="Center" HorizontalAlignment="Center" FlowDirection="RightToLeft" IsChecked="{Binding Path=PatientAoi.AoiIsActive}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding ArchiveAoiCommand, Mode=OneWay}"
CommandParameter="{Binding ElementName=CbArchiveAoi}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding ArchiveAoiCommand, Mode=OneWay}" CommandParameter="{Binding ElementName=CbArchiveAoi}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</StackPanel>
public ICommand ArchiveAoiCommand
{
get { return new RelayCommand<object>(ArchiveAoiExecute, AlwaysTrueCanExecute); }
}
private void ArchiveAoiExecute(object obj)
{
string dddd = obj.ToString();
}
I'd remove the Interaction.Triggers and use the CheckBox.CommandandCommandParameter properties instead.
<CheckBox x:Name="CbArchiveAoi"
VerticalAlignment="Center"
<-- snip -->
Command="{Binding ArchiveAoiCommand, Mode=OneWay}"
CommandParameter="{Binding ElementName=CbArchiveAoi}" />

Categories

Resources