I have a ListBox which is dynamically filled during runtime. It has a DataType of RequirementPreview which is needed to bind certain properties to triggers, sources and parameters. There is, however, 1 command-binding that needs to trigger a command that is set in the datacontext but has nothing to do with the template datatype.
What I want is that the Button fires the 'RevertDelete'-command and sends the Guid of the RequirementPreview to which the button belongs. As of now, nothing happens when I press the button.
Xaml:
<ListBox Grid.Row="1" Grid.ColumnSpan="3" Margin="5" IsEnabled="{Binding IsEnabled}" ItemsSource="{Binding Requirements}" SelectionMode="Extended">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SelectionChanged}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding IsDeleted}" Value="True">
<Setter Property="Foreground" Value="red"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type myModels:RequirementPreview}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="45"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Name}" ToolTip="{Binding Name}" HorizontalAlignment="Stretch"/>
<Button Grid.Column="2" HorizontalAlignment="Right" IsEnabled="{Binding IsEnabled}" Visibility="{Binding IsDeleted, Converter={StaticResource BoolToVisibility}}"
Command="{Binding RevertDelete}" CommandParameter="{Binding Guid}" Height="10" Width="10"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Xaml.cs:
[Dependency]
public IMainViewModel ViewModel
{
get { return this.DataContext as IMainViewModel; }
set { this.DataContext = value; }
}
Edit:
Tried messing around with the databinding;
Command="{Binding RelativeSource={x:Static RelativeSource.PreviousData}, Path=RevertDelete}"
Command="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=RevertDelete}"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=RevertDelete}
Neither made a difference.
I guess RevertDelete command is not a part of RequirementPreview type which works as a data context for the template. You'll need to use relative source binding for this command:
<Button Command="{Binding DataContext.RevertDelete, RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding Guid}" />
Related
Hi I need to solve a problem between the TextBox and the treeview. When I select the TreeView after the TextBox I don't receive the LostFocus Event (for the TextBox) why?
I have tried to play a lot with Focusable and the focusableManager but .... it didn't helped me.
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Visibility="{Binding VariableA, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToHiddenConverter}}
<TextBox Width="78" FocusManager.IsFocusScope="True"
PreviewTextInput="HatchingDistanceBox_PreviewTextInput"
Name="TextBoxAWhoShouldLostFocus" BorderThickness="0.5"
BorderBrush="White" MinHeight="30" Height="30" Text="{Binding SelectedFamille.VariableA}"
utilities:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text">
</TextBox>
<TreeView Name="TreeView_After" ItemsSource="{Binding FirstGeneration}" Focusable="True" Grid.ColumnSpan="3" Grid.Row="2" Grid.Column="0" AllowDrop="True" Background="#282828" Margin="15, 0,0,0" >
<TreeView.Style>
<Style TargetType="{x:Type TreeView}">
<EventSetter Event="GotFocus" Handler="TreeViewItem_GotFocus"></EventSetter>
</Style>
</TreeView.Style>
<i:Interaction.Behaviors>
<utilities:TreeViewSelectionBehavior SelectedItem="{Binding SelectedFamille}"/>
</i:Interaction.Behaviors>
<TreeView.Resources>
<DataTemplate x:Key="NormalTemplate">
<StackPanel Orientation="Horizontal" Name="StrategyNamePanel" Mouse.PreviewMouseDown="StrategyNamePanel_MouseDown" Width="200" Background="#282828" Focusable="True" FocusManager.IsFocusScope="True">
<TextBox Name="StrategyNameBox" FontWeight="Normal" FocusManager.IsFocusScope="True" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=Explicit}" MinHeight="30" Height="30" BorderThickness="0" utilities:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text"></TextBox>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="EditTemplate">
<StackPanel Orientation="Horizontal" Name="NamePanel" Focusable="True" Mouse.PreviewMouseDown="NamePanel_MouseDown" Width="200" Background="{StaticResource DarkGrey}" FocusManager.IsFocusScope="True">
<TextBox Name="NameBox" FontWeight="Normal" BorderBrush="{StaticResource DarkOrange}" FocusManager.IsFocusScope="True" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=Explicit}" MinHeight="30" Height="30" utilities:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text" ></TextBox>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<EventSetter Event="GotFocus" Handler="TreeViewItem_GotFocus"></EventSetter>
<EventSetter Event="TreeViewItem.DragOver" Handler="TreeView_After_DragOver"/>
<EventSetter Event="TreeViewItem.Drop" Handler="TreeView_After_Drop"/>
<EventSetter Event="TreeViewItem.MouseMove" Handler="TreeView_After_MouseMove"/>
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
The LostFocus from the textbox work when I click everywhere except in the TreeView
2) The lostFocus work if I first select a parent in the treeView and then a Treeview Item.
3)When I first select a treeViewItem and Then an Another treeViewItem there is no more LostFocus Event.
Why????
My problem is that I have a lot of code doing the same thing. All the buttons in my stackpanel trigger a command and with that command I want to send a parameter to a method in my view model.
I have the following XAML code, as you can see it is ridiculously repetitive:
<StackPanel x:Name="Row" Grid.Row="4">
<Button Content="z"
Command="{Binding ButtonClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
<Button Content="x"
Command="{Binding ButtonClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
<Button Content="c"
Command="{Binding ButtonClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
<Button Content="v"
Command="{Binding ButtonClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
<Button Content="b"
Command="{Binding ButtonClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
<Button Content="n"
Command="{Binding ButtonClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
<Button Content="m"
Command="{Binding ButtonClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
</StackPanel>
Is there a way I can reduce the amount of repetitive code, either in the XAML or View Model?
Thanks in advance
Simple solution that works, assuming you have buttons and command binding done at one place or else the first answer (seen the answer after my post) gives you easiest way by putting under an ItemsControl and do the stuff.
<StackPanel x:Name="Row" Grid.Row="4">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Command" Value="{Binding ButtonClickCommand}" />
<Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content}"
/>
</Style>
</StackPanel.Resources>
<Button Content="z" />
<Button Content="x" />
<Button Content="c" />
<Button Content="v" />
<Button Content="b" />
<Button Content="n" />
<Button Content="m" />
</StackPanel>
Hope this helps you :)
Create a list of items in your ViewModel, for example
public IEnumerable<string> Values { get; set; } = new List<string> { "x", "c", "v", "..." };
And assign it to the ItemsControl
<ItemsControl x:Name="Row" Grid.Row="4" ItemsSource="{Binding Values}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding }"
Command="{Binding Path=DataContext.ButtonClickCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding }"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ItemsControl.ItemsPanel says what container to use for these items and ItemTemplate defines what each element of StackPanel should look like.
Binding inside DataTemplate refers to string that's why in order to get to the ButtonClickCommand we have to go back to ItemsControl's context.
Inside my listview I´ve created a control template. Inside this template I made a button, so that every item inside mit listview has a button. This button represents an link which opens the directory that is shown. When I click the button, my program opens the explorer as I expect it. But when I click the button of an item that is not selected it opens the path of the selected item. So my question is, how can I change the selected item when I click the button inside my listview.
Here is how it looks like:
As you can see "R1" is selected, but I click on the link of "R3". What happens is, that C:\Temp\Folder1 gets opened, because "R1" is still the selecteditem. What I wish to is that C:\Temp\Folder3 gets opend. I think the trick should be that "R3" gets selected when clicking the button that represents the link. Does anyone know how to that?
This is my XAML-Code:
<ListView Grid.Row="1" ItemsSource="{Binding MyCollection}" FontSize="20" SelectedItem="{Binding SelectedMember, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="7,10,7,0" x:Name="ListView1" SelectionChanged="ListView1_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="Header 1" Width="150"/>
<GridViewColumn Header="Header 2" Width="120"/>
<GridViewColumn Header="Header 3" Width="120"/>
<GridViewColumn Header="Header 4" Width="560"/>
<GridViewColumn Header="Header 5" Width="100"/>
</GridView>
</ListView.View>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="560"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" Content="{Binding ID}" HorizontalAlignment="Center"/>
<ContentPresenter Grid.Column="1" Content="{Binding Name}" HorizontalAlignment="Center"/>
<ContentPresenter Grid.Column="2" Content="{Binding Description}" HorizontalAlignment="Center"/>
<Button Grid.Column="3" Content="{Binding Path}" Style="{StaticResource Link}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.GoToPathCommand }" HorizontalAlignment="Left" Margin="5,0,0,0" IsEnabled="{Binding ButtonEnabled}"/>
<ContentPresenter Grid.Column="4" Content="{Binding Owner}" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="DarkBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.GoToPathCommand }"
This Command will jump to the Cmd of the ViewModel. I assume that the Command will check which item is selected and it will access it's property Path.
Avoiding this behavior, You can create a Command that will take a parameter and set it from Binding:
<Button Content="{Binding Path}"
Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=DataContext.GoToPathCommand }"
CommandParameter="{Binding Path}"/>
Now the command itself must be adjusted:
public MyCmd : ICommand
{
public void Execute(object parameter)
{
string path = (string) parameter;
//Open the path via explorer
}
}
Try adding below trigger too in the ListViewItem Style
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
</Style.Triggers>
I have an Image and a button side by side in a DevExpress grid, when the user clicks the button I would like the user to be able to select from a FileDialog a new image that should immediately show in the Image Field. When the user updates the rest of the fields in the row the IPropertyChange event should fire and store the row. How can I achieve this in WPF?
XAML:
<dxg:GridColumn FieldName="Image" Header="Image" >
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<DockPanel>
<Image Source="{Binding RowData.Row.Image, Converter={StaticResource BinaryImageConverter}}" Width="100" />
<Button x:Name="BrowseFilePath" Height="20" Width="20" Content="..." Visibility="Hidden" CommandParameter="{Binding RowData.Row}" />
<!--<Button x:Name="BrowseFilePath" Height="20" Width="20" Content="..." Visibility="Hidden" Command="{Binding Source={x:Static local:FacilitiesBrowseImagePathDialog.BrowsePathCommand}}" CommandParameter="{Binding RowData.Row}" />-->
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dxg:GridRow}}" Value="True">
<Setter TargetName="BrowseFilePath" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
</dxg:GridColumn>
I have a treeview which contains files, every view model holds an item source which is an ObservableCollection with files items:
public ObservableCollection<CMItemFileNode> SubItemNode
On each item i have context menu options (Delete, Execute..).
If i move from one viewModel to another the ObservableCollection of files updated correctly and presented correctly but, when i perform a context menu command like delete file item, the command execute good but when i move to another view model (which holds SubItemNode ObservableCollection of is own) after the command executed the WPF still thinks i'm in the last view model i was in and not the one i'm really on.
Very important to mention is that when i update to .net 4.5 (which unfortunantly i can't do) everything is ok and the ObservableCollection addresses the correct view model.
Here is the treeView:
<TreeView x:Name="Files" Margin="0,5,5,0" Grid.Row="6" Grid.Column="2" ItemsSource="{Binding SubItemNode}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalAlignment="Stretch" Height="300" Grid.RowSpan="6" Width="300" dd:DragDrop.IsDragSource="True" dd:DragDrop.IsDropTarget="True" dd:DragDrop.DropHandler="{Binding}" dd:DragDrop.UseDefaultDragAdorner="True">
<TreeView.Resources>
<Style TargetType="{x:Type TreeView}">
<Setter Property="local:CMTreeViewFilesBehavior.IsTreeViewFilesBehavior" Value="True"/>
</Style>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
<Setter Property="local:CMTreeViewFilesItemBehavior.IsTreeViewFilesItemBehavior" Value="True"/>
</Style>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
</TreeView.Resources>
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Header="View File" Command="{Binding ExecuteFileCommand}" />
<Separator />
<MenuItem Header="Delete all" Command="{Binding DeleteAllFilesCommand}" />
<MenuItem Header="Delete selected" Command="{Binding DeleteSelectedFilesCommand}" />
</ContextMenu>
</TreeView.ContextMenu>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubItemNode}" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Margin="2" Width="32" Height="18" Source="{Binding Path=Icon}" HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBlock Text="{Binding Path=Name}" Grid.Column="1" Margin="2" VerticalAlignment="Center" Foreground="{Binding Path=Status, Converter={StaticResource ItemFileStatusToColor}}" FontWeight="{Binding Path=IsSelected, Converter={StaticResource BoolToFontWidth}}"/>
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Am I doing somthing wrong? and why in .net 4.5 it works well ?
Apparently in .net 4 after executing a context menu command we lose context inside the tree.
To solve this we need to add this to the context menu:
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" >
If we upgrade to .net 4.5 it's not necessary.