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>
Related
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 have the following:
<ListView SelectionMode="Multiple" SelectedIndex="{Binding SelectedIdx}" SelectionChanged="ItemsList_SelectionChanged" MinHeight="200" x:Name="ItemsList" ItemsSource="{Binding Items}" Background="Yellow" Grid.Row="1">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<!-- note that the list mode is wide enough to force a wrap to each new line -->
<WrapPanel Width="{Binding ActualWidth, ElementName=ItemsList}" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<local:Item/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Each individual 'Item' xaml has mousedown callbacks which aren't called but OnMouseOver is.
ItemsList_SelectionChanged is never called either.
The item xaml is pretty basic:
<ListViewItem x:Class="Controls.Item"
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:Controls"
mc:Ignorable="d"
xmlns:ViewModel="clr-namespace:Controls.Controls.Item.ViewModel"
d:DesignHeight="50" d:DesignWidth="50"
Width="50"
Height="50"
Background="Blue"
Padding="0,0,0,0"
MouseLeftButtonDown="ListViewItem_MouseLeftButtonDown">
<!-- <Grid>
< ! - - <Label IsHitTestVisible="False" Width="50" Height="50" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontSize="10" Background="Pink" Content="{Binding Label}"/> - - >
</Grid> -->
</ListViewItem>
Like I said before, 'ListViewItem_MouseLeftButtonDown' doens't get called either but if there's a MouseOver event that does get called.
I believe its because the parent ListViewItem or ListView itself handle the PreviewMouseDown event and mark it as Handled="True".
I have 2 suggestions for you:
Do not use ListViewItem as the ItemTemplate. One is being created to wrap your ItemTemplate anyway.
Write a Behavior to use on your ItemTemplate's Content. The Behavior should register to PreviewMouseDown event and raise a Command(with Binding to it from the ListView's DataContext).
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();
}
I had a question some time ago (this is NO duplicate) as you can see here: WPF Simple DataMatrix.
I asked about creating a matrix of LED lights on screen. I used to that the marked answer and created the matrix. It is displayed very well and I also applied commands on the Ellipse so I can edit the Matrix but also that works without any lag.
As result this is my code for the Matrix:
<ItemsControl x:Class="HTLED.WPF.Controls.LedGrid"
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:Data="clr-namespace:HTLED.Data;assembly=HTLED.Data"
xmlns:Controls="clr-namespace:HTLED.WPF.Controls"
xmlns:Commands="clr-namespace:HTLED.Client.Commands;assembly=HTLED.Client"
xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ViewModel="clr-namespace:HTLED.Client.ViewModel;assembly=HTLED.Client"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance ViewModel:LedContainerViewModel}" Name="ledGridRoot" >
<ItemsControl.Resources>
<DataTemplate x:Key="ledTemplate" DataType="{x:Type Data:Led}">
<Ellipse Name="ellipse" Fill="Green" Stretch="Uniform" SnapsToDevicePixels="True">
<Interactivity:Interaction.Triggers>
<Interactivity:EventTrigger EventName="PreviewMouseMove">
<Commands:CommandTrigger Command="{Binding ElementName=ledGridRoot, Path=DataContext.LedGridViewModel.LedMouseMoveCommand}" PassEventArgsToCommand="True"/>
</Interactivity:EventTrigger>
<Interactivity:EventTrigger EventName="PreviewMouseLeftButtonDown">
<Commands:CommandTrigger Command="{Binding ElementName=ledGridRoot, Path=DataContext.LedGridViewModel.LedOnCommand}" PassEventArgsToCommand="True"/>
</Interactivity:EventTrigger>
<Interactivity:EventTrigger EventName="PreviewMouseRightButtonDown">
<Commands:CommandTrigger Command="{Binding ElementName=ledGridRoot, Path=DataContext.LedGridViewModel.LedOffCommand}" PassEventArgsToCommand="True"/>
</Interactivity:EventTrigger>
</Interactivity:Interaction.Triggers>
</Ellipse>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=State}" Value="Off">
<Setter TargetName="ellipse" Property="Fill" Value="Red"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{StaticResource ledTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Controls:StretchStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In the background I have a class called LedMatrix. It has a property with the collection of the leds:
ObservableCollection<ObservableCollection<Led>> _leds;
public ObservableCollection<ObservableCollection<Led>> Leds
{
get { return _leds ?? (_leds = CreateMatrix(XSize, YSize)); }
set { SetProperty(value, ref _leds, () => Leds); }
}
The matrix is contained by another control:
<Canvas x:Class="HTLED.WPF.Controls.LedContainer"
....
mc:Ignorable="d"
d:DataContext="{d:DesignInstance ViewModel:LedContainerViewModel}"
d:DesignHeight="300" d:DesignWidth="300" Name="layoutRoot" Drawing:DrawingCore.EnableDrawing="True">
<Viewbox Canvas.Top="0" Canvas.Left="0" Width="{Binding ElementName=layoutRoot, Path=ActualWidth}"
Height="{Binding ElementName=layoutRoot, Path=ActualHeight}">
<Grid>
<Controls:LedGrid Width="50000" Height="25000" Margin="500" DataContext="{Binding Path=Main.LedContainerViewModel}" ItemsSource="{Binding Path=LedContentContainer.Content}" />
</Grid>
</Viewbox>
As you can see I set the ItemsSource of the Matrix in the container. That Itemssource Is a Interface like this:
public interface ILedContentContainer
{
LedMatrix Content { get; set; }
}
And the LedMatrix I already showed before (the ObservableCollection<ObservableCollection<Led>>).
And now the very important:
I have the change the LedMatrix (the Itemssource of LedGrid - see LedGridContainer) very often because it is some kind of an animation. The problem is that that all is very very slow. So I wanted to ask if you know some optimations?
Again I have to change the LedMatrix very very fast.
If you apply a whole new ObservableCollection each time as Led changes, the complete grid has to be rendered again and again. You should change the State property of the Led's that are changing (they should fire PropertyChanged).
Also, if the amount of Led's is constant, you don't need an ObservableCollection at all. You can use any IEnumerable.
I've got the following user-control:
Resources:
<DataTemplate x:Key="FilterComboDataTemplate">
<Label Content="{Binding Item2}" />
</DataTemplate>
<Style x:Key="FilterSelectorStyle" TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Filters}" />
<Setter Property="SelectedItem" Value="{Binding SelectedFilter}" />
<Setter Property="ItemTemplate" Value="{StaticResource FilterComboDataTemplate}" />
</Style>
Control Body:
<DockPanel>
<Label DockPanel.Dock="Top">
Select your filter/value to apply:
</Label>
<ComboBox Style="{StaticResource FilterSelectorStyle}" />
<StackPanel>
<!-- TODO: Fix Combobox First -->
</StackPanel>
</DockPanel>
It's inside a <Window> and opened using .ShowDialog(), this is what happens to the items when I click on the button:
Undesirable Results http://img827.imageshack.us/img827/1561/whyowhy.png
I'm at a complete loss as to why this is happening, I've checked the visual tree, everything's where it should be. I'm baffled. Anyone out there experienced strange behavior like this? Why are my items at 0,0 on my desktop instead of attached to my combobox?
I quickly coded this. Didn't have any problem.
<Window
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:WpfApplication5="clr-namespace:WpfApplication5" x:Class="WpfApplication5.MainWindow"
x:Name="MyWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="FilterComboDataTemplate">
<Label Content="{Binding Item2}" />
</DataTemplate>
</Window.Resources>
<DockPanel>
<Label DockPanel.Dock="Top">
Select your filter/value to apply:
</Label>
<ComboBox Height="32" ItemsSource="{Binding Filters, ElementName=MyWindow}" ItemTemplate="{DynamicResource FilterComboDataTemplate}"/>
<StackPanel>
<!-- TODO: Fix Combobox First -->
</StackPanel>
</DockPanel>
</Window>
Also, I've never seen any one putting ItemSource and SelectedItem in a style. I don't think that's a good WPF practice. I will rather bind to a ICollectionView which allows grouping, filtering, managing cursor etc