WPF tooltip Binding getting override when I set the tooltip from code - c#

I have a User control and I bind the tooltip of that control into some object's property
<usercontrols:ucButton x:Name="xSaveCurrentBtn" ButtonType="ImageButton" ButtonFontImageSize="16" ButtonImageWidth="18" ButtonImageHeight="18" ButtonImageType="Save" Click="xSaveSelectedButton_Click" ButtonStyle="{StaticResource $ImageButtonStyle_Menu}" DockPanel.Dock="Right" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,0,0">
<usercontrols:ucButton.ToolTip>
<ToolTip Content="{Binding ItemName, Mode=OneWay}" ContentStringFormat="Save {0}"/>
</usercontrols:ucButton.ToolTip>
</usercontrols:ucButton>
from the code I set the data context of the ucButton to be my object:
xSaveCurrentBtn.DataContext = WorkSpace.Instance.CurrentSelectedItem;
sometimes the CurrentSelectedItem is null, and if this is the case I want the tooltip to display "No Item Selected"
I tried doing this:
xSaveCurrentBtn.Tooltip = "No Item Selected";
but when the CurrentSelectedItem isn't null and I reset the xSaveBtn.DataContext to that object, I am still seeing the No Item Selected tooltip as if my WPF tooltip section was overriden and its no longer binding into the datacontext ItemName Property

You are trying to set a property to two values at the same time. It's impossible.
What you are doing in XAML is equivalent to:
xSaveCurrentBtn.Tooltip = new ToolTip() {.....};
When you setting a string value to the same property, the previous value is lost. And it is not possible to restore it if you do not save it first.
You might want to assign a value in case of a binding error:
<ToolTip Content="{Binding ItemName,
Mode=OneWay,
FallbackValue='No Item Selected'}"
ContentStringFormat="Save {0}"/>
how can I bind the data context to update to be the new CurrentSelectedItem without explicitly setting it?
Assuming that «WorkSpace.Instance» is an immutable property that returns an instance of «WorkSpace» and «CurrentSelectedItem» is a property with an «INotifyPropertyChanged.PropertyChanged» notification, then you can do this:
<usercontrols:ucButton DataContext="{Binding CurrentSelectedItem, Source={x:Static viewmodels:WorkSpace.Instance}}" ...>
The «viewmodels» prefix depends on the assembly and namespace in which the «WorkSpace» class is declared.

you can use ContentTemplate with TextBlock, which will either use StringFormat, or TargetNullValue depending on ItemName being null:
<usercontrols:ucButton.ToolTip>
<ToolTip Content="{Binding ItemName}">
<ToolTip.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding StringFormat='Save {0}',
TargetNullValue='No Item Selected'}"/>
</DataTemplate>
</ToolTip.ContentTemplate>
</ToolTip>
</usercontrols:ucButton.ToolTip>
or if you bind Tooltip.Content differently:
<usercontrols:ucButton.ToolTip>
<ToolTip Content="{Binding}">
<ToolTip.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ItemName,
StringFormat='Save {0}',
FallbackValue='No Item Selected'}"/>
</DataTemplate>
</ToolTip.ContentTemplate>
</ToolTip>
</usercontrols:ucButton.ToolTip>

Related

wpf dependency with ItemTemplate

I need to display value of selected RibbonMenuButton in TextBlock below. Items of ribbonMenuButton are defined as ItemTemplate. How to define reference in Path? I marked it by "xxx"
<ribbon:RibbonMenuButton ItemsSource = "{Binding Path=CompaniesList.Companies}" x:Name="rbtnCompanies" Label="{x:Static resources:ConsoliaJPK.SELECT_COMPANY}" SmallImageSource="Resources/Images/Check32.png" Margin="16,0,-15.604,-0.264">
<RibbonMenuButton.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="tblCompany" Text="{Binding Path=Name}" PreviewMouseLeftButtonDown="tblCompany_PreviewMouseLeftButtonDown" >
</TextBlock>
</DataTemplate>
</RibbonMenuButton.ItemTemplate>
</ribbon:RibbonMenuButton>
<TextBlock Text = "{Binding ElementName=rbtnCompanies, Path=xxx}" Margin="41,6,-132,-6.604"></TextBlock>
I suppose rbtnCompanies.xxx should contain Name. You can do this assignment in your tblCompany_PreviewMouseLeftButtonDown I suppose.

Custom control binding is not updating

I'm having trouble getting my binding to work correctly. Basically I have this, call this Control1.xaml. The commented out portion of the code binds correctly and updates as expected.
<progControls:CalibrationSummary
</progControls:CalibrationSummary>
<!--<TextBlock Text="{Binding Path=NumberOfCalibrations, Mode=OneWay}"/>-->
However, if I put that commented code in a custom control called CalibrationsSummary.xaml, I cannot bind this to NumberOfCalibrations.
Here's what CalibrationsSummary looks like
<Grid>
<TextBlock Text="{Binding Path=NumberOfCalibrations, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
Note that I do use RelativeSource to try to get the property associated with Control1.xaml, tried TemplateBinding also. What am I doing wrong?
CalibrationSummary has no TemplatedParent unless you have put it in a ControlTemplate.
If you don't explicitly set the DataContext of the property of CalibrationSummary somewhere, it will inherit the DataContext from its parent control (which I assume is Control1) and then you can bind any property of this control's DataContext as usual without specifying any source:
<Grid>
<TextBlock Text="{Binding Path=NumberOfCalibrations}"/>
</Grid>

WP7: Conditionally show & hide control elements in Data Templates

I have a note application with a ListBox control, which lists all the available notes from the ObservableCollection<Note> Notes. class Note has attributes like
String Title;
bool Has_Reminder;
DateTime Reminder_Date;
What I want is that the TextBlock element, which shows the Reminder_Date, is only shown, if Has_Reminder is true. But I do not know how to access this attribute from my custom control NoteListItem. Its this.DataContext attribute is null, but the control still properly displays the Note's bound attributes handed down by the ListBox ItemsSource. How can I achieve that?
Thanks for your help.
I tried to read the attributes in the constructor, which did not work:
public NoteListItem()
{
InitializeComponent();
Note this_note = LayoutRoot.DataContext as Note; // turns out, this_note is null
if (!this_note.Has_Reminder)
Reminder_Info.Visibility = System.Windows.Visibility.Collapsed;
}
NoteListItem control
<Grid x:Name="LayoutRoot" >
<TextBlock x:Name="Title" Text="{Binding Title}" />
<TextBlock x:Name="Reminder_Date" Text="{Binding Reminder_Date}" />
</Grid>
NoteList control:
<ListBox x:Name="NoteListBox" ItemsSource="{Binding Notes}" >
<ListBox.ItemTemplate>
<DataTemplate>
<local:NoteListItem />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Do you know how to use a converter? Your converter would convert a bool to a Visibility, then you can bind the TextBlock's Visibility to Has_Reminder:
<TextBlock x:Name="Reminder_Date" Text="{Binding Reminder_Date}" Visibility="{Binding Has_Reminder, Converter={...}}"/>
This might help: http://www.jeff.wilcox.name/2008/07/visibility-type-converter/

convert generic type to listbox control

I'm using silverlight framework 4: I'm trying to list my items in a generic list to a listbox control: But the only data a receive is the classname itself.
lsBox => the listbox control
lsTags => generic type
My question is: how can I add my items in the generic list, to the listbox control?
my code is:
lsBox.ItemsSource = lsTags;
You can use DisplayMemberPath and SelectedValuePath properties of your ListBox control to tell ListBox which property's value should be displayed for every item and which property should be used for determening ListBox.SelectedValue property. Or use ListBox.ItemTemplate to display a complex data like this:
<ListBox x:Name="usersInGroupLBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsActive, Mode=TwoWay}" />
<TextBlock Text="{Binding User.UserName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Do not forget, you can use only public properties for binding. Check you class Tag.
The default behavior of ListBox (and most other controls) for displaying user types is to call the ToString() method. The default behavior of that is to display the class name.
What you should do depends on what you want to display, but if it's something simple like displaying the value of the Name property, just set the DisplayMemberPath property:
<ListBox Name="lsBox" DisplayMemberPath="Name" />

WPF: Cannot set properties on property elements weirdness

private TextBlock _caption = new TextBlock();
public TextBlock Caption
{
get { return _caption; }
set { _caption = value; }
}
<l:CustomPanel>
<l:CustomPanel.Caption Text="Caption text" FontSize="18" Foreground="White" />
</l:CustomPanel>
Gives me the following error:
Cannot set properties on property elements.
If I use:
<l:CustomPanel>
<l:CustomPanel.Caption>
<TextBlock Text="Caption text" FontSize="18" Foreground="White" />
</l:CustomPanel.Caption>
</l:CustomPanel>
My TextBlock shows up fine but it's nested inside another TextBlock like so, it even seems to add itself outside of the Caption property:
<l:CustomPanel>
<l:CustomPanel.Caption>
<TextBlock>
<InlineUIContainer>
<TextBlock Text="Caption text" FontSize="18" Foreground="White" />
</InlineUIContainer>
</TextBlock>
</l:CustomPanel.Caption>
<TextBlock>
<InlineUIContainer>
<TextBlock Text="Caption text" FontSize="18" Foreground="White" />
</InlineUIContainer>
</TextBlock>
</l:CustomPanel>
As you might have already guessed, what i'd like my code to do is to set my Caption property from XAML on a custom panel, if this is possible.
I've also tried the same code with a DependencyProperty to no avail.
So, anyone that can help me with this problem?
I can explain what is going wrong and how to fix it.
First,
<l:CustomPanel>
<l:CustomPanel.Caption Text="Caption text" FontSize="18" Foreground="White" />
is a simple syntax error. The <l:CustomPanel.Caption> syntax does not accept XML attributes - the property value must be within the element.
This is proper property element syntax:
<l:CustomPanel>
<l:CustomPanel.Caption>
<TextBlock Text="Caption text" FontSize="18" Foreground="White" />
</l:CustomPanel.Caption>
</l:CustomPanel>
but:
Property element syntax works only with DependencyProperties (so it didn't work with your CLR property) and
Property element syntax always honors the ContentPropertyAttribute of the property type
Since TextBlock has a [ContentPropertyAttribute("Inlines")], the property element syntax is trying to add the TextBlock to the Inlines collection.
The solution is simple: Declare your property as a DependencyProperty of type UIElement instead of type TextBlock. This has the additional advantage of not restricting the display of content to just a TextBlock. If you really do want to restrict it to just a TextBlock, you can use a validation callback.
public UIElement Content { get { ...
public static readonly DependencyProperty ContentProperty = ...
Just got a non-ideal workaround from a colleague of mine. It involves declaring the Caption property as a resource like:
<Page.Resources>
<TextBlock x:Key="test" Text="Caption text" FontSize="18" Foreground="White" />
</Page.Resources>
<l:CustomPanel Caption="{StaticResource test}" />
I'd still like to know why I can't use the two previous options, so if anyone knows please answer. :)
It seems that you can get this error (in Silverlight 4 and 5 at least) if you specify a namespace on the element. For example:
<Path>
<MapLayer.Position xmlns="clr-namespace:Microsoft.Maps.MapControl">
...
In this case MapLayer.Position is an attached property. It seems that the Silverlight parser requires the namespace to be defined using a prefix:
<Path xmlns:map="clr-namespace:Microsoft.Maps.MapControl">
<map:MapLayer.Position>
...

Categories

Resources