Bind Command to a ComboBoxItem in WPF - wpf

I have a wpf project with a ComboBox. The items there inside are filled in dynamically. So it is bound to a model which contains a Label and a Command.
If the User selects an item in the Dropdown / ComboBox the Command should be executed. I tried it with a DataTemplate containing a TextBlock and a Hyperlink for the Command. But the Command will only execute if a select the Label (Hyperlink) and not if I click on the whole item.
<ComboBox ItemsSource="{Binding Path=States}" SelectedItem="{Binding CurrentState}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink Command="{Binding Command}" TextDecorations="None" Foreground="Black">
<TextBlock Text="{Binding Path=Label}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
So the question is now, how can I bind my Command to a ComboBoxItem?

A ComboBoxItem has no Command property but you could execute the command from the setter of the CurrentState property:
private State _currentState;
public State CurrentState
{
get { return _currentState; }
set
{
_currentState = value;
if (_currentState != null)
{
_currentState.Command.Execute(null);
}
}
}
This property will be set whenever you select an item in the ComboBox. The other option would be to handle the SelectionChanged event in the view.

Related

WPF MVVM Enable\Disable telerik:RadComboBox inside GridViewDataColumn from ViewModel

In WPF, I am trying to disable combo boxes inside a telerik:GridViewDataColumn based on the IsComboBoxEnabled property of my ViewModel. If I set IsEnabled=false from XAML, it works and the combo box is disabled. However, when I bind IsEnabled to a value on my viewmodel, it is always enabled even when the value is set to false.
<telerik:GridViewDataColumn>
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<telerik:RadComboBox SelectedValue="{Binding SomeSelectedValue}"
ItemsSource="{Binding SomeItemsSource}"
IsEnabled="{Binding IsComboBoxEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewDataColumn>
public bool IsComboBoxEnabled
{
get
{
return _isComboBoxEnabled;
}
set
{
_isComboBoxEnabled = value;
RaisePropertyChanged("IsComboBoxEnabled");
}
}
The issue was due to me setting the IsComboBoxEnabled property from the viewmodel of the datagrid instead of the viewmodel of the individual record.

Bind IsEnable property of button located inside data grid to variable

I want to bind IsEnable property of button to variable. Button is added inside data grid. Data Grid is located inside user control.
Below code is not working.
<DataGridTemplateColumn Header="Start" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="Start_Button"
DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext}"
IsEnabled="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}},Path=IsStartButtonEnable}"
Command="{Binding StartCommand}">START
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Model contains-(ServerModel.cs)
private bool _isStartButtonEnable = false;
public bool IsStartButtonEnable
{
get
{
return _isStartButtonEnable;
}
set
{
_isStartButtonEnable = value;
this.OnPropertyChanged("IsStartButtonEnable");
}
}
View Model(ServerViewModel.cs) Contains -
public static ObservableCollection<ServerModel> DataGridServerList { get; set; }
UserControl (ServerUserControl.cs) contains -
this.DataContext = new ServerViewModel();
Requirements - UserControl contains 3 buttons-Create, Start and Stop. User clicks on Create Button. If Create commnd gets success, then Start button gets enabled.Then user will click on Start button. If start commnd gets executed successfully, then Stop button gets enabled and so on.
<DataGridTemplateColumn Header="Start" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="Start_Button"
IsEnabled="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.IsStartButtonEnable}"
Command="{Binding StartCommand}">START
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I am using the DataContext of the UserControl directly and not that of the DataGrid.
In your case, indeed, the DataContext of the Button will be set to each item in the DataGrid. In order to access the property on your UserControl you need this change. Further more, you don't need to set the DataContext again so i removed that line.
You have two possibilities in my opinion. Either set the flag in the ViewModel and will be accessible by all Buttons through the Relative Source syntax or if you have it in the Model, you will have a flag for each row in the DataGrid. In either case you have the response:
If it is in the Model, set the DataGrid ItemsSource to your ObservableCollection and use
IsEnabled = {Binding IsStartButtonEnable }
2.If it is in the ViewModel, use
IsEnabled="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}},Path=DataContext.IsStartButtonEnable}"
I don't see other option but if you want it available for all Buttons in the DataGrid you have to set it in the ViewModel.

WPF MVVM DataTemplate: Inject Template ViewModel with Data from parent Viewmodel

I have an ObservableCollection in my parent ViewModel which I want to display in the parent View. So I've defined a child View and a child ViewModel handling button clicks.
How do I get each item from the ObservableCollection into the according child ViewModel without loosing my already setup RelayCommands for button click handling?
In my parent View Code-Behind the only thing I do is setting the DataContext to the appropiate ViewModel:
DataContext = new ParentViewModel();
In my parent View XAML I defined a ListBox to display a DataTemplate of my child View:
<ListBox
ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<views:ChildView Width="auto" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now in my ChildView I got several TextBlocks displaying the Binding Data and Buttons which should execute a file in a path specified within the ObservableCollection:
<TextBlock
Text="{Binding Path=Title}" />
...
<Button
Content="Start exe"
Tag="{Binding Path=ExePath}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path=OnButtonClicked}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
The Child ViewModel holds RelayCommands to handle the Button click event:
private RelayCommand onButtonClicked;
public ICommand OnButtonClicked
{
get
{
return onButtonClicked ??
(onButtonClicked =
new RelayCommand(ObeyOnButtonClicked, CanObeyOnButtonClicked));
}
}
private void ObeyOnButtonClicked()
{
... //Path conversion
Process.Start(pathToExe);
}
private bool CanObeyOnButtonClicked()
{
return true;
}
Now, within my child View's Code-Behind, when I add
DataContext = new SampleItemViewModel();
to the Constructor, the Button click is handled but the TextBoxes are all empty.
When i remove this line, the TextBoxes are filled correctly, but the Button Clicks are not handled.
How do I get both features working?
EDIT:
ParentViewModel:
private ObservableCollection<Item> items;
public ObservableCollection<Item> Items
{
get { return items; }
set
{
items= value;
OnPropertyChanged("Items");
}
}
... //Filling the Collection in Constructor
ChildViewModel contains just the above mentioned button click handlers.
EDIT:
I tried several things now but I don't know how to bind the Command from the ChildView to my ChildViewModel WITHOUT setting the DataContext of my ChildView to my ChildViewModel
You can remove the Event Trigger, as Button has a Command property.
<TextBlock Text="{Binding Path=Title}" />
...
<Button
Content="Start exe"
Tag="{Binding Path=ExePath}"
Command="{Binding Path=OnButtonClicked}"
>
</Button>
And set the DataContext :
<ListBox
ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<views:ChildView Width="auto" DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Silverlight 4 and LisBox's SelectedItem when using DataTemplate as ItemTemplate

I'm using tow listboxes for drag n drop where user can drag items from source listbox and drop on the target. I'm using a DataTemplate for the ListBoxItems of my ListBox Controls.
I need to give the user ability to move up/down items in the target listbox after they been moved from source. I have two button "Move Up" & "Move Down" to do that but when the user clicks on one of the button, it returns me the null object as selectedItem.
here is my code
private void moveUp_Click(object sender, RoutedEventArgs e)
{
ListBoxItem selectedItem = lstmenuItems.SelectedItem as ListBoxItem;
if (selectedItem != null)
{
int index = lstmenuItems.Items.IndexOf(selectedItem);
if (index != 0)
{
lstmenuItems.Items.RemoveAt(index);
index -= 1;
lstmenuItems.Items.Insert(index, selectedItem);
lstmenuItems.SelectedIndex = index;
}
}
}
I'm sure its to do with the ItemTemplate. here is the xaml for listbox
<ListBox x:Name="lstmenuItems" Height="300" MinWidth="200" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Code}"/>
<TextBlock Text="{Binding RetailPrice, StringFormat=£\{0:n\}}" />
</StackPanel>
<!-- Product Title-->
<TextBlock Text="{Binding Description1}" Width="100" Margin="2" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Any ideas how can I access the selected Item and how can I move it up/down?
Thanks in advance
The selectedItem variable will contain a null because the SelectedItem property doesn't return the type ListBoxItem. The SelectedItem property returns an object it received from the collection supply its ItemsSource property.
Change to :-
object selectedItem = lstmenuItems.SelectedItem;
and that should get you a little further.
That said consider having the ItemsSource bound to an ObservableCollection and manipulate the collection instead.

Bind TextBlock in DataTemplate (resource) to Content of checked radio button

I have a TextBlock in resource data template:
<DataTemplate x:Key="MyDataTemplate" ItemsSource="{Binding MySource}">
<TextBlock x:Name="MyText" Text="{Binding ???}" />
</DataTemplate>
that I want to bind with Content of checked radio button:
<RadioButton GroupName="MyGroup" Content="Code" />
<RadioButton GroupName="MyGroup" Content="Description" />
if Code radio button is selected, then I want the text become Text={Binding Code}.
Please help, thank you.
Assuming this is backed by a viewmodel, you would set up your viewmodel thusly:
bool isCodeChecked;
public bool IsCodeChecked
{
get { return isCodeChecked; }
set
{
if(value == isCodeChecked) return;
isCodeChecked = value;
// raise notification that ***MyText*** property has changed (INotifyPropertyChanged interface)
}
public string MyText
{
get { return IsCodeChecked ? "Code" : "Description"; }
}
Then set up your XAML:
<RadioButton GroupName="MyGroup" Content="Code" IsChecked="{Binding IsCodeChecked, Mode=OneWayToSource}" />
<DataTemplate x:Key="MyDataTemplate" ItemsSource="{Binding MySource}">
<TextBlock x:Name="MyText" Text="{Binding MyText}" />
</DataTemplate>
The binding on the CheckBox will cause the boolean property on the viewmodel to be updated, which in turn will notify the textbox to update its bound value.
I created 2 DataTamplate in resources, and I switch my TreeView's ItemTemplate from code behind
if (ViewByCodeRadioButton.IsChecked == true)
MyTreeView.ItemTemplate = Resources["MyDataTemplateCode"] as DataTemplate;
else
MyTreeView.ItemTemplate = Resources["MyDataTemplateDesc"] as DataTemplate;

Resources