Change image source base of model and ListViewItem properties - wpf

So i have this Image inside GridViewColumn:
<Image Width="16"
Height="16"
Source="{Binding IsChecked, Converter={StaticResource myConverter}}"/>
So IsChecked is my model property and base on its value i am changing my Image Source.
So Until here all works fine.
Now i want to change my Image Source also if MouseOver over my ListViewItem and i this case the imgae source will be different if MouseOver is true or false.
Any seggustion how to do that ?
I was thinking of use IMultiValueConverter but how can i pass into my converter the ListViewItem MouseOver value ?

A MultiBinding like this should work:
<Image>
<Image.Source>
<MultiBinding Converter="{StaticResource myConverter}">
<Binding Path="IsChecked"/>
<Binding Path="IsMouseOver" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Image.Source>
</Image>

Related

WPF pass ActualWidth and ActualHeight of child control to value converter

Using WPF, I wish to create an image for each data set in a collection and display the images stacked vertically. All the images must have the same height (and width). The images stacked together must make up the height of the containing element. The images must not be stretched in any way.
A non-working pretend example of the kind of thing I'm after is as follows.
<UniformGrid Columns="1" DataContext="{Binding DataSetCollection}">
<UniformGrid.Children>
<MultiBinding Converter="{StaticResource DataSetToImageConverter}">
<Binding />
<Binding Path="ActualWidth" RelativeSource="{RelativeSource AncestorType={x:Type UniformGridRow}}" />
<Binding Path="ActualHeight" RelativeSource="{RelativeSource AncestorType={x:Type UniformGridRow}}" />
</MultiBinding>
</UniformGrid.Children>
</UniformGrid>
This doesn't work for a number of reasons but hopefully communicates the intent. Key requirements are:
All children must be the same height
No stretching is allowed
Each image is created dynamically based on the area available to it
Images are redrawn when the size of the containing element changes
The value converter used to return the images correctly receives the width and height of the containing row
It doesn't have to use UniformGrid, it can be anything, however it should use databinding and a converter for each child.
This did the trick, binding to the size of the containing ContentPresenter.
<ItemsControl ItemsSource="{Binding DataSetCollection}" ItemTemplate="{StaticResource WriteableBitmapDataTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Using this data template
<DataTemplate x:Key="WriteableBitmapDataTemplate">
<Image>
<Image.Source>
<MultiBinding Converter="{StaticResource RangeToWritableBitmapConverter}">
<Binding />
<Binding Path="ActualWidth" RelativeSource="{RelativeSource AncestorType={x:Type ContentPresenter}}" />
<Binding Path="ActualHeight" RelativeSource="{RelativeSource AncestorType={x:Type ContentPresenter}}" />
</MultiBinding>
</Image.Source>
</Image>
</DataTemplate>

WPF - Binding a Line with a converter that returns a Line

I'm attempting to draw some scatter charts with WPF, and struggling to draw the little tick marks usually present on chart axes. My view model defines the positions of the ticks using a List<Tick> for each axes, where each Tick item is just the cartesian coordinate of where the tick would fall on the axis. I have an IMultiValueConverter which uses the canvas size to convert the single point into a Line object that can be rendered... but how do I bind this? WPF wants me to specify X1, X2, Y1, and Y2, but I just want to give it the line.
My thought was to define a data template like the following, but it does not compile because I can't give Line a multibinding directly. Is there an intermediate element / attribute I could be using?
<DataTemplate DataType="{x:Type viewModel:Tick}" x:Key="TickTemplate">
<Line>
<WhatsMissing?>
<MultiBinding Converter="{StaticResource PointsConverter}">
<Binding Path="Points"/>
<Binding Path="DataContext.MinPoint" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}"/>
<Binding Path="DataContext.MaxPoint" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}"/>
<Binding Path="ActualWidth" ElementName="ChartCanvas"/>
<Binding Path="ActualHeight" ElementName="ChartCanvas"/>
</MultiBinding>
</WhatsMissing?>
</Line>
</DataTemplate>
You could bind a ContentControl's Content property to the Line returned from you converter, but IMO a converter should not deal with UIElements. Creating and manipulating UIElements in code behind should generally be avoided.
Better return a LineGeometry from your converter, and bind a Path's Data property to the result:
<DataTemplate DataType="{x:Type viewModel:Tick}" x:Key="TickTemplate">
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<MultiBinding Converter="{StaticResource PointsConverter}">
...
</MultiBinding>
</Path.Data>
</Path>
</DataTemplate>

Wpf Binding vs MultiBinding update

I had an issue that has been resolved.
WPF binding HorizontalAlignment to TextAlignment
I have a ListBoxItem whose HorizontalAlignment property is changed by a Converter, according to the width of the Window. I have a TextBlock inside this ListBoxItem whose TextAlignment property is binded to the HorizontalAlignment property of the ListBoxItem.
First, I used a Simple Binding, that didn't work (the HorizontalAlignment of the ListBoxIten changed, but the TextAlignment was not updated). Here is the code:
<ListBox>
<ListBoxItem>
<TextBlock TextWrapping="Wrap" Text="Some text"
TextAlignment="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}, Path=HorizontalAlignment}"/>
</ListBoxItem>
</ListBox>
After, I used a MultiBinding instead of a Binding, passing AcualWidth property, which actually is not used by the Converter. Now the TextAlignment is updated when ListBoxItem's HorizontalAlignment changes. I used the following code:
<TextBlock TextWrapping="Wrap" Text="Some text">
<TextBlock.TextAlignment>
<MultiBinding Converter="{StaticResource HorizontalToTextAlignmentConverter}">
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/>
<Binding Path="HorizontalAlignment" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}"/>
</MultiBinding>
</TextBlock.TextAlignment>
</TextBlock>
The Converter itself is the same, it just has one more variable (ActualWidth of the Window) that is not used. So, my question is: Why the TextAlignment was update only with a MultiBinding?

why can't I use multibinding with the IsEnabled property of the button?

I am trying to set the IsEnabled property of a button using multibinding, because this property depends on three variables.
If I would set the content propery, I could use this code:
<Button Height="23" HorizontalAlignment="Left" Margin="629,49,0,0" Name="btnMyButton" VerticalAlignment="Top" Width="75">
<Button.Content>
<MultiBinding Converter="{StaticResource myMultiValueConverter}">
<Binding ElementName="MyElement"/>
<Binding />
</MultiBinding>
</Button.Content>
</Button>
I try to use this code:
<Button Height="23" HorizontalAlignment="Left" Margin="629,49,0,0" Name="btnMyButton" VerticalAlignment="Top" Width="75">
<Button.IsEnabled>
<?????
But in this case, although the Button.IsEnabled is avaliable, in the next line I can't find the Multibinding keyword, so I can't use multibinding with the IsEnabled property.
why? Is there any way to set the IsEnabled property with a multivalue converter?
Thanks.
The syntax should be the exact same as what you have for Button.Content - just replace "Content" with "IsEnabled".
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource myMultiValueConverter}">
<Binding ... />
<Binding ... />
<Binding ... />
</MultiBinding>
</Button.IsEnabled>
It might not auto-complete for you because the IsEnabled property expects a boolean value, not a MultiBinding object, but it shouldn't give you any errors, and will compile and execute just fine.
(It auto-completes for Button.Content because the Content property is of type object, which includes a MultiBinding object)

Why does MultiBinding with a Converter not work within a ToolTip?

For part of a fairly-complex WPF ToolTip, I'm attempting to use a MultiBinding to produce formatted text based on two properties. The problem is, the binding's MultiConverter receives DependencyProperty.UnsetValue for each item in its values array.
The following works, using a single Binding:
<ToolTipService.ToolTip>
<StackPanel>
<TextBlock>
<TextBlock.Text>
<Binding Path="Amt" Converter="{StaticResource singleValueConverter}"/>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</ToolTipService.ToolTip>
And so does this, using a MultiBinding with StringFormat:
<ToolTipService.ToolTip>
<StackPanel>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat='{0:C} in {1}'>
<Binding Path="Amt"/>
<Binding Path="Currency"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</ToolTipService.ToolTip>
But a MultiBinding with a Converter does not:
<ToolTipService.ToolTip>
<StackPanel>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource multiValueConverter}">
<Binding Path="Amt"/>
<Binding Path="Currency"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</ToolTipService.ToolTip>
The bindings in the last example don't receive any value. This isn't the case outside of a ToolTip - what is going on such that binding fails in this specific case?
Try setting Mode="OneWay" on your binding.
Also, have you checked this problem and solution:
http://social.msdn.microsoft.com/Forums/en-IE/wpf/thread/15ada9c7-f781-42c5-be43-d07eb1f90ed4
The reason of this error is the
tooltips have not been loaded, so
DependencyProperty.GetValue returns
DependencyProperty.UnsetValue. You
should add some code to test that is
value is Dependency.UnsetValue. The
following code shows how to do this.
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue)
return "";
[...]
}
Try this:
<ToolTipService.ToolTip>
<StackPanel>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource multiValueConverter}">
<MultiBinding.Bindings>
<BindingCollection>
<Binding Path="Amt"/>
<Binding Path="Currency"/>
</BindingCollection>
</MultiBinding.Bindings>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</ToolTipService.ToolTip>

Resources