bind the date of the DatePicker to ConverterParameter - c#

I'm trying to mark Names in a ComboBox based on a Date from a DatePicker using a converter class.
My current problem is I don't know how to bind the date of the DatePicker to the "ConverterParameter". Any suggestions?
(probably more errors in my code but i'm stuck at this point)
<Page.Resources>
<Style TargetType="ComboBoxItem" x:Key="combostyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<ControlTemplate.Resources>
<src:ColorFromMagazijnierIdConverter x:Key="conv" />
</ControlTemplate.Resources>
<Grid ToolTip="{Binding Converter={StaticResource conv}, ConverterParameter={ BIND THIS TO THE DATEPICKER DATE }, Mode=OneWay}">
<Rectangle x:Name="MarkedItemBackground" IsHitTestVisible="False" Fill="#80FF0000" />
<!--...-->
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource conv}}"
Value="{x:Null}">
<Setter TargetName="MarkedItemBackground"
Property="Visibility" Value="Hidden" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid Margin="10,10,10,0" Name="rootGrid">
<ComboBox Name="collectMagazijnierComboBox"
DisplayMemberPath="User.Name"
ItemContainerStyle="{DynamicResource ResourceKey=combostyle}"/>
<DatePicker Name="collectDatePicker" />
</Grid>

The ConverterParameter property cannot be the target of a binding. Only a DependencyProperty of a DependencyObject can be the target of a binding.
You'll need to use a MultiBinding:
<Grid>
<Grid.ToolTip>
<MultiBinding Converter="{StaticResource conv}" Mode="OneWay">
<Binding /> <!-- this mimics your current binding to the datacontext itself -->
<Binding ElementName="collectDatePicker" Path="SelectedDate" />
</MultiBinding>
</Grid.ToolTip>
<Rectangle x:Name="MarkedItemBackground" IsHitTestVisible="False" Fill="#80FF0000" />
<!--...-->
</Grid>
You'll then need to rewrite your ColorFromMagazijnierIdConverter converter to implement the IMultiValueConverter interface instead, in which you can access both values.
Although, I'm not 100% sure whether you can reference the collectDatePicker by ElementName from within the style resource like that. But sure you can play around with it!

Related

XAML/WPF Canvas or TextBlock Behavior Differences Between Windows Versions

The code below is used to view a thumbnail image of pages in a document.
<ListView x:Name="ThumbPanel" ItemsSource="{Binding OpenDocument.PageCollection}" SelectedIndex="{Binding PageIndexVM, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<Border MinHeight="50" MinWidth="50" BorderBrush="Black" BorderThickness="1" SnapsToDevicePixels="True" Margin="5">
<Grid HorizontalAlignment="Left">
<Image x:Name="ThumbImage" Width="{Binding ThumbWidth, Mode=OneWay, Source={StaticResource viewModel}}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding PageCached, Mode=OneWay}" Value="true">
<Setter Property="Source">
<Setter.Value>
<MultiBinding Converter="{StaticResource UriToImageWithRotation}" Mode="OneWay">
<Binding Path="CacheImagePath" />
<Binding Path="OriginalRotation" />
<Binding Source="{StaticResource viewModel}" Path="ThumbWidth" />
</MultiBinding>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding PageCached, Mode=OneWay}" Value="false">
<Setter Property="Source" Value="{StaticResource CheckGreen}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<Canvas HorizontalAlignment="Right" Margin="0, 2, 18, 0">
<Image Width="16">
<Image.Style>
<Style>
<Setter Property="Image.Source" Value="{StaticResource CheckGreen}" />
<Style.Triggers>
<DataTrigger Value="False" Binding="{Binding IsSelected}">
<Setter Property="Image.Source" Value="{StaticResource CancelX}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Canvas>
<Canvas VerticalAlignment="Bottom" HorizontalAlignment="Right">
<Canvas.Margin>
<MultiBinding Converter="{StaticResource TextMarginConverter}" Mode="OneWay">
<Binding ElementName="ThumbPageNum" Path="ActualWidth" />
<Binding ElementName="ThumbPageNum" Path="ActualHeight" />
</MultiBinding>
</Canvas.Margin>
<Border x:Name="ThumbPageNum" BorderBrush="Black" BorderThickness="1" SnapsToDevicePixels="True">
<TextBlock Text="{Binding Path=PageNumber, Mode=OneTime}" MinWidth="16" TextAlignment="Center" Padding="2" Background="White"/>
</Border>
</Canvas>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In that code the last canvas is to display a page number notation in the bottom right corner of the thumbnail image.
The notation shows up and works fine, but I’m having a problem that occurs in Windows 7 when the thumbnail image is clicked and brought into focus; the TextBlock will disappear and a blank white canvas is shown. In Windows 10 there is no change to page number notation and it shows properly regardless of if the thumbnail image is clicked and in focus. I do not have a Windows 8 machine to test this issue.
I have been unable to figure out what is causing this issue or a workaround. If anyone has any insight in regards to what is causing this problem and/or a possible fix I would appreciate some help.
Below is an image of this behavior:
The issue was caused by not explicitly setting the TextBlock Foreground property. When the ListView item was clicked it changed to a Selected Item and it's children adapted the Window Color and Appearance properties referenced at: "Control Panel\All Control Panel Items\Personalization\Window Color and Appearance\Advanced appearance settings...".
The font in my TextBlock turned white because that is my font color for a selected item in the Window Color and Appearance settings and it was not visible due to the white TextBlock background.

WPF Changing ListBox background color, enabled and disabled

I'm searching how to change the background color of my WPF Listbox, nothing worked... I don't want to change the background of the Item Template, but of the ListBox himself.
I tried the differents solutions answered here Answers
Here is my Listbox :
<ListBox Name="myListBox" ScrollViewer.VerticalScrollBarVisibility="Visible" SelectionChanged="myListBox_SelectionChanged" Background="#FFC3DDF7" Margin="0,0,0,10">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Value.IsOk}" Value="True">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel Width="200">
<TextBlock FontSize="10" FontWeight="Bold" VerticalAlignment="Center" Text="{Binding Path=Key}" />
<TextBlock FontSize="10" VerticalAlignment="Center" TextWrapping="Wrap">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1} {2}">
<Binding Path="Value.TextA" />
<Binding Path="Value.TextB" />
<Binding Path="Value.TextC" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Maybe the item template is on the foreground ?
Tried these codes :
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Blue"/>
</Style.Resources>
</Style>
and
<ListBox>
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
Not working. The down right corner, between the two scrollbars, became blue... But that's all !
The reason why your linked answer does not work is because you have the background of the listbox set to #FFC3DDF7 on the element itself. If you wish to change the initial background color of your listbox this would need to be moved into the style. If you do not move this then the rule for "closest" defined value would be the one on the element itself and the style can't override this.
<ListBox Name="myListBox" ScrollViewer.VerticalScrollBarVisibility="Visible" SelectionChanged="myListBox_SelectionChanged" Margin="0,0,0,10">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="#FFC3DDF7"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="LightGray" />
<Setter Property="Background" Value="LightGray" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Value.IsOk}" Value="True">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel Width="200">
<TextBlock FontSize="10" FontWeight="Bold" VerticalAlignment="Center" Text="{Binding Path=Key}" />
<TextBlock FontSize="10" VerticalAlignment="Center" TextWrapping="Wrap">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1} {2}">
<Binding Path="Value.TextA" />
<Binding Path="Value.TextB" />
<Binding Path="Value.TextC" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As Anthony pointed out, your style trigger will never set the Background of your ListBox because you have set a local value. It's called "Dependency Property Precedence". Take a look at this link: https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-value-precedence.
"Local" values have higher precedence over "style trigger" values. However, "style trigger" values have higher precedence over "style setter" values. This means that if you want to have an initial value for the property and change it based on a trigger, just set it in the style initially, instead of setting it locally like your code does.
First off all - this msdn link ListBox Styles and Templates will help you the most. You can check this way - what applies where in a ListBox and a ListBoxItem.
If you check the Style of the ListBoxItem you will see that the ContentPresenter gets no Foreground applied.
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter x:Name="contentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"/><!-- No foreground gets applied. -->
<Rectangle x:Name="FocusVisualElement" Stroke="#FF6DBDD1" StrokeThickness="1" Visibility="Collapsed" RadiusX="1" RadiusY="1" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Anyway here is your solution:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
Width="200">
<TextBlock VerticalAlignment="Center"
FontSize="10"
TextWrapping="Wrap">
<Run FontWeight="Bold" Text="{Binding Path=Key}" />
<LineBreak />
<Run>
<Run.Text>
<MultiBinding StringFormat="{}{0} {1} {2}">
<Binding Path="Value.TextA" />
<Binding Path="Value.TextB" />
<Binding Path="Value.TextC" />
</MultiBinding>
</Run.Text>
</Run>
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsOk}" Value="True" >
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
The TextBlock now listens to isOk and will applys the Foreground.

Style TreeviewItem layout (MVVM)

I have a TreeView to which I bind a ObservableCollection where TreeView inherits TreeViewItem.
I want to style the header of the tree view to have a image in front of each header. I setted the header to the ItemContainerStyle but it did not chnage its layout. However it works for the ContextMenu.
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ToolTip" Value="{Binding ID, Mode=TwoWay}"/>
<Setter Property="Header">
<Setter.Value>
<StackPanel Orientation="Horizontal">
<Image Source="Images/Icons/Plus-48.png" Height="10" Width="10" />
<TextBlock Text="{Binding MachinePartName}" Margin="0,0,4,0" />
</StackPanel>
</Setter.Value>
</Setter>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Add" Command="{Binding AddMachinePart_Command}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
You need to use HeaderTemplate instead:
<Setter Property="Header"
Value="{Binding }" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="Images/Icons/Plus-48.png"
Height="10"
Width="10" />
<TextBlock Text="{Binding MachinePartName}"
Margin="0,0,4,0" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
Don't forget to bind Header property.

WPF Binding - Bind to A when X is checked, else bind to B

Basically I have a TextBlock which displays the Microphone Gain.
<TextBlock FontFamily="Calibri Light" FontSize="20" Foreground="#FFF65B60" FontWeight="Bold" Height="35"><Run Text="{Binding AudioRecorder.Gain, StringFormat={}Microphone Gain: {0:#} %}"/></TextBlock>
As you can see, this is bound to "AudioRecorder.Gain" however I only want to bind to that value if this checkbox is NOT checked.
<CheckBox IsChecked="{Binding Recognizer.AutoGainControl}"
if its checked, I want to bind to
"Recognizer.Gain"
Is something like that possible or do I have to merge the two gain variables together?
I am not sure if you did succeed or not but some example should remain here for others who might search the same thing:
I have gathered some info and created a version of this :
<Window x:Class="ComboItems.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:windows="clr-namespace:System.Windows;assembly=PresentationCore"
xmlns:system="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Width="525">
<Window.Resources>
<x:Array x:Key="data1" Type="{x:Type system:String}">
<system:String>Item1</system:String>
<system:String>Item2</system:String>
<system:String>Item3</system:String>
</x:Array>
<ObjectDataProvider x:Key="visibilityValues"
ObjectType="{x:Type system:Enum}"
MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="windows:Visibility" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<Grid>
<StackPanel>
<RadioButton Content="RadioButton1" Name="Radio1" GroupName="radio" />
<RadioButton Content="RadioButton2" Name="Radio2" GroupName="radio" />
<ListBox Name="listbox">
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="ItemsSource">
<Setter.Value>
<Binding Source="{StaticResource data1}" />
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked, ElementName=Radio1}" Value="True" >
<Setter Property="ItemsSource">
<Setter.Value>
<Binding Source="{StaticResource data1}" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsChecked, ElementName=Radio2}" Value="True" >
<Setter Property="ItemsSource">
<Setter.Value>
<Binding Source="{StaticResource visibilityValues}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
</StackPanel>
</Grid>
</Window>
DataTrigger will do the job here and according to the IsChecked property of both RadioButtons it will change the source of the ListBox.
Further more, i have used binding to enumerations with the help of System.Enum type’s GetValues method which accepts a
Type parameter so that it knows which enumeration’s values it should return.
The above sample should work without any modification.

How to set TabIndex to a ComboBox within a ContentControl?

I have following code -
<ContentControl KeyboardNavigation.TabIndex="6"> //Point A
<ContentControl.Template>
<ControlTemplate>
<ContentControl x:Name="content">
<ContentControl.Template>
<ControlTemplate>
<ComboBox Style="{StaticResource ComboBoxStyle}" ItemsSource="{Binding Path=Property1}"
Margin="0, 7" >
<ComboBox.SelectedValue>
<Binding Path="PropertyText" />
</ComboBox.SelectedValue>
</ComboBox>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Property1}" Value="val1">
<Setter TargetName="content" Property="Template">
<Setter.Value>
<ControlTemplate>
<ComboBox Style="{StaticResource ComboBoxStyle}" ItemsSource="{Binding Path=Propert2}"
Margin="0, 7">
<ComboBox.SelectedValue>
<Binding Path="val2" />
</ComboBox.SelectedValue>
</ComboBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
Explanation
See the Point A. The TabIndex is working fine, but if I move this to internal elements like ComboBox, it goes to next TabIndex. Also I have a trigger.
Requirement
Whichever Combobox is visible should get TabIndex="6".
The parent control i.e. ContentControl should not get any TabIndex.
Please suggest. Thanx in advance.

Categories