Strange ComboBox Behaviour - WPF - c#

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

Related

How to tab once instead of twice in WPF

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>

The ability to propagate default values down the element tree doesn't work

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.

ListViewItem not receiving OnMouseDownEvent and ListView not calling selection changed callback

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).

How can I get the current datacontext from my control

I have a listbox that contains a control chooser I'm trying to develop. Basically, the datasource is XML and I want to read the current context to decide which element control to display.
For this purpose I want to grab the XmlDataProvider with the current item's context, and evaluate that XML. Within XAML I would write {Binding Path=#label} to retrieve a label attribute from the curretn XML element. From code behind, I cant even figure where to get this XML, as it's passed to the class by the list control to this control, but not as an accessible property so far as I can find.
Anyway getting #label isn't sufficient; I want the XmlElement object in class ControlChooser, instantiated below.
<ListBox
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding XPath=*[not(self::units)]}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<W3V:ControlChooser/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<!-- Force the items to fill all available space. -->
<Style TargetType="ListBoxItem">
<Setter
Property="VerticalContentAlignment"
Value="Stretch"
/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Or, if you can suggest another way to get the job (switching what control is displayed) done....
You can use multiple DataTemplates to style the different element types. If you are familiar with XSLT, DataTemplates are the functional equivalent of xsl:template.
Example to style:
<Window x:Class="ZoomingScrollViewer.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">
<Window.Resources>
<XmlDataProvider x:Key="testData" XPath="/Contacts/*">
<x:XData>
<Contacts xmlns="">
<Person Name="John" />
<Person Name="Robby" />
<Business>
<ContactName>Jemma</ContactName>
<BusinessName>Ars</BusinessName>
</Business>
<Business>
<BusinessName>The other one</BusinessName>
</Business>
</Contacts>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Source={StaticResource testData}}">
<ListBox.Resources>
<DataTemplate DataType="Person">
<TextBlock Text="{Binding XPath=#PersonName}" />
</DataTemplate>
<DataTemplate DataType="Business">
<StackPanel>
<TextBlock Text="{Binding XPath=ContactName}" />
<TextBlock Text="{Binding XPath=BusinessName}" />
</StackPanel>
</DataTemplate>
</ListBox.Resources>
</ListBox>
</Grid>
</Window>
If you wanted to select the DataTemplate based off of an attribute, rather than an element, you can use a DataTemplateSelector to run arbitrary code as explained in this question.
I found "Different views / data template based on member variable" as the closest to an answer. With the idea there, I could make a standalone control that made sense to me. This is the key bit:
<DataTrigger Binding="{Binding XPath=#kind}" Value="Number">
<Setter Property="ContentTemplate" Value="{StaticResource SmallInt}" />
</DataTrigger>
Here's the whole control:
<ContentControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:W3V="clr-namespace:W3.Views"
x:Class="W3.Views.ControlChooser">
<ContentControl.Resources>
<DataTemplate x:Key="StringChoice" >
<W3V:ComboView />
</DataTemplate>
<DataTemplate x:Key="SmallInt" >
<W3V:SpinView />
</DataTemplate>
</ContentControl.Resources>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource StringChoice}" />
<Style.Triggers>
<DataTrigger Binding="{Binding XPath=#kind}" Value="Number">
<Setter Property="ContentTemplate" Value="{StaticResource SmallInt}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>

Adding events on WPF LineSeries DataPoint

I am using WPF Toolkit to draw a line chart (a feature on our application). Given a Collection, I am able to plot the graph, however, when the user double clicks on the DataPoint on the graph, I am finding it difficult to get the X and Y data value (not the Co-Ordinate value in the line graph).
I am able to set property using DataPointStyle, but unable to add event to it.
If I use MouseDoubleClick="lineChart_ShowResults_DoubleClick" property on the LineSeries node, then it triggers an event when user clicks on any point. But, I need to trigger the event only if the user clicks on the DataPoint. The following is the XAML that I tried to implement. Please help.
<Window x:Class="TeamXXX.YYYUI.GraphicalDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GraphicalDisplay" Height="400" Width="600" xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="439" d:DesignWidth="654" SizeToContent="WidthAndHeight">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid MinHeight="360" MinWidth="575" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<chartingToolkit:Chart Name="lineChart" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<chartingToolkit:Chart.LegendStyle>
<Style TargetType="Control">
<Setter Property="Height" Value="0" />
<Setter Property="Width" Value="0" />
</Style>
</chartingToolkit:Chart.LegendStyle>
<chartingToolkit:LineSeries DependentValuePath="Value" Name="lineSeries" IndependentValuePath="Key" ItemsSource="{Binding}" IsSelectionEnabled="True" MouseDoubleClick="lineChart_ShowResults_DoubleClick">
<!--<chartingToolkit:LineSeries.DataPointStyle>
<Style x:Uid="CommonLineSeriesDataPoint" TargetType="chartingToolkit:LineDataPoint">
<Setter Property="" Property="lineChart_ShowResults_DoubleClick"/>
</Style>
</chartingToolkit:LineSeries.DataPointStyle>-->
<chartingToolkit:LineSeries.DependentRangeAxis>
<chartingToolkit:LinearAxis Orientation="Y" Title="Cost in minutes" FontSize="16" />
</chartingToolkit:LineSeries.DependentRangeAxis>
<chartingToolkit:LineSeries.IndependentAxis>
<chartingToolkit:LinearAxis Orientation="X" Title="Fold" FontSize="16" />
</chartingToolkit:LineSeries.IndependentAxis>
</chartingToolkit:LineSeries>
</chartingToolkit:Chart>
</Grid>
</ScrollViewer>
</Window>
As you said, The event triggers upon a click on any of the points because the event is assigned to the LineSeries. On this line (from your post)
<chartingToolkit:LineSeries DependentValuePath="Value" Name="lineSeries" IndependentValuePath="Key" ItemsSource="{Binding}" IsSelectionEnabled="True" MouseDoubleClick="lineChart_ShowResults_DoubleClick">
You were in the right path by going into LineSeries.DataPointStyle but I believe that you should define an event setter instead of a setter.
Like this:
<chartingToolkit:LineSeries.DataPointStyle>
<Style>
<EventSetter>
<EventSetter Event="Control.MouseDoubleClick" Handler="lineChart_ShowResults_DoubleClick"/>
</EventSetter>
</Style> </chartingToolkit:LineSeries.DataPointStyle>
</chartingToolkit:LineSeries.DataPointStyle>
And obviously remove the event handling on the LineSeries.
I did not try it, let me know if it works

Categories

Resources