C# WPF Same Command for Multiple events - c#

I have a WPF application in C# that follows MVVM pattern. I have a written the following code in xaml for double click event in a datagrid that will invoke a command.
<DataGrid.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding LoadDetailGridCommand}">
<MouseBinding.CommandParameter>
<MultiBinding Converter="{StaticResource Converter}">
<Binding ElementName="dgInvDetails" Path="SelectedItem"/>
<Binding ElementName="dgInvDetails" Path="CurrentColumn"/>
</MultiBinding>
</MouseBinding.CommandParameter>
</MouseBinding>
</DataGrid.InputBindings>
I want the same to be triggered when enter key is pressed. Do I have to use the same code with KeyBinding and set Enter key for the same command or is there any better way of doing this?
Thanks in Advance!

If you want to reuse the binding, you could define it as a resource:
<Window.Resources>
<local:MultiConverter x:Key="Converter" />
<MultiBinding x:Key="binding" Converter="{StaticResource Converter}">
<Binding ElementName="dgInvDetails" Path="SelectedItem"/>
<Binding ElementName="dgInvDetails" Path="CurrentColumn"/>
</MultiBinding>
</Window.Resources>
...and then use a custom markup extension to reference it:
<DataGrid.InputBindings>
<KeyBinding Key="Return" Command="{Binding LoadDetailGridCommand}"
CommandParameter="{local:BindingResourceExtension binding}" />
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding LoadDetailGridCommand}"
CommandParameter="{local:BindingResourceExtension binding}" />
</DataGrid.InputBindings>

You need to specify key binding for enter key.
Try below
<DataGrid>
<DataGrid.InputBindings>
<KeyBinding Command="{Binding LoadDetailGridCommand}" Key="Enter" >
<KeyBinding.CommandParameter>
<MultiBinding Converter="{StaticResource Converter}">
<Binding ElementName="dgInvDetails" Path="SelectedItem"/>
<Binding ElementName="dgInvDetails" Path="CurrentColumn"/>
</MultiBinding>
</KeyBinding.CommandParameter>
</KeyBinding>
</DataGrid.InputBindings>
</DataGrid>

Related

ConvertBack is not called

I'm trying to write a universal control in which I can pass different data models (all implement INotifyPropertyChanged) with a converter. The data is passed in the control without problems and is displayed correctly (some of it also uses IMultivalueConverts, which work flawlessly). Although the data is modified, the IMultiValueConverter of the MainControl is not called.
The universal control should just show rectangles calculated from coordinates in an ObservableCollection.
I put DebugConverters on all bindings, and everything seems to be updated except the ConvertBack to the top. The SourceUpdate from the ListBox is also called.
I tried this converter with different NotifyOn...Updated, Mode and UpdateSourceTrigger, I always see the values changing in the control, but never the ConvertBack of the Main Control.
The partial data template used (Updates are done correctly), all the DegreeTo... converters are called both ways
<DataTemplate x:Key="RectangleWithLabel">
<Canvas IsHitTestVisible="True">
<Rectangle x:Name="RectangleROI" MouseLeftButtonDown="myCanvas_PreviewMouseLeftButtonDown" >
<!--
<Rectangle.Visibility>
<Binding Path="ROI" Converter="{StaticResource NullToVisibilityConverter}"/>
</Rectangle.Visibility>
-->
<Canvas.Left>
<MultiBinding Converter="{StaticResource DegreeToScreenPixelConverterH}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged" >
<Binding Path="ROI.Begin.PosH" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource DegreeToScreenPixelConverterV}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
<Binding Path="ROI.Begin.PosV" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</Canvas.Top>
<Rectangle.Width>
<MultiBinding Converter="{StaticResource DegreeToScreenPixelWidthConverter}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
<Binding Path="ROI.Begin.PosH" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="ROI.End.PosH" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True"/>
</MultiBinding>
</Rectangle.Width>
<Rectangle.Height>
<MultiBinding Converter="{StaticResource DegreeToScreenPixelHeightConverter}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
<Binding Path="ROI.Begin.PosV" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True"/>
<Binding Path="ROI.End.PosV" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" />
<Binding Path="DataContext.UsedCoordinateSystem" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" NotifyOnSourceUpdated="True" Mode="TwoWay" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</Rectangle.Height>
<Rectangle.Fill>#33FF0000</Rectangle.Fill>
<Rectangle.Stroke>#FF00FF00</Rectangle.Stroke>
<Rectangle.IsHitTestVisible>true</Rectangle.IsHitTestVisible>
</Rectangle>
The List View containing all the data:
<ListView ItemsSource="{Binding Rectangles, Mode=TwoWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" x:Name="listBox" Width="{Binding ActualWidth, ElementName=ImageControl, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" Height="{Binding ActualHeight, ElementName=ImageControl, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" ItemTemplate="{StaticResource RectangleWithLabel}" MouseMove="ListBox_MouseMove" DataContextChanged="ListBox_DataContextChanged" SourceUpdated="ListBox_SourceUpdated" IsSynchronizedWithCurrentItem="True" TargetUpdated="ListBox_TargetUpdated" />
The call to the ImageViewer from the parent, here the converter is called on the way to the ImageViewer, but the ConvertBack is never called:
<common:ImageViewer x:Name="ctrlImage" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<common:ImageViewer.DataContext>
<MultiBinding Converter="{StaticResource ConverterWhichIsOnlyCalledOneWay}" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" UpdateSourceTrigger="PropertyChanged">
<Binding Path="." UpdateSourceTrigger="PropertyChanged" Mode="TwoWay" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True"/>
</MultiBinding>
</common:ImageViewer.DataContext>
</common:ImageViewer>
How can I get the ConvertBack to be called?
EDIT:
I made an overview of the controls and the converters. I think I was wrong, that the ConvertBack should be called, everything is updating, even without the big converter. But I'm still stuck when adding some elements to the ObservableCollection. When I add some values, the values appear in the DataContext of the MainWindow. But the Converter is not triggered. When I add the Observable.Count as Binding to the Big Converter, the update is triggered, but all bindings are lost.
Changes from the original code were: Changing all internal variables to DependencyProperties, this made updates reliable for the single entries in the ObservableCollection.
Overview of the GUI and the used converters
Time to answer the question myself:
I was wrong when assuming that a changes travels down throught the converter when there is a direct connection between two elements.
So if I have an element (just consider it as a leave of a tree) in a deeply nested and it is once displayed once through a converter (which changes some other objects) and the same time without a converter, the element is updated without calling the converter. WPF is so clever to see that the value is the same and does not pipe the change through the converter up and down.

WPF MultiBinding Converter Object Type

I have bound the Checked event of a checkbox to a method. I am also passing two Command Parameters to that method through a converter (implementing IMultiValueConverter). In the code below, the two CommandParameter bindings are of type bool and type string respectively.
<CheckBox Name="cbTopLeftHeader" Content="Top Left Header">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding IncludeCheckedCommand}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource MultiBindingConverter}" ConverterParameter="IncludeChecked">
<Binding ElementName="cbTopLeftHeader" Path="IsChecked"></Binding>
<Binding Source="{StaticResource TopLeft}"></Binding>
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
Why is it that if I replace the line:
<Binding ElementName="cbTopLeftHeader" Path="IsChecked"></Binding>
With:
<Binding RelativeSource="{RelativeSource Self}" Path="IsChecked"></Binding>
In my converter the IsChecked parameter changes from type bool to type DependencyProperty (DependencyProperty.UnsetValue)?
How can I achieve passing the Checked property without having the element bind to itself by name?
Get rid the interaction trigger and use the Command and CommandParameter properties of the CheckBox:
<CheckBox Name="cbTopLeftHeader" Content="Top Left Header" Command="{Binding IncludeCheckedCommand}">
<CheckBox.CommandParameter>
<MultiBinding Converter="{StaticResource MultiBindingConverter}" ConverterParameter="IncludeChecked">
<Binding RelativeSource="{RelativeSource Self}" Path="IsChecked"/>
<Binding Source="{StaticResource TopLeft}"></Binding>
</MultiBinding>
</CheckBox.CommandParameter>
</CheckBox>
Or stick with your current approach of binding to the CheckBox using ElementName. {RelativeSource Self} of an InvokeCommandAction is not a CheckBox.

WPF Multibinding with Source and Path

I am writing the below code for implementing a Multibinding in WPF textblock
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}-{1}">
<Binding Source="{Binding Path=localResource.bookdata_labelPageNO,Source={StaticResource LanguageManagerDynamic}}"/>
<Binding Path="PageNo"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
I am trying to load a string like "Page xx" where xx is the page number which is a property of the binded model and the string "Page" is loaded from the resource
But i am getting runtime error on this line # XAML . What is causing the error ?
This was my previous working code
<TextBlock Text="{Binding PageNo,StringFormat=page. {0}}" />
Can You try Like this
<TextBlock>
<Run Text="Page" />
<Run Text="{Binding PageNo}" />
</TextBlock>
Ok for pure xaml solution you can do this, assuming your resources are loaded properly.
<Window.Resources>
<sys:String x:Key="Page">Page</sys:String>
</Window.Resources>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Source="{StaticResource Page}"/>
<Binding Path="PageNo" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>

multi binding in wpf

I am trying to do multiple binding in wpf.
here is my code:
<CheckBox>
<CheckBox.IsChecked>
<MultiBinding Converter="{View:MultiConvertorOr}">
<Binding ElementName="txtbox1" Path="Text" Converter="{View:TextToBool}" Mode="TwoWay">
<Binding RelativeSource="{RelativeSource AncestorType={x:Type ListBoxItem}}" Path="IsSelected" Mode="TwoWay">
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
My goal is when I enter text I want the checkbox to be checked (what happens) and the listBoxItem to be selected. (this part is not working).
I also want to keep the binding between the itemListBox and the checkBox (this also works).
Any Ideas how can I do what I want? maybe with event triggers or something like it?
Thanks ahead.

Assign a converter to a member of ancestor for binding in xaml

I wanted to know how to assign my converter to a member called ConvertPoint in the ancestor Viewport?
<DataTemplate DataType="{x:Type local:TestShape}">
<DataTemplate.Resources>
<RelativeSource AncestorType="{x:Type root:Viewport}" x:Key="Viewport"/>
<root:BezierScaleConvertor x:Key="BezierScaleConvertor" />
</DataTemplate.Resources>
<control:TestShape>
<control:TestShape.StartPoint>
<MultiBinding Converter="???"> <----------- Here I don't know how to refer to the member ConvertPoint which is a convertor in Viewport, if I use dynamicResource or Binding, it will raise an exception because it's not a DP.
<Binding Path="StartPoint" />
<Binding Path="ScaleX" RelativeSource="{StaticResource Viewport}"/>
<Binding Path="ScaleY" RelativeSource="{StaticResource Viewport}" />
</MultiBinding>
</control:TestShape.StartPoint>
<control:TestShape.Segments>
<MultiBinding Converter="{StaticResource BezierScaleConvertor}">
<Binding Path="Segments" />
<Binding Path="ScaleX" RelativeSource="{StaticResource Viewport}" />
<Binding Path="ScaleY" RelativeSource="{StaticResource Viewport}" />
</MultiBinding>
</control:TestShape.Segments>
</control:TestShape>
</DataTemplate>
I finally got it out.
To 100% make this cas works, you should use c# code version of datatemplate.
That's all.

Categories

Resources