I've looked into several methods of setting focus and nothing appeared to work. I'm sure someone out there has a solution to this. It's such a simple task.
I want to set the focus of the textbox which appears in the context menu when the user right-clicks on the listbox. I don't want the user to have to click the textbox each time they right-click.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
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"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox>
<ListBox.ContextMenu>
<ContextMenu>
<ContextMenu.Template>
<ControlTemplate>
<Border BorderThickness="2" BorderBrush="sc#1,.1,.1,.1" CornerRadius="4"
Background="sc#1,.05,.05,.05">
<TextBox Grid.Row="0" Margin="4" MinWidth="150" Name="SearchBox" VerticalAlignment="Center">
</TextBox>
</Border>
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
</Grid>
</Window>
IsFocused property of TextBox is read only. This forces the use of method in our case.
You need CallMethodAction behavior. Good tutorial to start with.
<TextBox Grid.Row="0" Margin="4" MinWidth="150" Name="SearchBox" VerticalAlignment="Center">
<i:Interaction.Triggers>
<ei:PropertyChangedTrigger Binding="{Binding IsOpen, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}">
<ei:CallMethodAction MethodName="FocusSearchBox" TargetObject="{Binding DataContext, ElementName=SearchBox}"/>
<ei:ChangePropertyAction PropertyName="Background" Value="Purple"/>
</ei:PropertyChangedTrigger>
</i:Interaction.Triggers>
</TextBox>
public void FocusSearchBox()
{
TextBox t = (TextBox) CtxMenu.ContextMenu.Template.FindName("SearchBox", CtxMenu.ContextMenu);
t.Focus();
}
Related
My problem is when I'm adding command to button, which is located in ListBoxItem Style in Page.Reosources and click it, nothing happen. But if I add button in default grid, command will work.
XAML:
<Page x:Class="kkRedux.MVVM.View.SpecialView"
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"
xmlns:local="clr-namespace:kkRedux.MVVM.View"
xmlns:viewModel="clr-namespace:kkRedux.MVVM.ViewModel"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="SpecialView">
<Page.DataContext>
<viewModel:SpecialViewModel />
</Page.DataContext>
<Page.Resources>
<Style TargetType="ListBoxItem" x:Key="DieStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Margin="11">
<Button Content="Click Mey"
Width="100" Height="100"
Background="Black"
Command="{Binding DownloadCommand}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ItemsPanelTemplate x:Key="panelTemplate">
<WrapPanel />
</ItemsPanelTemplate>
</Page.Resources>
<Grid>
<!--ItemsSource ommited-->
<ListBox Name="specialListBox"
ItemContainerStyle="{StaticResource DieStyle}"
ItemsPanel="{StaticResource panelTemplate}"
Background="Transparent"/>
<!--this Command is working-->
<Button Content="Click"
Height="100" Width="100"
Command="{Binding DownloadCommand}"/>
</Grid>
</Page>
ViewModel:
internal class SpecialViewModel
{
public RelayCommand DownloadCommand { get; set; }
public SpecialViewModel()
{
DownloadCommand = new RelayCommand<string>(o => Download(o));
}
private void Download(string arg)
{
MessageBox.Show(arg);
}
}
P.S. Click's working fine, but I can't use it due to MVVM.
Bind to the DataContext of the parent Page:
Command="{Binding DataContext.DownloadCommand,
RelativeSource={RelativeSource AncestorType=Page}}"
The default DataContext the element in the ListBox is the current item in the Items collection of the ListBox. That's why your binding doesn't work.
I have a simple page that allows me to associate names with bunks. Unfortunately tab isn't working as I expect. I have to tab once to get to the next item and again to get to the TextBox. This also occurs if I remove the Label control. I've searched and searched and tried a bunch of things but can't figure this one out. Any suggestions? I'm starting to get comfortable with WPF MVVM but I'm no expert.
<Page x:Class="DiverBoard.Views.ConfigurePage"
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"
xmlns:vm="clr-namespace:DiverBoard.ViewModels"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="800"
Title="ConfigurePage" Background="Navy">
<Page.DataContext>
<vm:TripViewModel/>
</Page.DataContext>
<WrapPanel>
<ListBox Background="Navy" ItemsSource="{Binding Trip.Bunks}" KeyboardNavigation.TabNavigation="Cycle">
<ListBox.Template>
<ControlTemplate>
<DockPanel LastChildFill="True">
<ItemsPresenter></ItemsPresenter>
</DockPanel>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label FontSize="18" Foreground="white" Content="{Binding Value.BunkNumber}" Width="50"></Label>
<TextBox FontSize="18" Text="{Binding Value.DiverName}" Width="200" IsTabStop="true"></TextBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</WrapPanel>
</Page>
Naturally I figured it out right after posting a question by reading something again that I had already read.
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsTabStop" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
I have a strange problem in my simple application window when trying to set font size for all controls on it. Some controls inherit the font size from parent window, another (Menu, StatusBar) don't.
I expected that setting the FontSize property value for the window will propagate down the element tree. But for some controls it does not work.
Why? Is there any explanation for this? Is there any error in my code?
NOTE: There is no code behind.
MainWindow.xaml
<Window x:Class="WpfApp.MainWindow"
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"
xmlns:local="clr-namespace:WpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="340" Width="300"
FontSize="24" >
<StackPanel>
<Label Content="Hello! " />
<Menu DockPanel.Dock="Top" Margin="10">
<MenuItem Header="File"/>
<MenuItem Header="Edit"/>
<MenuItem Header="View"/>
<MenuItem Header="Help"/>
</Menu>
<ListBox Margin="10">
<ListBoxItem>Chapter 1</ListBoxItem>
<ListBoxItem>Chapter 2</ListBoxItem>
</ListBox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Margin="5" Padding="5" Content="Help"/>
<Button Margin="5" Padding="5" Content="OK" />
</StackPanel>
<StatusBar Margin="10">
<Label>Status Bar</Label>
<Separator/>
<Label>Zoom</Label>
<ComboBox SelectedIndex="0">
<ComboBoxItem>100%</ComboBoxItem>
<ComboBoxItem>75%</ComboBoxItem>
<ComboBoxItem>50%</ComboBoxItem>
<ComboBoxItem>25%</ComboBoxItem>
</ComboBox>
</StatusBar>
</StackPanel>
</Window>
On the picture below the menu and the status bar are not inherit the
font size:
Some WPF controls like Menu and StatusBar explicitly set the FontSize property in their default styles.
Menu.xaml
<Style x:Key="{x:Type Menu}" TargetType="{x:Type Menu}">
...
<Setter Property="FontSize"
Value="{DynamicResource {x:Static SystemFonts.MenuFontSizeKey}}"/>
...
</Style>
This is why inheritance is breaking.
If a property is set explicitly it will not inherit a value.
The only way around this is to override the default styles.
I would like to bind a property from a nested UserControl to my MainWindow.
I'm already using a similar structure for other things but this is a bit different:
-MainWindow
--Ribbon
---RibbonButton <-- the button I would like to disable
--/Ribbon
--UserControl1 - not directly the control I want bind to
---UserControl2 - nested user control, sitting inside the above one
----TextBox <-- Bind the RibbonButton to the Text property. Disable the button when TextBox empty
---/UserControl2
--/UserControl
-/MainWindow
So, the usual combination of Elementname and Path doesn't work here obviously. Is DataContext the way to go here? The UserControls are in separate files and so is the MainWindow. Or should I do this in code-behind?
Some of the code I'm having there:
MainWindow
<RibbonWindow.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</RibbonWindow.Resources>
...
<RibbonGroup Header="Import">
<RibbonButton x:Name="mplImpFromForum" Label="From forum" FontSize="12" LargeImageSource="Icons/General/Icon8_download_72px.png" Click="mplImpFromForum_Click"/>
<RibbonButton x:Name="mplImpManual" Label="Manual import" SmallImageSource="Icons/General/Icon8_whole_hand_32px.png"}>
<RibbonButton.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=frmLogin, Path=}"
// here lies my problem
</Style.Triggers>
</Style>
</RibbonButton.Style>
</RibbonButton>
</RibbonGroup>
</RibbonTab>
</Ribbon>
<Viewbox Grid.Row="1" Panel.ZIndex="1" MaxHeight="200" MaxWidth="200">
<local:frmLogin x:Name="frmLogin" Loaded="frmLogin_Loaded" Grid.Row="1"/>
</Viewbox>
<local:frmMPLMain x:Name="frmMPLMain" Grid.Row="1"/> // "Source UserControl, "parent
to the real target.
The first nested UserControl
<UserControl x:Class="Fever_Tool_WPF.frmMPLMain"
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"
xmlns:local="clr-namespace:Fever_Tool_WPF"
mc:Ignorable="d"
x:Name="MPLRoot"
d:DesignHeight="500" d:DesignWidth="1000">
...
<local:frmMPLImp x:Name="frmMPLImp" Grid.Column="2" Grid.ColumnSpan="4" Grid.RowSpan="6"/>
// The second UserControl, this one contains the TextBox I want to take as a source
<DataGrid HeadersVisibility="None" Grid.RowSpan="3" Grid.ColumnSpan="2"></DataGrid>
</Grid>
The second UserControl
<UserControl x:Class="Fever_Tool_WPF.frmMPLImp"
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"
xmlns:local="clr-namespace:Fever_Tool_WPF"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="1000">
<UserControl.Resources>
<Style x:Key="uiMPLImpBaseStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Margin" Value="5"/>
</Style>
</UserControl.Resources>
...
<TextBox x:Name="txtMPLImport" Style="{StaticResource uiMPLImpBaseStyle}" Grid.Row="2" Grid.ColumnSpan="4"/>
// This is the textbox I would like to check.
...
</Grid>
I have a small application to help myself learn WPF and MVVM etc. I have been using the example by Josh Smith found here to construct my own application. I have got the application adding TabItems, but the embedded DataGrid which is bound to an ObservableCollection<ResourceViewModel> is not showing any data, see the image below:
The DataGrid is the section surrounded in blue. The UserControl also seems to be showing the in the tab itself for some reason, but that is not the problem I am asking about here. The UserControl contains a DataGrid which is bound as follows
<DataGrid ItemsSource="{Binding Resources}"
dataAccess:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox,
Path=Text, UpdateSourceTrigger=PropertyChanged}"
AlternatingRowBackground="Gainsboro"
AlternationCount="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
...</DataGrid>
The Resources property is defined in the ViewModels namespace as
internal class ResourceDataViewModel : WorkspaceViewModel
{
readonly ResourceDataRepository resourceRepository;
public ObservableCollection<ResourceViewModel> Resources { get; private set; }
...
}
Where the ResourceViewmodel holds the information for each row of the DataGrid. I can confirm that the Resource property is populated. When I use the same model outside of MVVM and populate Resource in the same way it works. Can someone provide me with and idea of why this could be happening?
I have attempted to set the explicit path for the binding
ItemsSource="{Binding Path=(viewModels:Resources)}"
but this also does not work. Thanks for your time.
Edit. To address comments. I set the DataContext in the App.xaml.cs file by
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
// Create the ViewModel to which
// the main window binds.
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
// When the ViewModel asks to be closed,
// close the window.
EventHandler handler = null;
handler = delegate
{
mainWindowViewModel.RequestClose -= handler;
window.Close();
};
mainWindowViewModel.RequestClose += handler;
// Allow all controls in the window to
// bind to the ViewModel by setting the
// DataContext, which propagates down
// the element tree.
window.DataContext = mainWindowViewModel;
window.Show();
}
The XAML of the MainWindow:
<Window x:Class="ResourceStudio.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
Title="MainWindow" Height="629.4" Width="814.4">
<Window.Resources>
<ResourceDictionary Source="MainWindowResources.xaml" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="284*"/>
<ColumnDefinition Width="567*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<DockPanel KeyboardNavigation.TabNavigation="None"
Background="#FFBEC8D8"
Grid.ColumnSpan="2"
Margin="0,0,0.4,0">
<Menu DockPanel.Dock="Top"
Background="#FFF9F9F9"
BorderBrush="Black"
KeyboardNavigation.TabNavigation="Cycle">
<MenuItem Header="_File">
<MenuItem Header="Load _Resource..."
Height="Auto"
Command="{Binding LoadResourceCommand}"/>
<MenuItem Header="_Add Language..."
Height="Auto"/>
<Separator/>
<MenuItem Header="Close _Workspace"
Height="Auto"
Command="{Binding CloseCommand}"/>
<MenuItem Header="E_xit"
Height="Auto" Command="{Binding CloseCommand}" />
</MenuItem>
<MenuItem Header="_Edit">
</MenuItem>
</Menu>
<ToolBarTray DockPanel.Dock="Top" MaxHeight="24" Background="#FFF9F9F9">
<ToolBar Background="#FFF9F9F9">
<Button ToolBar.OverflowMode="Never">One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ToolBar>
</ToolBarTray>
</DockPanel>
<Grid Grid.Row="1" Grid.ColumnSpan="2" Margin="0,0,0.4,23.6" Grid.RowSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabControl ItemsSource="{Binding Path=Workspaces}"
Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
TabStripPlacement="Top"
Height="Auto"
Width="Auto">
</TabControl>
</Grid>
<StatusBar Grid.Row="2" Grid.ColumnSpan="2" Margin="0,0.4,0.4,-0.4">
<StatusBarItem DockPanel.Dock="Left" Background="#FF007ACC" Margin="0,2,0,0">
<TextBlock Text="Ready" Margin="5,0,0,0"/>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
Where the MainWindowResources.xaml is:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
>
<!--This template applies a ResourceControl view to an instance of the
ResourceDataViewModel class shown in the main window.-->
<DataTemplate DataType="{x:Type viewModels:ResourceDataViewModel}">
<views:ResourceControl/>
</DataTemplate>
<!--This template explains how to render the 'Workspace'
content area in the main window.-->
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"/>
</DataTemplate>
</ResourceDictionary>
The full code for the ResourceControl.xaml is:
<UserControl x:Class="ResourceStudio.Views.ResourceControl"
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"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:dataAccess="clr-namespace:ResourceStudio.DataAccess"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Name="control">
<DockPanel DataContext="{Binding ElementName=control}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBox Text="M" DockPanel.Dock="Top" Name="searchBox" />
<Grid DockPanel.Dock="Top">
<Border BorderBrush="#FF007ACC" BorderThickness="2" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<DataGrid ItemsSource="{Binding Path=(viewModels:Resources)}"
dataAccess:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
AlternatingRowBackground="Gainsboro" AlternationCount="2" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<DataGrid.Resources>
<dataAccess:SearchValueConverter x:Key="searchValueConverter"/>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="dataAccess:DataGridTextSearch.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource searchValueConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
<Binding RelativeSource="{RelativeSource Self}" Path="(dataAccess:DataGridTextSearch.SearchValue)" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="dataAccess:DataGridTextSearch.IsTextMatch" Value="True">
<Setter Property="Background" Value="Orange" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#FF007ACC"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
</Border>
</Grid>
</DockPanel>
</UserControl>
The TextBox is bound to the DataGrid. When the user types into that TextBox the DataGrid filters and highlights the cells which contains the required text. This however, is not the problem and this code works, it is just the binding to the DataGrid I am interested in. Thanks again for tour time.
Edit2: According to #dkozl's comments I have removed the DataContext="{Binding ElementName=control}" from the DockPanel declaration, so we now have
<DockPanel HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
...
and in the MainWindowResource.xaml I now have
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
>
<!--This template applies a ResourceControl view to an instance of the
ResourceDataViewModel class shown in the main window.-->
<DataTemplate DataType="{x:Type viewModels:ResourceDataViewModel}">
<views:ResourceControl DataContext="{Binding}"/>
</DataTemplate>
<!--This template explains how to render the 'Workspace'
content area in the main window.-->
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"/>
</DataTemplate>
</ResourceDictionary>
This has not worked. That is my DataGrid in the ResourceControl is not being populated. Thanks again for your time it is most appreciated...
Your UserControl DockPanel.DataContext is bound to ResourceControl control and not to ResourceDataViewModel class. What you need to do instead is to bind DataContext of ResourceControl in your DataTemplate. To achive that first remove DataContext="{Binding ElementName=control}" from ResourceControl.DockPanel and then bind ResourceControl.DataContext to your object by <views:ResourceControl DataContext={Binding}"/>. Also you need to change DataGrid items binding from ItemsSource="{Binding Path=(viewModels:Resources)}" to ItemsSource="{Binding Path=Resources}".
Not part of the original question but same template applies to tab header and tab content because DataTemplate is type specific and in this case tab header content and tab content is the same thing. To solve the issue remove DataTemplate for viewModels:ResourceDataViewModel type and put this directly into your main TabControl:
<TabControl.ContentTemplate>
<DataTemplate>
<views:ResourceControl DataContext={Binding}"/>
</DataTemplate>
</TabControl.ContentTemplate>