WPF overlay help - c#

i am trying to create an overlay like this when mouse move over image control. how to I do it using WPF ?
please advice

You create both the image and the overlay, and bind the visibility property of the overlay to the image's and the overlay's IsMouseOver property.
You can also do it with triggers instead of binding. It works too.
Update:
Here is sample code. The XAML can look like this:
<Grid>
<Grid.Resources>
<local:OverlayVisibilityConverter x:Key="OverlayVisibilityConverter" />
</Grid.Resources>
<Image x:Name="myImage" Source="MyImage.JPG" />
<Image x:Name="myOverlay"
Source="MyOverlay.jpg"
VerticalAlignment="Center"
Opacity="0.2">
<Image.Visibility>
<MultiBinding Converter="{StaticResource OverlayVisibilityConverter}">
<Binding ElementName="myOverlay" Path="IsMouseOver" />
<Binding ElementName="myImage" Path="IsMouseOver" />
</MultiBinding>
</Image.Visibility>
</Image>
</Grid>
Of course the overlay must not be an image and can be anything. I just used an image in the sample. The opacity can be anything between 0 and 1.
The code for the converter can look like this:
class OverlayVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var isMouseOverOverlay = (bool)values[0];
var isMouseOverImage = (bool)values[1];
if (isMouseOverImage || isMouseOverOverlay)
return Visibility.Visible;
else
return Visibility.Hidden;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

I didn't like the complexity of the other answer as I felt it was too much for something so simple, so I tried it using MouseEnter and MouseLeave events and it seems to work quite well.
XAML:
<Grid MouseEnter="Grid_MouseEnter" MouseLeave="Grid_MouseLeave">
<Image x:Name="MainImage" Source="..." />
<Image x:Name="OverlayImage" Source="..." />
</Grid>
With accompanying code:
private void Grid_MouseEnter(object sender, MouseEventArgs e)
{
OverlayImage.Visibility = System.Windows.Visibility.Visible;
}
private void Grid_MouseLeave(object sender, MouseEventArgs e)
{
OverlayImage.Visibility = System.Windows.Visibility.Collapsed;
}
You don't need to use an image for the overlay, it can be anything. In my real case I actually had a StackPanel overlay which contained buttons for edit and delete (so the user could change/remove the image)

Related

C# WPF Image Converter for Buttons based on Boolean Value

I am making an RPG in WPF and C#. I have movement buttons with images attached. I am trying to figure out how to change the image of the button depending on if there is a room available to move to in that direction. I have looked up converters but I am not quite sure how to implement them for my situation.
This is one example I have tried to implement that I found online:
<Button Content="{Binding MyBooleanValue, Converter={StaticResource
MyBooleanToImageConverter}}" />
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
bool v = (bool)value;
Uri path = new Uri((v ? "ImgSrcIfTrue.png" : "ImgSrcIfFalse.png"), UriKind.Relative);
return new Image()
{
Source = new System.Windows.Media.Imaging.BitmapImage(path),
Height = ...,
Width = ...,
};
}
Here is part of the code I am working on
<!-- Movement Buttons -->
<Button Grid.Row="1" Grid.Column="1"
Click="OnClick_MoveNorth">
<StackPanel>
<Image Source= "/Image/Buttons/Up.png"/>
</StackPanel>
</Button>
I already have functions for the boolean values, i am just trying to figure out how to implement a Converter to change the button image.
I have used the Boolean Visibility and hoping to do something similar.
Visibility="{Binding HasMonster, Converter={StaticResource BooleanToVisibility}}"
Better bind the Source property of an Image element in the Content of the Button:
<Button>
<Image Source="{Binding MyBooleanValue,
Converter={StaticResource MyBooleanToImageConverter}}"/>
</Button>
The converter would directly return a BitmapImage. If the image files are supposed to be assembly resources (i.e. they are part of your Visual Studio project and their Build Action is set to Resource), they must be loaded from Pack URIs:
public class BooleanToImageConverter : IValueConverter
{
public object Convert(
object value, Type targetType, object parameter, CultureInfo culture)
{
var uri = (bool)value
? "pack://application:,,,/ImgSrcIfTrue.png"
: "pack://application:,,,/ImgSrcIfFalse.png";
return new BitmapImage(new Uri(uri));
}
public object ConvertBack(
object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
You would add the converter to the Window's Resources like this:
<Window.Resources>
<local:BooleanToImageConverter x:Key="MyBooleanToImageConverter"/>
...
</Window.Resources>

How to set a TextBlock's font size to be a ratio of another font size property?

I have a TextBlock inside a custom user control that I would like to be slightly larger (maybe 7% larger) than the global font size property for that user control. I am unsure of the best way to go about this. Does anyone have any suggestions?
(Obviously this attempt is atrocious, but hopefully it helps visualize what I'm asking).
<TextBlock
x:Name="Title"
FontSize="{myUserControl.FontSize * 1.07}">
Hello Custom User Control!
</TextBlock>
The best answer (credit to #Kenny) is a simple converter that takes the user control font size as it's input.
Use in xaml:
<z:RatioConverter x:Key="AdjustTitleFontSizeConverter" Ratio="1.07" />
<TextBlock
x:Name="Title"
FontSize="{Binding FontSize, Converter={StaticResource AdjustTitleFontSizeConverter}">
Hello Custom User Control!
</TextBlock>
RatioConverter.cs
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
public class RatioConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Input santize first..
return (System.Convert.ToDouble(value)) * this.Ratio;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public Double Ratio
{
get { return (Double)GetValue(RatioProperty); }
set { SetValue(RatioProperty, value); }
}
public static readonly DependencyProperty RatioProperty = DependencyProperty.Register(
"Ratio", typeof(Double), typeof(RatioConverter), new FrameworkPropertyMetadata(1.0));
}
Apply ScaleTransform with a desired scale factor.
In this example all TextBlock inherit FontSize=20 from parent Window (it is Dependency Property inheritance). Then I change FontSize to 22 for one TextBlock, and scale another (20 * 1.1 == 22). They look similar to me.
<Window x:Class="WpfDemos.FontWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WpfDemos" Height="300" Width="300" FontSize="20">
<StackPanel>
<TextBlock Text="Hello Custom User Control!"/>
<TextBlock Text="Hello Custom User Control!"/>
<TextBlock Text="Hello Custom User Control!">
<TextBlock.LayoutTransform>
<ScaleTransform ScaleX="1.1" ScaleY="1.1"/>
</TextBlock.LayoutTransform>
</TextBlock>
<TextBlock Text="Hello Custom User Control!" FontSize="22"/>
<TextBlock Text="Hello Custom User Control!"/>
<TextBlock Text="Hello Custom User Control!"/>
</StackPanel>
</Window>
You can use https://www.nuget.org/packages/CalcBinding/ library for this.

Binding to a Rectangle within a ListBox ItemTemplate?

I have a ListBox, which uses data binding for content (bound to an ObservableCollection), and an ItemTemplate for layout. Within the ItemTemplate, there is a TextBlock displaying a date (from the ObservableCollection), and a colored Rectangle.
I want the rectangle's fill color to change based on the date (to indicate age). However, since the Rectangle itself isn't bound to the date (and I don't see how it could be), I haven't been able to get a DataTrigger to work to alter the fill color.
Is there another way to get the Rectangle color to be controlled by the data binding?
Edit:
Here is a (simplified) copy of my ListBox ItemTemplate, as requested. Right now, the Rectangle's fill is a set color, but I want to change it to vary based on the targetstartdate field.
<ListBox Name="listBox1" ItemsSource="{Binding Path=testList}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Rectangle Fill="#FF009A00" Width="5" StrokeThickness="1" Margin="0,1,4,1"/>
<TextBlock Text="{Binding targetstartdate}" Margin="0,0,0,4" Foreground="#FF009A00" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can bind the rectangle's Fill or Stroke property to the Date. Then, use an IValueConverter to convert the date to the appropriate color.
<Window.Resources>
<local:DateToBrushConverter x:Key="DateToBrushConverter" />
</Window.Resources>
<Rectangle Fill="{Binding targetstartdate,Converter={StaticResource DateToBrushConverter}}"
... />
The Convert method should return a Brush object, which matches the Rectangle.Fill property.
public class DateToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var date = value as DateTime?;
if (!date.HasValue)
return new SolidColorBrush(Colors.Transparent);
else if (!date.Value > DateTime.Today.AddDays(-1))
return new SolidColorBrush(Colors.Blue);
// etc
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Bind rectangle's color to an IValueConverter, use the date as binding and determine the color based on the date inside the IValueConverter class.

Assign an Image for each Pivot Item Header

I am trying to assign an image for each of my pivot items's header instead of a Text .
I tried several methods (one was given by this post http://social.msdn.microsoft.com/Forums/wpapps/en-US/e7b5fd17-3465-4a94-81af-5c056c992c11/add-image-to-pivot-title?forum=wpdevelop )
I managed to assign the same image for my pivot but not one image for each header.
This is what I tried :
<phone:Pivot.HeaderTemplate >
<DataTemplate>
<Image Source="21.jpg" Height="55" Width="55"/>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
This obviously gave me the same image for each headers ,
So i wanted to try something like this :
<phone:Pivot.HeaderTemplate >
<DataTemplate>
<Image Source="{Binding}" Height="55" Width="55"/>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
[...]
<phone:PivotItem ??? >
<// phone:PivotItem >
But then i don't know what to add my image path.
i used this method when i wanted to assign a text as a header and it worked :
<phone:Pivot.HeaderTemplate >
<DataTemplate>
<TextBlock Text="{Binding }" FontSize="88" />
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:PivotItem Header = "Title1" />
How can i assign an image for each of my Header ?
You should be able to simply provide the image source in the Header:
<phone:PivotItem Header = "21.jpg" />
This sets the data context to use for the HeaderTemplate for that particular item.
You need to use a Converter Class to solve this issue.
namespace MyImageConvertor
{
public class MyValueConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
var uri = new Uri((string)(value), UriKind.RelativeOrAbsolute);
var img = new BitmapImage(uri);
return img;
}
catch
{
return new BitmapImage();
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var img = value as BitmapImage;
return img.UriSource.AbsoluteUri;
}
#endregion
}
}
Then use the this convertor in your xaml.
<UserControl x:Class="ValueConverter.MainPage"
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"
mc:Ignorable="d"
xmlns:this="clr-namespace:MyImageConvertor">
<UserControl.Resources>
<this:MyValueConverter x:Key="ImageConverter"/>
</UserControl.Resources>
<phone:Pivot>
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<Image Source="{Binding ImageUrlProperty, Converter={StaticResource ImageConverter},Mode=TwoWay}"></Image>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
</phone:Pivot>
Make sure you have the full image path in the ImageUrlProperty value like ..\Images\logo.png.

Setting the image position via code

I want to set the image position via code to fit on the button (see screenshot). But I can't work it out. In WinForms it was easy, but in Silverlight I can't just set the X & Y apparently.
public void LockControls()
{
int LockIndex = 0;
DependencyObject myUserControl = LayoutRoot;
foreach (var button in FindAll<Button>(myUserControl))
{
if (button.Tag != null)
{
Image LockedIcon = new Image();
LockedIcon.Width = 20;
LockedIcon.Height = 20;
//LockedIcon.Margin = new Thickness(0,0,0,0);
LockedIcon.Source = new BitmapImage(new Uri("images/LockedIconx20alpha.png", UriKind.Relative));
LockedIcon.Name = "Lockie" + LockIndex;
LayoutRoot.Children.Add(LockedIcon);
button.Tag = "Locked" + LockIndex;
LockIndex++;
}
}
}
http://puu.sh/wS7g
THe screenshot shows the image position (the locck), but I don't understand how the current position is being set. Just to clarify, I want to set the position to the "0%" button
Thanks in advance,
Jack
That's not the correct way of doing. If I understand correctly you want to super-impose an image on top of a button to prevent the user from using it. It won't work.
For that you have to understand the layout system of Silverlight: the controls are laid out by the engine during the measure and arrange events.
Trying to overlay an image like that will require you to hook up on those events, or derive the Button class and override the Arrange method to overlay your image.
But that won't prevent the user from using the button because the button itself is not disabled, and one could just "tab" into it, and activate it.
Instead I suggest you use a style for the button, and override, say, the Disabled state to overlay your locked image. The button style is described here.
All you have to do is replace:
<Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
by
<Image x:Name="DisabledVisualElement" IsHitTestVisible="false" Opacity="0" Width="20" Height="20" Source="images/LockedIconx20alpha.png" />
And set the opacity in the following to 1:
<vsm:VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity" To=".55"/>
</Storyboard>
</vsm:VisualState>
Set this style on your button (I assume you know how to do this) then when you need to lock your button, set it to disabled and your image will be automatically laid on-top and your button will be un-clickable.
In general, if you want to set the Image position arbitrary, you should host the Image control in a Canvas container.
However, in your case you should really change the Content element of your Button depending on the need for showing the lock or not.
<UserControl DataContext="{Binding Main, Source={StaticResource Locator}}
<Grid.Resources>
<converters:VisibilityConverter x:Key="VisibilityConverter" />
</Grid.Resources>
<Button Width="100" Height="23" IsEnabled="{Binding IsControlsEnabled}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<Image Source="lock.png" Margin="10,0,10,0"
Visibility="{Binding IsControlsEnabled, Converter={StaticResource VisibilityConverter}}"/>
<TextBlock Text="Button"/>
</StackPanel>
</Button.Content>
</Button>
Additionally, you shouldn't really write the kind of code you have in your question in Silverlight. Learn how to use data binding. It's very powerful. Simply bind the IsEnabled property of your Buttons to an exposed Property instead.
An example of doing so using the MVVM Light toolkit (I recommend you learn the MVVM pattern for Silverlight/WPF development):
The View Model:
public class MainViewModel : ViewModelBase
{
private bool isControlsEnabled;
public bool IsControlsEnabled
{
get { return isControlsEnabled; }
set
{
if (IsControlsEnabled.Equals(value)) return;
isControlsEnabled = value;
RaisePropertyChanged(() => IsControlsEnabled);
}
}
}
The Visibility Converter:
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (bool)value ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then you can simply enable/disable all controls that are bound, for example using a CheckBox:
<CheckBox IsChecked="{Binding IsControlsEnabled, Mode=TwoWay}" Content="Controls are enabled"/>

Categories