Dynamic tooltip with textblock in WPF - c#

i'm have some trouble with tooltip in textblock wpf .
After i completed 1 task and if task is error i want update error info with tooltip . But tooltip never show when completed . Please help me .
Thanks
Here my code
C# code
if (status == "Error")
{
LogCreateSite item = (LogCreateSite)gridLog.Items[rowIndex];
item.ErrorInfo = "Error";
DataTemplate template = cellTitle.ContentTemplate;
Canvas canvas = (Canvas)template.LoadContent();
TextBlock txtError = (TextBlock)canvas.Children[1];
ToolTip toolTip = new ToolTip();
toolTip.Content = "asdfasdf";
txtError.ToolTip = toolTip;
txtError.UpdateLayout();
}
And my Xaml :
<DataTemplate x:Key="error">
<Canvas Margin="10,15,0,0">
<!--<Ellipse Fill="#FF5050" Width="12" Height="12">
</Ellipse>-->
<Viewbox Width="16" Height="16">
<Frame Source="../Icon/Error_16.xaml" />
</Viewbox>
<TextBlock Text="Error" Margin="25,-3,0,0">
</TextBlock>
<TextBlock Cursor="Hand" Name="txtErrorInfo" ToolTip="{Binding ErrorInfo, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" FontSize="14" Text="?" Margin="60,-3,0,0" FontWeight="Bold" Foreground="Blue">
</TextBlock>
</Canvas>
</DataTemplate>

You need to do binding for tool tip to show the error/message to user.
Please go thru this tutorial for wpf binding. Introduction to WPF data binding from WPF-tutorial.
your XAML should be like this for a proper binding.
Name="txtErrorInfo" ToolTip="{binding path=error mode=OneWay UpdateSourceTrigger=PropertyChanged}"
It is required to mention mode and UpdateSourceTrigger when you are changing the property which should be shown to user.

Correcting your code, see this sample for how to show ToolTip from code :
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ToolTip t = new ToolTip();
t.Content = DateTime.Now.ToString();
t.IsOpen = true;
t.PlacementTarget = txtError;
t.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
txtError.ToolTip = t;
}

Related

How to Pro-gramatically add click Event to FrameworkElementFactory

I'm trying to apply a data template programatically behind code. I've set the properties fine but I'm stuck on how to add the Click Event. May I ask how abouts do I do that?
Xaml Code that's being copied
<DataTemplate>
<telerik:RadToggleButton Content="+"
Width="20"
Height="20"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Click="RiskButton_OnClick"
Visibility="{Binding AttachmentVisibility, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</DataTemplate>
What I currently have
var toggleButton = new FrameworkElementFactory(typeof(RadToggleButton));
toggleButton.SetValue(RadToggleButton.ContentProperty, "+");
toggleButton.SetValue(RadToggleButton.WidthProperty, 20.0);
toggleButton.SetValue(RadToggleButton.HeightProperty, 20.0);
toggleButton.SetValue(RadToggleButton.HorizontalContentAlignmentProperty, HorizontalAlignment.Center);
toggleButton.SetValue(RadToggleButton.VerticalAlignmentProperty, VerticalAlignment.Center);
//toggleButton.AddHandler(); <- what goes here?
DataTemplate dt = new DataTemplate
{
VisualTree = toggleButton
};
dt.Seal();
toggleButton.AddHandler(RadToggleButton.ClickEvent, new RoutedEventHandler(SomeHandler));
SomeHandler is a RoutedEventHandler:
public void SomeHandler(object sender, RoutedEventArgs e)
{
}

Hyperlink click action and ability to select and copy text

I'm working on a WPF application in C# and need the ability for users to click a hyperlink(execute the command) but also have the ability to select the text and copy it.
I searched for options but could not find anything that would help me.
Currently i have the following in my WPF XAML:
<TextBlock Grid.Column="1" Grid.Row="0">
<Hyperlink Command="{Binding OpenDefaultMailApplicationCommand}" >
<TextBox Height="20" IsReadOnly="True" Foreground="Blue" BorderThickness="0">test#test.nl</TextBox>
</Hyperlink>
</TextBlock>
What am i doing wrong? The text is selectable only i don't have the ability to click on it to execute my command.
This is what I use for similar req.
You need to have a textbox, which is non editable and is clickable. you can style it as a hyperlink by making in underlined and color changes etc.
<TextBox IsReadOnly="True"
Background="Transparent"
BorderThickness="0"
Text="test#test.nl"
Height="20"
PreviewMouseLeftButtonDown="TextBox_PreviewMouseLeftButtonDown"
TextDecorations="Underline"
MouseMove="TextBox_MouseMove"
Foreground="Blue" />
private void TextBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftCtrl))
{
MessageBox.Show("CLicked");
}
}
private void TextBox_MouseMove(object sender, MouseEventArgs e)
{
var txtBox = sender as TextBox;
if (Keyboard.IsKeyDown(Key.LeftCtrl))
{
txtBox.Cursor = Cursors.Hand;
}
else
txtBox .Cursor = null;
}
So i found a other approach for the problem.
By using a richtextbox and adding a hyperlink to that, a user is able to select the text but can also click it.
<RichTextBox Name="rtbEmail" Grid.Column="1" Grid.Row="0" Foreground="Blue" BorderThickness="0"
Margin="3"/>
In the 'C#' usercontrol.cs i programmaticly set the hyperlink and add a click eventhandler to it.
FlowDocument doc = new FlowDocument();
rtbEmail.Document = doc;
rtbEmail.IsReadOnly = true;
rtbEmail.IsDocumentEnabled = true;
Paragraph para = new Paragraph();
doc.Blocks.Add(para);
Hyperlink link = new Hyperlink();
link.IsEnabled = true;
link.Inlines.Add(DataContext.EmailAddress);
link.Click += new RoutedEventHandler(this.OpenEmailAppEvent);
para.Inlines.Add(link);
Hopefully someone has use for this :). i did :)

How to change the foreground of a specific word in a textblock?

I've got a textblock in which the user sees a stacktrace, like this:
System.ArgOutOfRangeExc.:
Argument is out of range.
Parametername: index
at System.Collections.ArrayList.getItem(Int32 index)
//...
at SomethingElse.formData.formData_CloseForm(Object sender, FormClosingEventArgs e)
The idea is, that everything like "System...." gets colored grey and the rest of the stacktrace (here: "at SomethingElse....") should not be colored.
I dont know how and where to start and how to manage this problem. Any solutions? I'm working with C# and WPF
EDIT: The text in the textbox is not static. The text changes everytime the user clicks on a row in a DataGrid, so I need to do that programmatically (working with Substring will get very complicated)
You can simply use a number of Run elements inside your TextBlock. Each Run can have it's own formatting. Take this simple example:
<TextBlock FontSize="14" Margin="20">
<Run Text="This is Green," Foreground="Green" />
<Run Text="this is Red" Foreground="Red" />
<Run Text="and this is Blue AND Bold" Foreground="Blue" FontWeight="Bold" />
</TextBlock>
Please note that the Run.Text property is a DependencyProperty, so you can also data bind its value. This can also be accomplished programmatically:
<TextBlock Name="TextBlock" FontSize="14" Margin="20" />
...
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Run run = new Run("This is Green,");
run.Foreground = Brushes.Green;
TextBlock.Inlines.Add(run);
run = new Run(" this is Red");
run.Foreground = Brushes.Red;
TextBlock.Inlines.Add(run);
run = new Run(" and this is Blue AND Bold");
run.Foreground = Brushes.Blue;
run.FontWeight = FontWeights.Bold;
TextBlock.Inlines.Add(run);
}

Reach a TextBlock from a specific ListViewItem from the ListView in Windows Phone 8.1 XAML programmatically

I am a new developer on Windows Phone 8.1, I am try to reach a specific ListView item from the ListView collection and be able to color it or color the TextBock inside of it, But I can't reach the item or reach any of items inside of ListView, Please take a look for my below code :
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
SQLiteRT db1 = new SQLiteRT();
var db_connection = await db1.Connection("MyDB.sqlite");
List<MyTBL> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;");
db_connection.Close();
LV_Options.ItemsSource = t_list;
}
// my List View called LV_Options
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView lv1 = sender as ListView;
if (lv1 == null)
return;
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
tb.FontSize = 17; // here I got debug error (it not worked !!!!!!!)
var item = LV_Options.Items.ElementAt(3); // this seems not work also !!!!
item.BackColor = Color.LightSteelBlue;
}
As you can see above, I tried to reach a specific item by LV_Options.Items.ElementAt(3) but it doesn't work! I also tried to reach the TextBlock from the selected List view item, but also not worked !
(Updated)
XAML code :
<!-- Title Panel -->
<StackPanel Grid.Row="0" Margin="19,0,0,0">
<TextBlock Name="TB_Rslt" Text="Here result of your answer" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
<TextBlock Text="page title" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
</StackPanel>
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,10,19,15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="TB_Question" Text="Choose Answer " Margin="0,0,25,0" HorizontalAlignment="Right" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" />
<TextBlock Name="TB_EnWord" Text="" Margin="90,0,15,0" HorizontalAlignment="Left" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" TextAlignment="Right" />
<StackPanel Grid.Row="1" Margin="5,22,0,0">
<ListView Name="LV_Options" SelectionChanged="LV_Options_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding AMean1}" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<Button Name="Btn_Answer" Content="Ansewr" HorizontalAlignment="Left" Grid.Row="1" VerticalAlignment="Bottom" Click="Btn_Answer_Click"/>
My application is a quiz application that offer 4 choices/options as answers for each question, and when user select a true answer, I want to highlight the true answer(true choice) by make its background to green, and if the user selected wrong answer/option I want to make the background of that answer (a specific List View item) with red.
Any help please ?
You're not going to be able to access an element inside a data template like that. Instead, leverage the binding to a view model to set the color and other view-related properties. First, create a wrapper view model for your data class:
public class MyTBLViewModel : INotifyPropertyChanged
{
public MyTBL Entity
{
get { return _entity; }
}
private readonly MyTBL _entity;
public Brush Highlight
{
get { return _brush; }
set
{
_brush = value;
RaisePropertyChanged("Highlight");
}
}
private Brush _highlight;
public double ItemFontSize
{
get { return _itemFontSize; }
set
{
_itemFontSize = value;
RaisePropertyChanged("ItemFontSize");
}
}
private Brush _itemFontSize;
public MyTBLViewModel(MyTBL entity)
{
_entity = entity;
_highlight = new SolidColorBrush(Colors.Transparent);
_itemFontSize = 12;
}
public event PropertyChangedEventArgs PropertyChanged;
protected void RaisePropertyChanged(string propName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propName));
}
}
Use this as your ItemsSource:
List<MyTBLViewModel> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;")
.AsEnumerable().Select(entity => new MyTBLViewModel(entity)).ToList();
Now in your view, bind the view elements to "Highlight" and "ItemFontSize", and to any other properties you like:
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6" Background="{Binding Highlight}">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding Entity.AMean1}" TextWrapping="Wrap"
FontSize="{Binding ItemFontSize}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Finally, you can get the data item from the SelectionChangedEventArgs -- use it to update your view-related properties:
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Color.LightSteelBlue);
item.ItemFontSize = 17;
}
foreach (var item in e.RemovedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Colors.Transparent);
item.ItemFontSize = 12;
}
}
var item = LV_Options.Items.ElementAt(3);
This line is incorrect. It will not return you a TextBlock. I don't know what a .BackColor is, and it should not compile. The Items property in a ListView will return you a list of ListViewItems. If you want to access the inside element from a ListViewItem, you'll need to access the ContentTemplateRoot property.
Do not use var ever. It lets you assume that you know the type, whereas if you explicitly typed the declaration you would realize you're doing it wrong.
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
What is a MyTBL type? FindName is only available to framework DependencyObjects so I'm assuming it's a user control? You have to provide a lot more code to show us what you're doing and what you're setting the ListView's ItemsSource and ItemTemplate with and what these errors are and how you have 2 breaking debug errors at once and what the error messages are.
Comprehending runtime error messages is a huge part of being a good developer.

Finding a control inside another control in WPF

Since there is no link button in WPF I created a link button using hyperlink and text block controls.
There are 3 controls:
<TextBlock Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" >
<Hyperlink Name="hyplnkIsActiveMarkets" Click="hyplnkIsActive_Click" Foreground="Blue" >
<TextBlock Name="txtblkIsActiveMarkets" Text="Active" />
</Hyperlink>
</TextBlock>
<TextBlock Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left">
<Hyperlink Name="hyplnkIsActiveBudgets" Click="hyplnkIsActive_Click" Foreground="Blue" >
<TextBlock Name="txtblkIsActiveBudgets" Text="Active" />
</Hyperlink>
</TextBlock>
<TextBlock Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Left">
<Hyperlink Name="hyplnkIsActivePrograms" Click="hyplnkIsActive_Click" Foreground="Blue" >
<TextBlock Name="txtblkIsActivePrograms" Text="Active" />
</Hyperlink>
</TextBlock>
All the link buttons calls same click method
private void hyplnkIsActive_Click(object sender, RoutedEventArgs e)
{
Hyperlink objHyperlink = (Hyperlink)sender;
TextBlock objTextBlock = new TextBlock();
if (objHyperlink == hyplnkIsActiveMarkets)
{
objTextBlock = txtblkIsActiveMarkets;
}
else if (objHyperlink == hyplnkIsActiveBudgets)
{
objTextBlock = txtblkIsActiveBudgets;
}
else if (objHyperlink == hyplnkIsActivePrograms)
{
objTextBlock = txtblkIsActivePrograms;
}
if (objTextBlock.Text == "Active")
ChangeHyperLinkStatus(objHyperlink, objTextBlock, Status.Inactive);
else ChangeHyperLinkStatus(objHyperlink, objTextBlock, Status.Active);
}
In the click method I check for the text block inside the hyper link individually using if condition.
Is there any easier way to do this? That's basically finding control inside a control?
UPDATE: you can not use VisualTreeHelper.GetParent(...) to get the parent of your hyperlink as you have mentioned hyperlink is not visual. corrected the answer.
See code below.
private void hyplnkIsActive_Click(object sender, RoutedEventArgs e)
{
Hyperlink objHyperlink = (Hyperlink)sender;
TextBlock objTextBlock = (TextBlock)LogicalTreeHelper.GetChildren(objHyperlink)[0];
// This will give logical tree first child of objHyperlink
if (objTextBlock.Text == "Active")
ChangeHyperLinkStatus(objHyperlink, objTextBlock, Status.Inactive);
else
ChangeHyperLinkStatus(objHyperlink, objTextBlock, Status.Active);
}
See this article about logical tree on MSDN
I think you're going into the wrong direction by relaying your execution logic on controls and not on data.
You can, for example, bind a ICommand or RelayCommand to the buttons, or just subscribe different events, or define a custom DataTemplate where on mouse down the clicked control is assignable to some ModelView property.
Doing in way you do, you create tough coupling between UI and your execution logic.
In this case easier use WindowsForm then WPF.
I got it finally . Thanks to Maheep fa his help
TextBlock objTextBlock = (TextBlock)LogicalTreeHelper.GetChildren(objHyperlink).Cast<System.Windows.Documents.InlineUIContainer>().FirstOrDefault().Child;

Categories