Make a binding on ElementName to change when trigered - c#

I'm probably missing something because what I do is suposed to work I think. I'm trying to bind the ElementName of a value to change when trigered.
here's the code (it is in the style):
<ContentPresenter>
<ContentPresenter.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Tick}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName={Binding FieldNameFocus}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
And get this error:
Error 2 A 'Binding' cannot be set on the 'ElementName' property of type 'Binding'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject. C:\Users\xavier\Documents\Visual Studio 2012\Projects\Test_Validation\Test_Validation\MainWindow.xaml 1 2 Test_Validation
Maybe I'm not in the right path though... I just want to have focusedElement to change according to FieldNameFocus when Tick becomes True. (Both are in my dataContext)
Thanks in advance.

Your binding should look like this: Value="{Binding ElementName=YourElementName, Path=PropertyOfTheElement}"
Example binding by ElementName:
<TextBox Name="tbx1" Text="TextBox"/>
<TextBox Name="tbx2" Text="{Binding ElementName=tbx1, Path=Text}"/>

Hello the error is pretty clear, you cannot use Binding on with ElementName. When using ElementName you should provide the name of a control present in your xaml File as the previous post showed. As your trigger is bind to a boolean value you might want to replace "ElementName={Binding FieldNameFocus}" by
"ElementName=controlNameOnWhichYouWantToSetFocus".
Eg <Textbox x:Name="ControlIWantFocusOnWhenTickIstrue"> then in your trigger
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName="ControlIWantFocusOnWhenTickIstrue"/>

Related

Is it possible to use trigger setter to change ViewModel property?

I am opening Popup using IsOpen bound to some hard to reach attached property. All I want is to somehow pass IsOpen value to ViewModel.
Trying to use setter for this:
<Popup StaysOpen="False"
IsOpen="{Binding Path=(local:ListViewBehavior.IsColumnHeaderClicked), RelativeSource={RelativeSource FindAncestor, AncestorType=GridViewColumnHeader}}">
<Popup.Style>
<Style TargetType="Popup">
<Style.Triggers>
<Trigger Property="IsOpen" Value="True">
<!-- this is not possible -->
<Setter Property="{Binding IsPopupOpened ...}" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</Popup.Style>
</Popup>
Gives:
A 'Binding' cannot be set on the 'Property' property of type 'Setter'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
Is there a way to pass IsOpen value (which is already bound to something else in the View) to ViewModel?
You could created an attached Property, which is set by eventhandlers to the Opened and Closed Events of the Popup. That can be bind to the IsPopupOpen Property of your ViewModel by OneWayToSource Binding.
I'm also not quite sure if there is an easier Solution, but this is a kind of "Workaround" what I would do, in case that no-one provides a better solution here.

Binding visibility of a control depending on the state of a string attribute in my viewmodel

I have a string property in my viewmodel called "CurrentTool". How can I bind the visibility of a control depending on the state of the currentTool?
This for example does not work:
<DockPanel Visibility="{Binding (CurrentTool == brush), Converter={StaticResource BoolToVis}}"/>
I know that I can create some boolean properties in my viewmodel such as CurrentToolIsBrush and just bind to that, but I want to know if there is a simpler cleaner way.
You can use QuickConverter to convert inline in XAML (https://quickconverter.codeplex.com/)
In your case you could use something like:
Visibility="{qc:MultiBinding '$P0==$P1 ? Visibility.Visible : Visibility.Collapsed', P0={Binding CurrentTool}, P1={Binding brush}}"
You can use custom style with DataTriggers
<DockPanel.Style>
<Style TargetType="{x:Type DockPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentTool}" Value="brush">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DockPanel.Style>

Binding Button Tooltip with Content / Label

I have this code:
<ribbon:Button Label="Hello" />
I wanted to bind its tooltip to Label like:
<ribbon:Button Label="Hello" ToolTip="Hello" />
I have already tried creating style with the following info, but failed:
<Style TargetType="{x:Type ribbon:Button}">
<Setter Property="ToolTip" Value="{Binding Text}" />
</Style>
Please tell me how can I fix this. Instead of ribbon:Button, normal button code be used and I want to bind its tooltip property with its Content property.
Edit: One more thing after trying, if i set the Value property of Setter inside style without any binding, it works fine. Eg:
<Style TargetType="{x:Type ribbon:Button}">
<Setter Property="ToolTip" Value="This will show" />
</Style>
But binding is not applied here. So problem arises only when binding is done :(
Of course your style won't work, because you always bind to the properties of your DataContext, which i doubt is your Control itself.
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=Text}"/>
should work fine.
The golden rule for binding is: look for binding errors in the debug output.
Secondly, you are binding Text, where everywhere else you use the property label.
Thirdly, understand that the basis for Binding is the DataContext. You can give Xaml elements a name, then use the Binding syntax based on ElementName to bind to FrameworkElement properties.

DateTime XAML Binding String Format to show "null" for DateTime.MinValue

I have a binding to a date:
<TextBlock Text="{Binding Path=EndDateTime, StringFormat=d}"/>
What I want is that when its value is DateTime.MinValue (DateTime's default value) to display null instead of the date.
Is this possible without using a converter, simply by somehow extending my binding's StringFormat property?
Is there any other XAML only solution?
Thank you in advance!
You could use a DataTrigger in the TextBlock's Style
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding Path=EndDateTime, StringFormat=d}" />
<Style.Triggers>
<DataTrigger Binding="{Binding EndDateTime}" Value="{x:Static sys:DateTime.MinValue}">
<Setter Property="Text" Value="NULL" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
There is no XAML only solution for this in Silverlight 4. In Silverlight 5 you could use a Markup Extension, though that's still code you would have to write. In Silverlight 4 you could use a Behavior as well.
My suggestion is to expose a property on your ViewModel which provides the null functionality. Then you wouldn't have to use a Converter, though the property you're binding to would work as you would like.

Why does WPF Style to show validation errors in ToolTip work for a TextBox but fails for a ComboBox?

I am using a typical Style to display validation errors as a tooltip from IErrorDataInfo for a textbox as shown below and it works fine.
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
But when i try to do the same thing for a ComboBox like this it fails
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
The error I get in the output window is:
System.Windows.Data Error: 17 : Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1'). BindingExpression:Path=(0)[0].ErrorContent; DataItem='ComboBox' (Name='ownerComboBox'); target element is 'ComboBox' (Name='ownerComboBox'); target property is 'ToolTip' (type 'Object') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.Parameter name: index'
Oddly it also attempts to make invalid Database changes when I close the window if I change any ComboBox values (This is also when the binding error occurs)!!!
Cannot insert the value NULL into column 'EmpFirstName', table 'OITaskManager.dbo.Employees'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Simply by commenting the style out everyting works perfectly. How do I fix this?
Just in case anyone needs it one of the comboBox' xaml follows:
<ComboBox ItemsSource="{Binding Path=Employees}"
SelectedValuePath="EmpID"
SelectedValue="{Binding Path=SelectedIssue.Employee2.EmpID,
Mode=OneWay, ValidatesOnDataErrors=True}"
ItemTemplate="{StaticResource LastNameFirstComboBoxTemplate}"
Height="28" Name="ownerComboBox" Width="120" Margin="2"
SelectionChanged="ownerComboBox_SelectionChanged" />
<DataTemplate x:Key="LastNameFirstComboBoxTemplate">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{1}, {0}" >
<Binding Path="EmpFirstName" />
<Binding Path="EmpLastName" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
SelectionChanged: (I do plan to implement commanding before long but, as this is my first WPF project I have not gone full MVVM yet. I am trying to take things in small-medium sized bites)
// This is done this way to maintain the DataContext Integrity
// and avoid an error due to an Object being "Not New" in Linq-to-SQL
private void ownerComboBox_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
Employee currentEmpl = ownerComboBox.SelectedItem as Employee;
if (currentEmpl != null &&
currentEmpl != statusBoardViewModel.SelectedIssue.Employee2)
{
statusBoardViewModel.SelectedIssue.Employee2 = currentEmpl;
}
}
Your getting this error because when you validation finds that there are no issues, the Errors collection returns with no items, and the following binding logic fails:
Path=(Validation.Errors)[0].ErrorContent}"
you are accessing the validation collection by a specific index. I'm currently working on a DataTemplate Suggestion for replacing this text.
I love that Microsoft listed this in their standard example of a validation template.
update so replace the code above with the following, and the binding logic will know how to handle the empty validationresult collection:
Path=(Validation.Errors).CurrentItem.ErrorContent}"
(following xaml was added as a comment)
<ControlTemplate x:Key="ValidationErrorTemplate" TargetType="Control">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Red" FontSize="24" Text="*"
ToolTip="{Binding .CurrentItem}">
</TextBlock>
<AdornedElementPlaceholder>
</AdornedElementPlaceholder>
</StackPanel>
</ControlTemplate>
Update in 2019
As of currently, the correct path syntax to use is:
Path=(Validation.Errors)/ErrorContent
I think this is the best way:
Path=(Validation.Errors)/ErrorContent
/ is actually equal to CurrentItem by #Nathan
In my case, CurrentItem is a no go.
Try the converter for converting to a multi-line string as described here
I've seen the code you're using posted in multiple places, but it seems odd to me that
Path=(Validation.Errors)[0].ErrorContent}
doesn't raise any red flags. But I'm also new to WPF and perhaps there is some secret to making that work in every case.
Rather than attempting to index a possibly empty collection with an array index, add a converter that returns the first error in the list.
In my case, I was getting this exception when I tried to apply #Nation Tregillus' solution:
Cannot resolve property 'CurrentItem' in data context of type
'System.Collections.ObjectModel.ReadOnlyObservableCollection'
So I went with #Altiano Gerung's solution instead, where my code ended up being:
<ControlTemplate x:Key="ValidationErrorTemplate">
<DockPanel Margin="5,0,36,0">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" DockPanel.Dock="Right"
Margin="5,0,36,0"
ToolTip="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors)/ErrorContent}"
ToolTipService.ShowDuration="300000"
ToolTipService.InitialShowDelay="0"
ToolTipService.BetweenShowDelay="0"
ToolTipService.VerticalOffset="-75"
>
CurrentItem did not work for me either But
#Nathtan's answer worked for my situation where I have a custom textBox resource. Thanks #Nathan I spent an hour on this.
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)/ErrorContent}" />
</Trigger>
</Style.Triggers>

Categories

Resources