XAML link to section of window - wpf

In XAML how can I set a hyperlink to take the user to a particular section of my window. Like how you can with anchor tags in HTML. Basically we want the user to be able to click on an error in a list of errors and the link will take them to that area.

XAML Hyperlink NavigateUri could work with a bit of code behind, i.e.
<Window x:Class="fwAnchorInWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox x:Name="TextBoxName" Text="Enter Name"/>
<TextBox x:Name="TextBoxNumber" Text="Enter Number"/>
<TextBlock>
<Hyperlink NavigateUri="TextBoxName" RequestNavigate="Hyperlink_RequestNavigate">
There is a name error.
</Hyperlink>
</TextBlock>
</StackPanel>
</Window>
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
namespace fwAnchorInWindow
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
if (sender is Hyperlink)
{
string controlName = ((Hyperlink)sender).NavigateUri.ToString();
IInputElement control = (IInputElement)this.FindName(controlName);
Keyboard.Focus(control);
}
}
}
}
FindName is only one way to find a child control. There are also other ways per this post: WPF ways to find controls.
It is also important to note that WPF distinguishes between Logical Focus and Keybaord Focus: Mark Smith's It's Bascially Focus. In the code above having keyboard focus automatically indicates logical focus.

Related

WPF Window messages not firing while popup window animation is running

I have created a little Popup window in WPF, which shows and hides with a 500 millisecond fade-animation.
The Popup is shown when the PreviewMouseUp of a TextBox control is fired, and hidden when the focus of the TextBox is lost.
The problem is that if I have two of these TextBoxes, the animation of the Popup-window seems to block all Window Messages sent to the main window while the animation is going. The PreviewMouseUp of the second TextBox is fired only right after the animation of the first TextBox's Popup is complete.
Is there a way to make the fade-animation of my Popup Window NOT to block Window Messages while the animation is running?
Example XAML file:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" Margin="22,26,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" PreviewMouseUp="TextBox_PreviewMouseUp_1" LostFocus="TextBox_LostFocus_1"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="22,54,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" PreviewMouseUp="TextBox_PreviewMouseUp_1" LostFocus="TextBox_LostFocus_1"/>
</Grid>
</Window>
Example Code file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TextBox_PreviewMouseUp_1(object sender, MouseButtonEventArgs e)
{
Popup p = new Popup();
p.Width = 100;
p.Height = 100;
p.Placement = PlacementMode.Left;
p.PlacementTarget = (TextBox)sender;
p.Child = new Border();
p.IsOpen = true;
((TextBox)sender).Tag = p;
}
private void TextBox_LostFocus_1(object sender, RoutedEventArgs e)
{
Popup p = (Popup)((TextBox)sender).Tag;
DoubleAnimation anim = new DoubleAnimation(100, 0, new Duration(new TimeSpan(0, 0, 1)));
p.BeginAnimation(WidthProperty, anim);
}
}
}
If you click quickly both textboxes, you notice that the other Popup won't appear (and the textbox doesn't get focus) while the animation is running.
What I have found so far, it seems like if the animation is really intensive (high framefrate), the window messages are blocked until the animation is complete. If I set the application framerate to lower value, like 30FPS, then the problem goes away. But this is not an option for me because I wan't the animations to be as smooth as possible.
This happened because I was animating the margins of the popup window - which generates a lot of window messages when the window size frequently changes. (Which ofcourse jams the whole windows messagepump of the application for the duration of the animation).
So the solution is not to animate the popup itself but a child control of the popup instead (for example a panel), and set the popup to allow transparency so we get the same effect but are actually not animation the actual window size.

Lose focus on textbox when enter is pressed or clicked away

I have a textbox on a canvas. How do I lose the focus (so the caret goes away) when I press enter and/or click on the canvas? My textbox is in a template for a button.
I've tried pretty much everything and it doesn't work:
FocusManager.SetIsFocusScope(mainCanvas, true)
mainCanvas.Focus();
FocusManager.SetFocusedElement(child, parent);
it is interesting that if I use a button it works with KeyBoard.Focus(button) but it doesn't work with a canvas, does anyone know why or have any other suggestion?
The problem with Canvas is that when you click on it, you don't actually get the click event to occur unless you have a background that is not white.
One trick if you want white is to use white -1 or #FFFFFE or if the parent is also white use Transparent. So no one can tell it isn't white.
Now your click event can occur.
Also you need to make it focusable.
MainWindow.xaml
<Window x:Class="TextBoxInCanvas.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid Name="MainGrid">
<Canvas Name="canvas1" Focusable="True" Background="#FFFFFE" MouseDown="canvas1_MouseDown">
<TextBox Height="23" Name="textBox1" Width="120" IsEnabled="True"
Canvas.Left="81" Canvas.Top="115" PreviewKeyDown="textBox1_PreviewKeyDown"/>
</Canvas>
</Grid>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Input;
namespace TextBoxInCanvas
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void canvas1_MouseDown(object sender, MouseButtonEventArgs e)
{
Keyboard.Focus(canvas1);
}
private void textBox1_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (Key.Enter == e.Key)
Keyboard.Focus(canvas1);
}
}
}
How to make the WPF Canvas mouse click event work?
I made a more complete post on my blog.

How to enable KeyBinding for DelegateCommand in Prism 4?

I would like to enable a KeyBinding for a DelegateCommand in a Prism4 desktop application. For example, in my XAML file I have this:
<Grid.InputBindings>
<KeyBinding Gesture="CTRL+A" Command="{Binding Command3}"/>
</Grid.InputBindings>
<StackPanel>
<Button Grid.Row="0" Grid.Column="1" Content="HitMe" prism:Click.Command="{Binding Command3}" />
</StackPanel>
and in my ViewModel I have this:
public DelegateCommand<string> Command3 { get; private set; }
private void ExecuteCommand3(string commandParameter)
{
Debug.WriteLine("ExecuteCommand3");
}
private bool CanExecuteCommand3(string commandParameter)
{
return true;
}
When I press the HitMe button the debug line outputs but pressing CTRL+A has no effect.
I have considered using the CommandReference class from TestMvvmExample2341 but that seems to duplicate the functionality of Prism 4 mechanisms.
Is there a an easy way to have CTRL+A invoke the Command3 in Prism4?
That's it, maybe your problem is related to the Focus in your view, try this:
At runtime set the focus over the Button and then apply the keystroke. Also take a look at these posts:
WPF MVVM KeyBinding not being recognized right away and not always working
http://joyfulwpf.blogspot.com/2009/05/mvvm-commandreference-and-keybinding.html

Design-time problem with custom behaviors and triggers in Silverlight

I have implemented a few custom behaviors and triggers and added them via XAML. They work fine at run time but prevent the Cider designer view from loading at design time, and presumably will cause a problem in Blend too, though I haven't confirmed that.
Here is an overview of what I've implemented for one of the behaviors; hopefully someone can point out what I'm missing.
The behavior looks like this;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interactivity;
namespace MiX.Core.UI.Silverlight
{
public class UpdateOnTextChangedBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.TextChanged += OnAssociatedObjectTextChanged;
}
void OnAssociatedObjectTextChanged(object sender, TextChangedEventArgs e)
{
BindingExpression binding = this.AssociatedObject.GetBindingExpression(TextBox.TextProperty);
if (binding != null)
{
binding.UpdateSource();
}
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.TextChanged -= OnAssociatedObjectTextChanged;
}
}
}
An implementation in XAML looks like this;
<TextBox x:Name="Username" Text="{Binding Username,Mode=TwoWay}" BorderThickness="1" Style="{StaticResource TextBoxStyleGeneral}" Foreground="#FF333333" FontSize="10" BorderBrush="{x:Null}" Grid.Column="1" d:LayoutOverrides="GridBox" Margin="2,0" Grid.ColumnSpan="2" Background="{x:Null}" VerticalAlignment="Center" Grid.Row="1">
<i:Interaction.Behaviors>
<mixcore:UpdateOnTextChangedBehavior/>
</i:Interaction.Behaviors>
</TextBox>
In the XAML editor the <mixcore:UpdateOnPasswordChangedBehavior/> element is highlighted with a squiggly and reports the error A value of type 'UpdateOnTextChangedBehavior' cannot be added to a collection or dictionary of type 'BehaviorCollection'. When attempting to view in the Design view the designer fails to load, stating The document contains errors that must be fixed before the designer can be loaded.
In Silverlight ,If design is not able to load with the changes we made in code then it is bug in silverlight.
Silverlight yet is not designed to handle various exceptions through code,like if you do have any code with return type and you don't check for null there,then again it doesn't load the designer this case is mostly seen with Overriding the IValueConverter method {x:Static} ...and so on
There is nothing wrong in your code unless until it compile fine and doesn't throw exception.
Don't worry about the designer.
Similarly,one case you can look at:
http://connect.microsoft.com/VisualStudio/feedback/details/361509/xaml-designer-cannot-handle-typename-with-nested-classes

Setting CommandTarget to selected control in a TabControl

I have a WPF window with a few buttons and a tabcontrol having a tab for each 'document' the user is working on. The tabcontrol uses a DataTemplate to render the data in ItemSource of the tabcontrol.
The question: If one of the buttons is clicked, the command should be executed on the control rendering the document in the active tab, but I've no idea what I should set CommandTarget to. I tried {Binding ElementName=nameOfControlInDataTemplate} but that obviously doesn't work.
I tried to make my problem a bit more abstract with the following code (no ItemSource and Document objects, but the idea is still the same).
<Button Command="ApplicationCommands.Save" CommandTarget="{Binding ElementName=nestedControl}">Save</Button>
<TabControl x:Name="tabControl">
<TabControl.Items>
<TabItem Header="Header1">Item 1</TabItem>
<TabItem Header="Header2">Item 2</TabItem>
<TabItem Header="Header3">Item 3</TabItem>
</TabControl.Items>
<TabControl.ContentTemplate>
<DataTemplate>
<CommandTest:NestedControl Name="nestedControl"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
I tested the code by replacing the complete tabcontrol with only one single NestedControl, and then the command button just works.
To be complete, here is the code of NestedControl:
<UserControl x:Class="CommandTest.NestedControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Label x:Name="label" Content="Not saved"/>
</Grid>
</UserControl>
And code behind:
public partial class NestedControl : UserControl {
public NestedControl() {
CommandBindings.Add(new CommandBinding(ApplicationCommands.Save, CommandBinding_Executed));
InitializeComponent();
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) {
label.Content = "Saved";
}
}
I don't know exactly how CommandTarget works, but binding to the active tab in a TabControl is done with something like this:
"{Binding ElementName=tabControl,Path=SelectedItem}"
(SelectedItem is the current active tab)
EDIT:
More information about CommandTarget can be found here: Setting Command Target in XAML
EDIT 2:
Deleted my initial answer since it was not an answer to the question.

Resources