In the past I created a winform user control that inherit imagebox control, which the user can select part of the image by drawing a rectangle with the mouse.
Now I want to do the same with WPF. I wrote this XAML code:
<StackPanel Width="321" Height="241">
<Canvas x:Name="SampleImageCanvas"
MouseMove="SampleImageCanvas_MouseMove"
MouseDown="SampleImageCanvas_MouseDown"
MaxHeight="240" MaxWidth="320" >
<Canvas.Width>
<MultiBinding Converter="{StaticResource SizeConverter}" Mode="OneWay">
<Binding XPath="./Size/Width" />
<Binding XPath="./Size/Ratio" />
</MultiBinding>
</Canvas.Width>
<Canvas.Height>
<MultiBinding Converter="{StaticResource SizeConverter}" Mode="OneWay">
<Binding XPath="./Size/Height" />
<Binding XPath="./Size/Ratio" />
</MultiBinding>
</Canvas.Height>
<Canvas.Background>
<ImageBrush x:Name="SampleImage" ImageSource="{Binding XPath=./SampleImage}" Stretch="Uniform"/>
</Canvas.Background>
<Rectangle x:Name="ROI"
Canvas.Top="{Binding XPath=./ROI/Top, Mode=TwoWay}"
Width="{Binding XPath=./ROI/Width, Mode=TwoWay}"
Height="{Binding XPath=./ROI/Height, Mode=TwoWay}"
Canvas.Left="{Binding XPath=./ROI/Left, Mode=TwoWay}"
Stroke="#FFD13750"
/>
</Canvas>
</StackPanel>
The data is stored in an xml document. the image is bigger than the canvas, so it has to be stretch uniformly, to fit the max size of the canvas, and I want the canvas to resize to the size of the image scaled display, so the image fills 100% of the canvas with no margins.
when I'll have this, the mouse move/enter/exit event will be set only to the image borders.
The problem is the canvas height binded value, which cause the image not to be shown although it has beec defined same as the canvas width which works, and the convertor returns the corect value.
When I set the height to exact value instead of binded value, like Height="240", it works.
Thanks!
Related
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>
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>
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>
In dialog, I need to scale bitmap in cell of datagrid for avoid bluring
here is MyFile.xaml
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Margin="1"
Width="90"
Height="18"
VerticalAlignment="Center"
Stretch="Fill"
RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
SnapsToDevicePixels="True"
HorizontalAlignment="Center">
<Image.Source>
<MultiBinding Converter="{StaticResource HatchIdToPaleteImageConverter}" ConverterParameter="90">
<Binding Path="HatchId"/>
<Binding Path="Color" />
</MultiBinding>
</Image.Source>
</Image>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
But bitmaps in 5th, 20th row are hidden their top but the others are OK.
If I scroll my grid by vertical scrollbar, the hidden image changed: bitmaps in 11st, 26th row are hidden their top but the others are OK. I guess the 5th, 20th datagridcell of view is always wrong.
If I remove RenderOptions.BitmapScalingMode="NearestNeighbor"
the bitmap in all rows are showed full but it's blur.
I try to remove the margin or resize my row's height but it's not work.
I change height of Image. It's work.
Maybe the height of bitmap is not the same between all row of datagrid
Height="19"
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?