Binding by relative source is not working in Tooltip WPF - c#

I am using Syncfusion visual style. I am trying to bind the ToolTip foreground inside the TextBlock present inside the StackPanel for displaying the ToolTip text.But the binding doesn't work properly in the TextBlock.
MainWindow.xaml
<Grid>
<CheckBox Grid.Row="5" Grid.Column="1" HorizontalAlignment="Center" Margin="0,4,10,0" VerticalAlignment="Center" IsChecked="{Binding AutoAdd, Mode=TwoWay}">
<CheckBox.ToolTip>
<StackPanel>
<TextBlock Foreground="{Binding Path=Foreground, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type ToolTip}}}" FontWeight="Bold" FontSize="14" Margin="0,0,0,5">Automatically Add To Path</TextBlock>
<TextBlock Foreground="{Binding Path=Foreground, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type ToolTip}}}">
If this path is associated with the primary configuration,
<LineBreak />
automatically add newly instantiated optical elements to the end of the path.
</TextBlock>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,8" />
<WrapPanel>
<Image Margin="0,0,5,0" />
<TextBlock Foreground="{Binding Path=Foreground, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type ToolTip}}}" FontStyle="Italic">Press F1 for more help</TextBlock>
</WrapPanel>
</StackPanel>
</CheckBox.ToolTip>
</CheckBox>
</Grid>
Any other work around regarding this issue.
Regards,
Hari Prasad

A Tooltip is in a different datacontext and not directly in the visual tree to a control which appears to be it's parent. Hence, when you search up the visual tree using relativesouce, it will find nothing.
You may use PlacementTarget to reference the thing which is nominally it's parent - checkbox in your markup
"{Binding Path=PlacementTarget.PropertyName, RelativeSource={RelativeSource Self}}"
Here PropertyName is whichever property you want.
That could be DataContext.ViewModelProperty if you wanted a property in your viewmodel.
In this instance I would try
Foreground="{Binding Path=PlacementTarget.Foreground, RelativeSource={RelativeSource Self}}"
Depending on your usage, maybe using a dynamicresource would be simpler though.

Related

A command from a context menu that does not work

Well, I have a WPF project and I'm using Visual Studio 2010. I'm using C# and XAML, and I'm using the MVVM pattern.
The problem I have must be simple but I just can't see why it's not working.
Alright, so I have a project with a ListBox. In that ListBox are many ChatNodes; each represented visually. The visual element for a ChatNode is here:
<ControlTemplate x:Key="NodeVisualTemplate">
<Grid>
<Border BorderThickness="2" Margin="2" CornerRadius="5,5,5,5" BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.SelectionMode, Converter={StaticResource SelectionModeToColourConverter}}" ContextMenu="{StaticResource ChatNodeMenu}">
<StackPanel Opacity="{Binding IsInvisibleNode, Converter={StaticResource ResourceKey=VisibleToOpacityConverter}}">
<TextBlock Text="Test" Background="AntiqueWhite"/>
<TextBlock Text="{Binding Path=NodeText}" Background="Aqua"/>
<StackPanel Orientation="Horizontal">
<TextBox Text="Type here" MinWidth="50"/>
<Image Source="{StaticResource ImgFolder}" Margin="0,0,5,0" Width="32" Height="32"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</ControlTemplate>
I draw your attention to the BorderBrush for the Border. I will show that again here:
BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.SelectionMode, Converter={StaticResource SelectionModeToColourConverter}}"
This code sits inside a ListBoxItem and is able to find the parent ListBox and then access a property of it. This works fine. The property is in a view model called ChatNodeListViewModel and looks like this:
private int _selectionMode = 0;
public int SelectionMode
{
get { return _selectionMode; }
set
{
if (_selectionMode != value)
{
_selectionMode = value;
RaisePropertyChanged("SelectionMode");
}
}
}
I mention it specifically because another thing which is almost identical is not working, even though this BorderBrush code is working.
So, on to the not working part.
In that same ControlTemplate above, we see a ContextMenu, called 'ChatNodeMenu'. This is as follows:
<ContextMenu x:Key="ChatNodeMenu" >
<MenuItem Header="Remove" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.RemoveChatNodeCommand}" />
</ContextMenu>
It has the same binding, only this time it is for a Command called 'RemoveChatNodeCommand'. The menu does appear on a right click on a ChatNode, but the command does not run. I have actually used almost identical code in other parts of my project so I assume it's correct... but clearly there is an error somewhere.
So where is this command? It is in the view model called 'ChatNodeListViewModel' and I will present it here:
void RemoveChatNodeExecute()
{
MessageBox.Show("Remove chat node");
return;
}
bool CanRemoveChatNode()
{
return true;
}
public ICommand RemoveChatNodeCommand { get { return new RelayCommand(RemoveChatNodeExecute, CanRemoveChatNode); } }
I have also used this in many places throughout my code and it's worked every time but this one.
So, either there's a fault in the code or perhaps a simple mistake. I've checked the name of the command and re-copied it several times. I've checked the other parts of my code where I've used the same code, but I can't see anything wrong. I've cleaned and rebuilt my project just in case.
If anyone can venture a guess, I would be very happy with that.
The ListBox is not a visual ancestor of a ContextMenu but you could set the Tag property of the Border to the ListBox and then bind to the PlacementTarget of the ContextMenu:
<Border ... Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}" ContextMenu="{StaticResource ChatNodeMenu}">
<MenuItem Header="Remove" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.Tag.DataContext.RemoveChatNodeCommand}" />
I have same issue related to conextmenu not able to work on command. could you help me to find solution.
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="test2">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="rr2" Command="{Binding DataContext.NextCommand, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" CommandParameter="{Binding}" ></MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

WPF - How to display a tooltip on a hyperlink only when the hyperlink is disabled

This is a more specific description of my problem from a previous question, with a follow-up answer.
I had a standard hyperlink defined in XAML:
<TextBlock>
<Hyperlink IsEnabled="{Binding LinkEnabled}">
<TextBlock Text="{Binding Text}"/>
</Hyperlink>
</TextBlock>
The hyperlink's IsEnabled property is bound to a property on the view model, the value of which can change. I needed to place a tooltip on the hyperlink which would only be displayed if the hyperlink is disabled.
To show the tooltip only when the hyperlink is disabled, the ToolTipService.ShowOnDisabled and ToolTipService.IsEnabled (with the negation converter) properties must be set on the hyperlink:
<TextBlock>
<Hyperlink IsEnabled="{Binding LinkEnabled}"
ToolTip="ToolTip"
ToolTipService.ShowOnDisabled="True"
ToolTipService.IsEnabled="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={StaticResource negateConverter}}">
<TextBlock Text="{Binding Text}"/>
</Hyperlink>
</TextBlock>
However, the tooltip won't be shown, since once the hyperlink is disabled, it stops being hit-testable, because it is contained in the TextBlock (or so I understood).
Thus, the solution would be to change the "IsEnabled" property on the parent TextBlock, not on the hyperlink.
However, this works:
<TextBlock IsEnabled="False">
But this doesn't:
<TextBlock IsEnabled="{Binding LinkEnabled}">
In the latter case, changing the TextBlock's IsEnabled property will not change the hyperlink's IsEnabled property. To solve this issue, the hyperlink's IsEnabled property must be bound to the parent's property.
And here is the actual solution, all put together:
<TextBlock IsEnabled="{Binding LinkEnabled}">
<Hyperlink IsEnabled="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type FrameworkElement}}}"
ToolTip="ToolTip"
ToolTipService.ShowOnDisabled="True"
ToolTipService.IsEnabled="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type FrameworkElement}}, Converter={StaticResource negateConverter}}">
<TextBlock Text="{Binding Text}"/>
</Hyperlink>
</TextBlock>

Binding to another element?

I can't get this to work, I have a TextBlock that I want to bind its 'Text' property to a the Window's title.
I tried this:
<TextBlock Text="{Binding path=Window.Title}" ... />
You're using the wrong syntax with binding. First add a name to your Window, let it be "window1".
Then do the following:
<TextBlock Text"{Binding ElementName=window1, Path=Title}" ... />
<TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" />
If the Window element has no name, you can refer to it with a RelativeSource.

how to bind a command from DataContext of Page to a list item

I have a Page and a viewmodel is set as its datacontext. in that page I have a list. which is populating through a property in the viewmodel. List has a user control. and that user control has a button. I want that button to be bind with a command that is in viewmodel. Is there anyway to do that?
<Page DataContext=PageViewModel>
...
<ScrollViewer Grid.Row="3" Margin="20,0" Visibility="{Binding ByVenueSelected, Converter={StaticResource BooleanToVisibilityConverter}}">
<StackPanel>
<ItemsControl ItemsSource="{Binding EventsListByVenue}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<myControls:EventDetails /> <!--in this control i want to bind a command available in PageViewModel-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
...
</Page>
with help of #FunksMaName, I solved this. I am sure there are more elegant and better approach, but yet this is a quick & easy solution for me:
<Button Style="{StaticResource NoHighlightButtonStyle}" Tag="{Binding link}" CommandParameter="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}" Visibility="{Binding link,Converter={StaticResource DataAvailabilityToVisibilityConverter}}" Command="{Binding Path=Event.LinkCommand,Source={StaticResource Locator}}" >
<TextBlock Margin="0,5" Foreground="SkyBlue" Text="{Binding link}" TextWrapping="Wrap" FontSize="16"/>
</Button>
things to note:
i think xaml searched the command parameter in context of command only, so it was giving me null parameter, while the same binding was working fine for textblock inside Button. So i tricked it to store the value in tag, and used it from there.
Tag="{Binding link}" CommandParameter="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}"

Modify TemplatedParent from ControlTemplate

I have a problem to modify TemplatedParent from ControlTemplate. My xaml code is:
<RadioButton Name="source" Focusable="True">
<RadioButton.Template>
<ControlTemplate>
<RadioButton Name="target" Focusable="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Focusable, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
When Focusable in source is changing also Focusable in target should change and Enabled in source and target should change.
For excample:
source.Focucable = false
then
source.IsEnabled = false, target.IsEnabled=false, target.Focusable=false
UPDATED
When I tried solution proposed by Rachel, everything works fine as long as code looks like this:
<RadioButton Name="source"
Focusable="False"
IsEnabled="{Binding Focusable, RelativeSource={RelativeSource Self}}"
Height="19"
HorizontalAlignment="Left"
Width="146" Margin="0,12,0,0" VerticalAlignment="Top">
<RadioButton.Template>
<ControlTemplate>
<RadioButton
Name="target"
Focusable="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Focusable, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Focusable, RelativeSource={RelativeSource Self}}"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
Problem occurs in my real application, where I can't set binding in xaml (controls are build dynamically, and templates are reading from resources file) but only in c#.
XAML in this situation looks like this:
<RadioButton Name="source"
Focusable="False"
Height="19"
HorizontalAlignment="Left"
Width="146" Margin="0,12,0,0" VerticalAlignment="Top">
<RadioButton.Template>
<ControlTemplate>
<RadioButton
Name="target"
Focusable="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Focusable, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Focusable, RelativeSource={RelativeSource Self}}"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
and c#
Binding bindingRadio = new Binding("RadioButton.Focusable");
bindingRadio.RelativeSource = new RelativeSource(RelativeSourceMode.Self);
source.SetBinding(RadioButton.IsEnabledProperty, bindingRadio);
In xaml source Focusable is set to False, so binding in c# should set IsEnabled also to false. But when I click on radio it is making checked. Where should I put this c# code to make things works as it should be (i tried Window_Load, Radio_Initialized, Radio_Loaded)
Why not just bind the IsEnabled properties to the Focusable properties?
It looks like you're already binding the Focusable property to the template value, so just bind the IsEnabled property to the Focusable one
IsEnabled="{Binding Focusable, RelativeSource={RelativeSource Self}}"
Also, I think as a shortcut for your Focusable binding you can use {TemplateBinding Focusable} instead of binding to the relative source

Categories