How to use EventToCommand - Error in XAML - c#

The user input something in the TextBox and hits the Enter-button. When the Enter-button is hit the AddFieldCommand is called. How do I do what in XAML?
My code is giving me a warning: "The Property 'Text' is set more than once".
I need to know which object in the Canvas that is being updated, so I can add the content from the TextBox to my model - this is why I use EventToCommand.
<TextBox x:Name="txtFields" Text="{Binding FieldsTextProperty, UpdateSourceTrigger=PropertyChanged}" Height="23" TextWrapping="NoWrap" Background="#FFCBEECD" AcceptsReturn="False" >
<TextBox.InputBindings>
<KeyBinding Key="Enter" >
</KeyBinding>
</TextBox.InputBindings>
<i:EventTrigger EventName="AddField">
<cmd:EventToCommand Command="{Binding DataContext.AddFieldCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</TextBox>
Can anybody help?

In XAML, everything that’s placed inside an element becomes its content. For text boxes, this sets the Text property. This is to allow things like this:
<TextBox>Foo bar</TextBox>
So you can place the content within the XAML elements. This is equivalent to this:
<TextBox Text="Foo bar" />
Now, if you look at your XAML code, you will notice that you have two elements inside the TextBox element: TextBox.InputBindings and i:EventTrigger. To explain the first, you need to know that there is another way to specify an element’s property values, by using child elements. This makes the above examples equivalent to this:
<TextBox>
<TextBox.Text>Foo bar</TextBox.Text>
</TextBox>
This works for all properties of TextBox. Now, InputBindings is an property of TextBox, so having it as a child element will correctly set the property and it will also not affect the element’s content value (so Text isn’t set by its presence). However, i:EventTrigger is not an property of TextBox, so this will set the content of the TextBox—giving the error message you see.
To use interaction event triggers, you need to place these into the attached property i:Interaction.Triggers. As an attached property, it can be set with a child element like above. So, your code should look like this:
<TextBox …>
<i:Interaction.Triggers>
<i:EventTrigger EventName="AddField">
<cmd:EventToCommand … />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>

You can use ICommand interface to execute your command and use IsDefault=true property of the button which allows it to remain focus.So when you click enter it will execute the Command you binded on the button.
<TextBox x:Name="txtFields" Text="{Binding FieldsTextProperty,UpdateSourceTrigger=PropertyChanged}" Height="23" TextWrapping="NoWrap" Background="#FFCBEECD" AcceptsReturn="False" />
<Button Name="btnEnter" IsDefault="True" Command="{Binding DataContext.AddFieldCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />

Related

WPF Binding CommandParameter to Element of perent window

I build some WPF application that as MainView, inside this MainView I have a button that opens a setting window and a Model that I want to be able to show or hide from this settings view. (the show/hide button was originally on the MainView itself) the problem is that I do not know how to use the CommandParameter in the SettingsView to bind to an element In the MainViw.
the element in the MainView:
<Dev:DevUnitView x:Name="DevData" DataContext="{Binding MainModel.DevUnit}" Visibility="Visible" Margin="994,656,74,-83"/>
the button in the SettingsView:
<Button Content="Show/Hide debug values" Command="{Binding Settings.DevVisibilityCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Dev:DevUnitView}}, Path=DataContext}" Margin="156,22,180,349"/>
I also tried to Bind to the MainView but I do not know how to find the element I need from there:
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type mainWindow:MainView}}, Path=DevUnit}"
in this case, it cannot resolve the "DevUnit" in the data context, I also tried by name and other variation of this without success.
the old button that worked in the MainView:
<Button Content="DEV" Command="{Binding Settings.DevVisibilityCommand}" CommandParameter="{Binding ElementName=DevData}" Margin="406,359,810,259"/>
now no matter how I try to bind it I getting Null UserControl.

Is there a way to pass treeViewItem name as command parameter?

I am creating a simple treeview with binding to a collection. What I want is to display full info about the collection element in a listview when treeview element is selected. Similar to windows file explorer. The problem is I cannot bind selected treeviewitem to a Command.
Tried binding command to SelectedItemChanged event with a parameter of treeviewitem name - didn`t work.
Tried it with a simple event - gets cumbersome and breaks MVVM pattern. There must be an elegant way to solve this since what I am trying to do is really widespread in different apps.
<TreeView Grid.Row="1" Background="AliceBlue" ItemsSource="{Binding TopPanelNodes}" Name="TopTreeView" SourceUpdated="TopTreeView_SourceUpdated" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Nodes}">
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" IsEnabled="False">
<TextBlock Text="{Binding Name}" >
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding UpdateInspectorCommand }" CommandParameter=??? />
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
I would like to pass treeviewitem name as command parameter instead of ??? in my code so selected treeview item will be identified by name so I can get respective info and bind it to listview.
Solved it using RelativeSource.
CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeView}}}"
Works fine.

WPF Binding two dependency properties of the same control but two datacontexts needed

I have two controls in a grid.
<TextBlock Text="{Binding Name}" TextAlignment="Center" />
<TextBox Visibility="{Binding ElementName=EditMode,Source={Binding RelativeSource=
{RelativeSource FindAncestor, AncestorType={x:Type Window}}},
Converter={StaticResource BoolToVis}}" Text="{Binding Name}"
TextAlignment="Center" />
I am trying to implement something like an editable/non editable behaviour. I know i might choose for a TextBox and simply change the IsEditable property but still, in my scenarion i would need to DataContext, at least that's what i am thinking of.
In my example, the TextBlock works fine, and the Text property on the TextBox also works fine but for the Visibility part, i want to bind to a data property ( EditMode which is a boolean) found on some other layer. Is there a way to change the DataContext to that, but only for the Visibility ? The Text property should remain as it is now.
Should i try a hack, to define an invisible checkbox, change IsChecked when my Edit button is clicked and bind directly to that ? I will try this. I think this way, no DataContext changing is needed.
#FrumRoll is correct that you can access a property that is not in the set DataContext object using a RelativeSource Binding. However, I'm not sure that their code is quite right... try this:
<TextBox Visibility="{Binding DataContext.EditMode, RelativeSource={RelativeSource
AncestorType={x:Type YourXamlPrefix:MainWindow}}}, Converter={StaticResource
BoolToVis}}" Text="{Binding Name}" TextAlignment="Center" />
Clearly, you'll need to change the YourXamlPrefix value with your local XAML Namespace Prefix and MainWindow with the name/type of your Window if it is not called MainWindow. This also assumes that your EditMode property has been defined in that Window.
This may also work, but is not specifically looking for your exact Window, so may have some problems:
<TextBox Visibility="{Binding DataContext.EditMode, RelativeSource={RelativeSource
AncestorType={x:Type Window}}}, Converter={StaticResource BoolToVis}}"
Text="{Binding Name}" TextAlignment="Center" />
It seems to me you were almost there, you should be able to use a RelativeSource to do this. The issue is that you misused ElementName, ElementName is to bind to a property of a named source and would be used instead of RelativeSource. What you meant to use was Path, which is optional as seen below.
<TextBox Visibility="{Binding DataContext.EditMode, RelativeSource={RelativeSource AncestorType={x:Type Window}},
Converter={StaticResource BoolToVis}}"
Text="{Binding Name}" TextAlignment="Center" />

Cannot bind command within a ListBox

My WPF uses the MVVM approach. I'm trying to bind 2 controls within my list control
<ListBox ItemsSource="{Binding ParentDuplicate}" SelectedItem="{Binding SelectedParent, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ContentControl Content="{Binding}" />
<Button Content="Delete me now"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=Window}, Path=DeleteCommand}"
CommandParameter="{Binding FilePath}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem I'm having, is the DeleteCommand is not binding (the Ouput window informs me as well)
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Data.Binding', AncestorLevel='1''. BindingExpression:Path=DeleteCommand; DataItem=null; target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')
If I move this button to outside the ListBox, then the binding works and the event fires so I know the issue must be with the ListBox (I'm guessing the problem is the ItemsSource prevents the binding to anything but the ItemsSource bound property (in this case, ParentDuplicate))
So, within the Button control, there are 2 properties being bound, DeleteCommand and FilePath
Both of these properties live within my single ViewModel. FilePath is a child of ParentDuplicate and this binds as desired. The issue is only with the DeleteCommand. What am I doing wrong?
Edit
When I use the Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=Window}, Path=DeleteCommand} it is looking in my MainWindow code behind, not at the ViewModel. How do I make it use the ViewModel?
I tried
Command="{Binding RelativeSource={RelativeSource AncestorType=xmlnsViewModel:MainWindowViewModel}, Path=DeleteCommand}"
but the above also results in the same binding errors
The ancestor search finds the control, not the DataContext, so you'll need to tell your binding where to find the DeleteCommand property. If your ViewModel is the DataContext of the MainWindow then you can just use:
<Button Content="Delete me now"
Command="{Binding RelativeSource={RelativeSource
Mode=FindAncestor, AncestorLevel=1, AncestorType=Window},
Path=DataContext.DeleteCommand}"
CommandParameter="{Binding FilePath}" />

Binding toggle button to two commands

I have a toggle button in my silverlight application as follows:
<ToggleButton Content="ToggleButton" Margin="0,30,0,0" Style="{StaticResource ChkToggleButton}" />
The toggle currently is changing visual states on toggle and nothing more.
However, I need to bind each of the toggle with a different command. For eg: On button press1, run command1 and on button press again, run command2.
How can this be done?
Use Triggers for such purposes:
<ToggleButton Content="ToggleButton" Margin="0,30,0,0" Style="{StaticResource ChkToggleButton}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding FirstCommand}"
CommandParameter="{Binding SomeParameter}" />
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding SecondCommand}"
CommandParameter="{Binding AnotherParameter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ToggleButton>
If you don't have Interactivity you can get it by installing Expression Blend SDK or as a NuGet package.
use a single command and also keep track of the toggle state.
Have a viewmodel (preferably, or some codebehind) and let it use these two inputs to decide what actually needs to be done.

Categories