How to active UserControl outside the wrapper? - wpf

I met a Focus related problem in UserControl:
Suppose we have a UserControl like this:
<UserControl x:Class="_20130826.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<ListBox>
<ListBoxItem>
<TextBlock Text="text1" />
</ListBoxItem>
<ListBoxItem>
<TextBlock Text="text2" />
</ListBoxItem>
<ListBoxItem>
<TextBlock Text="text3" />
</ListBoxItem>
<ListBoxItem>
<TextBlock Text="text4" />
</ListBoxItem>
</ListBox>
</StackPanel>
</UserControl>
And the MainWindow.xaml like this:
<Window x:Class="_20130826.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:temp="clr-namespace:_20130826"
Title="MainWindow">
<StackPanel>
<Button Content="Deactive UserControl" />
<StackPanel>
<Button Name="Button1" Content="Active UserControl" />
<ContentControl>
<temp:UserControl1 />
</ContentControl>
</StackPanel>
</StackPanel>
</Window>
Step 1: Click text1 TextBlock inside UserControl, and default the
background changes to deeper.
Step 2: Click 'Deactive UserControl' button, so the text1 background
turns to lighter.
Step 3: Click 'Active UserControl' button, then ...
I want the text1 background changed to deeper, which means the UserControl has been focused/actived.
How can I achieve this?

If you want to set the Focus to the UserControl when the Button("Active UserControl") gets pressed, we can add a Click event handler and assign focus to the UserControl.
So say something like:
<Window x:Class="_20130826.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:temp="clr-namespace:_20130826"
Title="MainWindow">
<StackPanel>
<Button Content="Deactive UserControl" />
<StackPanel>
<Button Name="Button1" Content="Active UserControl" Click="Button1_OnClick" />
<ContentControl>
<temp:UserControl1 x:Name="myUserControl" />
</ContentControl>
</StackPanel>
</StackPanel>
</Window>
and in MainWindow.xaml.cs:
private void Button1_OnClick(object sender, RoutedEventArgs e) {
FocusManager.SetFocusedElement(this, myUserControl);
}
Now when you click the "Active UserControl" Button, Focus will switch to the UserControl. However this will not give you that "deeper" state on the ListBoxItem as it still doesnt have Focus. So to sort that
In UserControl1.xaml.cs add:
protected override void OnGotFocus(RoutedEventArgs e) {
base.OnGotFocus(e);
if (!Equals(e.OriginalSource, this))
return;
TraversalRequest tRequest = new TraversalRequest(FocusNavigationDirection.Next);
MoveFocus(tRequest);
}
What this does is when the UserControl gets focus, it moves Focus to the next element within it which would be the element you clicked initially.
You can get a demo of your code tweaked with this: Here

Related

Set binding on button tooltip with a declared instance of a user control as source

I've added a user control (with labels and textboxes) to my WPF project shown here:
<UserControl x:Class="MyProject.myControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="384" Width="543">
<Grid x:Name="_LabelServerURL">
<Label x:Name="_LabelServerUrl" Content="Server Url:" HorizontalAlignment="Left" Margin="60,21,0,0" VerticalAlignment="Top" FontWeight="Bold"/>
<TextBox x:Name="_TextboxUrl" HorizontalAlignment="Left" Height="23" Margin="158,22,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="235"/>
<Label x:Name="_LabelURLExample" Content="(https://promodel.com)" HorizontalAlignment="Left" Margin="398,21,0,0" VerticalAlignment="Top" Width="139"/>
</Grid>
</UserControl>
and have created an instance of that user control in my main window code behind.
public partial class MainWindow : Window
{
private myControl _settings = new myControl();
public MainWindow()
{
InitializeComponent();
AddStackPanelChildren();
_ButtonEPSSettings.ToolTip = _epsSettings;
//SetButtonTootips();
}
In my main window I have a list of buttons, and I want to set their tooltip property (or bind the tooltip property) to the instance of my user control so that the tooltip dynamically updates when I add values to the textboxes in my user control. So far in my main window xaml I've been able to show my user control as the tooltip shown here:
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls ="clr-namespace:MyProject" <!--Declare project namespace-->
Title="EPS Configuration Manager" Height="415" Width="766">
<Grid>
<Button x:Name="_ButtonSettings"
Content="EPS Settings"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="199"
HorizontalContentAlignment="Left"
BorderThickness="0"
Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" Click="_ButtonSettings_Click"
>
<Button.ToolTip>
<ToolTip>
<StackPanel HorizontalAlignment="Left" Height="384" Margin="0,0,0,0" VerticalAlignment="Top" Width="543" Name="_StackPanelEPSSettings">
<Controls:myControl/>
</StackPanel>
</ToolTip>
</Button.ToolTip>
</Button>
I am still not clear on setting that tooltip as the instance of my user control as declared in my main window code behind. Any help will go a long way. Thanks.
If you set tooltips in backgroud, don't use these code:
<Button.ToolTip>
<ToolTip>
<StackPanel HorizontalAlignment="Left" Height="384" Margin="0,0,0,0" VerticalAlignment="Top" Width="543" Name="_StackPanelEPSSettings">
<Controls:myControl/>
</StackPanel>
</ToolTip>
</Button.ToolTip>
If you want the tooltip dynamically updates:
private myControl mytooltip = new myControl();
public MainWindow()
{
InitializeComponent();
AddStackPanelChildren();
mytooltip._TextboxUrl.Text = "Hello";
_ButtonEPSSettings.ToolTip = mytooltip;
//SetButtonTootips();
}

XAML: move the cursor in textbox automatically

I dont know if this works but is there any chance to move the cursor inside a Textbox automaticaly for one position(1 space bar click). For example:
I run the application and the cursor inside the Textbox moves automatically for one space bar
my textbox:
<TextBox TextChanged="Searchbox_TextChanged" x:Name="Testing" Margin="2" Grid.Row="1" Text="{Binding SearchSmthg, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Controls:TextboxHelper.ClearTextButton="True" Controls:TextboxHelper.Watermark="Search ..."/>
use CaretIndex and FocusManager:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid FocusManager.FocusedElement="{Binding ElementName=Focustext}">
<TextBox x:Name="Focustext" Text=" " CaretIndex="1" MaxHeight="25" />
</Grid>
</Window>
Edit: add a GotFocus event handler and set CaretIndex=1 there
XAML:
<TextBox GotFocus="Testing_GotFocus"
Code Behind:
private void Testing_GotFocus(object sender, RoutedEventArgs e)
{
//make sure your Textbox is not empty..
Testing.CaretIndex = 1;
}

Click event is not raised for Button in popup on datagrid

I'am quite new with WPF and still trying to figure it out in all its details ;)
I have a strange issue with the button not raising its click event. I have a UserControl called PopupButton which is basically a button with a popup showed on click. The content of the popup is ContentPresenter and is binded to the dependency property called PopupContentHolder on the PopupButton.
Then on the main form I have a DataGrid with DataGridTemplateColumn where in the <DataGridTemplateColumn.CellTemplate> <DataTemplate> I placed my PopupButton. Then I assign a list box with an ItemTemplate as the content of the popup for my PopupButton.
In simple this looks as follows
<DataGrid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
ColumnHeaderHeight="40"
FontSize="11"
HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Pocos}"
RowHeight="30"
SnapsToDevicePixels="True"
VerticalScrollBarVisibility="Disabled">
<DataGrid.Columns>
<DataGridTemplateColumn MinWidth="70" Header="NAme">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:PopupButton DoPopupOnMainButton="True"
Foreground="{StaticResource HeaderLinkActiveColor}"
MarkButtonOnPopup="True"
PopupBackground="{StaticResource PopupBackground}"
PopupPadding="5"
ShowDownArrow="False"
Text="Some test button">
<controls:PopupButton.PopupContentHolder>
<StackPanel>
<ListBox Background="Transparent" ItemsSource="{Binding Tenders}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Margin="0,2,0,0"
Click="Button_Click"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},
Path=DataContext.SaveCommand}"
Content="{Binding .}"
FontSize="11" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</controls:PopupButton.PopupContentHolder>
</controls:PopupButton>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
Now the problem is with the button inside the ListBox in PopupButton, Neither Click event nor Command is raised. Moreover when I put the PopupButton outside the DataGrid then everythinkg works perfect. Also when I put above list box directly in grid cell then it works.
Maybe its something wrong with my PopupButtonControl.
<UserControl x:Class="WpfApplication1.PopupButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="userControlRoot"
Width="Auto"
Height="Auto">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<Storyboard x:Key="PopupCloseStoryBoard">
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="popup" Storyboard.TargetProperty="IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0.1" Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="PopupOpenStoryBoard">
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="popup" Storyboard.TargetProperty="IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0.0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Grid>
<Border x:Name="brdButtonBack"
Background="Transparent"
CornerRadius="3,3,0,0"
Padding="{Binding Padding,
ElementName=userControlRoot}" />
<Button x:Name="btnMain"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Click="btn_Click"
Command="{Binding MainCommand,
ElementName=userControlRoot}"
Content="{Binding Text,
ElementName=userControlRoot}"
IsEnabled="{Binding IsEnabled,
ElementName=userControlRoot}" />
<Popup x:Name="popup"
MinWidth="{Binding ActualWidth,
ElementName=userControlRoot}"
AllowsTransparency="True"
Placement="Bottom"
PlacementTarget="{Binding ElementName=brdButtonBack}"
PopupAnimation="Slide"
StaysOpen="False">
<Border Background="{Binding PopupBackground,
ElementName=userControlRoot}"
BorderBrush="White"
CornerRadius="0,3,3,3"
Padding="{Binding PopupPadding,
ElementName=userControlRoot}">
<ContentPresenter Content="{Binding PopupContentHolder, ElementName=userControlRoot}" />
</Border>
</Popup>
</Grid>
I have simplified the control but the problem reproduces with that version too. The code behind for the control mostly contains dependency properties, the only logic is shown below
public partial class PopupButton : UserControl
{
//... dependency properties
public PopupButton()
{
InitializeComponent();
}
private void btn_Click(object sender, RoutedEventArgs e)
{
Storyboard s = (Storyboard)TryFindResource("PopupOpenStoryBoard");
s.Begin();
}
private void popup_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
//trick to close popup when the button inside is clicked
//this must be done with storyboard and delay
//since popup can not be closed before the event reaches clicked
//button
if (e.Source is Button)
{
Storyboard s = (Storyboard)TryFindResource("PopupCloseStoryBoard");
s.Begin();
}
}
}
Has anyone any clue what can be wrong with it?
Thanks.
I did finally solve this by rewriting PopupButton as CustomControl. There, instead of firing StoryBoard to close the popup, when the contained button is clicked I used following code
mainPopup.AddHandler(Button.ClickEvent, new RoutedEventHandler(mainPopup_ButtonClick), true);
Adding a button click handler for main popup, which will be called on the popup even if the event is already handled by the source button.
void mainPopup_ButtonClick(object sender, RoutedEventArgs e)
{
MainPopup.IsOpen = false;
}
More info about handling already handled routed events here
Maybe it is just a typo because there is a btn_Click and Button_Click event handler in your code.
Would you mind providing the code of the PopupContentHolder or maybe the whole PopupButton class?

mvvm navigation treeview

i'm trying to implement a navigation menu using a treeview.
on the left panel there is a treeview and on the right panel the matched view.
since it's MVVM i'm having a difficult to switch between the correct views.
clicking on Menu1 - should display View1.xaml view
clicking on Menu2 - should display View2.xaml view
my code looks like that:
MainView.xaml
<Window x:Class="Menu.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Views="clr-namespace:Menu.View"
Title="MainView" Height="300" Width="300">
<Window.Resources>
<DataTemplate DataType="{x:Type Views:Page1}">
<Views:Page1 />
</DataTemplate>
<DataTemplate DataType="{x:Type Views:Page2}">
<Views:Page2 />
</DataTemplate>
</Window.Resources>
<DockPanel>
<Grid DockPanel.Dock="Left">
<TreeView>
<TreeViewItem Header="Menu 1" />
<TreeViewItem Header="Menu 2" />
<TreeViewItem Header="Menu 3" />
</TreeView>
</Grid>
<Grid DockPanel.Dock="Right">
<Views:Page1 />
<Views:Page2 />
</Grid>
</DockPanel>
</Window>
Page1.xaml (the view that should be visible when clicking "Menu 1")
<Grid>
<Label FontSize="24" FontWeight="Bold">1</Label>
</Grid>
Page2.xaml (the view that should be visible when clicking "Menu 2")
<Grid>
<Label FontSize="24" FontWeight="Bold">2</Label>
</Grid>
for every page i have its own ViewModel and i have the main one called MainViewModel.
how should i implement such thing in a MVVM mode ?
I think here is the mistake. You should have put your ViewModels in the DataType. so when you fill the DataContext the DataTemplate do his job. something like :
<DataTemplate DataType="{x:Type ViewModels:Page1ViewModel}">
<Views:Page1 />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:Page2ViewModel}">
<Views:Page2 />
</DataTemplate>
instead of :
<Views:Page1 />
<Views:Page2 />
add a ContentControl and do a binding to it's content like this :
<ContentControl Content="{Binding MyViewModel}"></ContentControl>
myView is property in your MainViewViewModel (which has to implement INotifyPropertyChanged) can be like this :
object _MyView;
public object MyViewModel
{
get
{
return _MyView;
}
set
{
_MyView = value;
OnPropertyChanged("MyViewModel");
}
}
now, in each TreeViewItem add a Command that do update it's Content for ex :
in your MainViewViewModel add CallView1Command property and implement it (see how dealing with commands)
so in Command's excute method you can update MyViewModel according to the View you want to show.
I recommend using Unity to instanciate ViewModels.
Not very well explained, but, Hope it helps anyway

WPF Focus Navigation Wrapping

Is there a way to force Focus Navigation (as controlled by the Tab key or MoveFocus method) to wrap inside a given container? I have included code which demonstrates this problem below. What is the easiest way to make Tab move focus from TextBox "Charlie" to TextBox "Able" (and visa-versa for Shift+Tab on TextBox "Able") rather than moving it to MenuItem "Alpha"?
<Window x:Class="NavWrapExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<DockPanel LastChildFill="True">
<Menu DockPanel.Dock="Top">
<MenuItem Header="Alpha" />
<MenuItem Header="Bravo" />
<MenuItem Header="Charlie" />
</Menu>
<StackPanel>
<TextBox Text="Able" />
<TextBox Text="Baker" />
<TextBox Text="Charlie" />
</StackPanel>
</DockPanel>
</Window>
Use the KeyboardNavigation.TabNavigation attached property, like so:
<StackPanel KeyboardNavigation.TabNavigation="Cycle">
<TextBox Text="Able" />
<TextBox Text="Baker" />
<TextBox Text="Charlie" />
</StackPanel>
Found the answer on Mark Smith's blog.
It sounds like what you want is the same behavior as toolbars: you can tab into them, but once an element within the toolbar gets keyboard focus, focus loops inside. If so, use FocusManager as follows:
<StackPanel FocusManager.IsFocusScope="True">
<!-- Controls go here... -->
</StackPanel>

Resources