WP7 - Update UserControl through binding - silverlight

I have a WP7 silverlight project. I have a 'UserControl' to display rectangles based on a DependencyProject.
Now, when I place the control on my page with the following:
<uc:RectangleControl NumRectangles={Binding Path=RectangleCount,Mode=OneWay} />
I get my rectangles displayed based on initial value of 'RectangleCount'. However, when RectangleCount is changed, the User control never updates. I expect this is caused by me drawing my rectangles in the OnLoaded event, but I can't for the life of me find another event to bind to to cause the control to draw new rectangles when the NumRectangles DP is updated.
Any help?
The UserControl XAML:
<UserControl x:Class="WP7Test.Controls.RectangleControl"
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"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="80" d:DesignWidth="480">
<Canvas x:Name="canvas"
Height="{Binding Height}" Width="{Binding Width}">
</Canvas>
</UserControl>
And in the code behind, I add rectangles based on a dependency property:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace WP7Test.Controls
{
public partial class RectangleControl : UserControl
{
private double RectangleSpacing = 1;
#region Dependency Properties
public int NumRectangles
{
get { return (int)GetValue(NumRectanglesProperty); }
set { SetValue(NumRectanglesProperty, value); }
}
// Using a DependencyProperty as the backing store for NumRectangles. This enables animation, styling, binding, etc...
public static readonly DependencyProperty NumRectanglesProperty =
DependencyProperty.Register("NumRectangles", typeof(int), typeof(RectangleControl), new PropertyMetadata(5));
#endregion
public RectangleControl()
{
InitializeComponent();
Loaded += new RoutedEventHandler(OnLoaded);
}
private void OnLoaded(object sender, RoutedEventArgs args)
{
double rectangleWidth = 20;
double rectangleHeight = 20;
double x = 0;
double y = 0;
for (int i = 0; i < NumRectangles; i++)
{
Brush b = new SolidColorBrush(Colors.Red);
Rectangle r = GenerateRectangle(x, y, rectangleWidth, rectangleHeight, b);
canvas.Children.Add(r);
x += rectangleWidth + 1;
}
}
public Rectangle GenerateRectangle(double x, double y, double width, double height, Brush brush)
{
Rectangle r = new Rectangle();
r.Height = height;
r.Width = width;
r.Fill = brush;
Canvas.SetLeft(r, x);
Canvas.SetTop(r, y);
return r;
}
}
}

When you register your dependency property, you need to provide a handler for the 'changed' event within your PropertyMetadata. See the MSDN documentation here:
http://msdn.microsoft.com/en-us/library/ms557330%28VS.95%29.aspx
The method that you supply as a dependency property change handler will be static so you need to use the arguments passed to this method to obtain a reference to your control. From here you can clear and re-build your UI.

Related

Scroll multiple image in wpf

<Grid>
<Grid.Background>
<ImageBrush ImageSource="Images\Desert.jpg"
Stretch="UniformToFill" TileMode="Tile"
ViewportUnits="Absolute" Viewport="0,0,1024,768"/>
</Grid.Background>
<Grid.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<RectAnimation Storyboard.TargetProperty="Background.Viewport"
To="-1024,0,1024,768" Duration="0:0:10"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
I have this code that scroll a single image in a grid with looping.
Now I have 2 images 1(red) and 2(yellow) am looking something like this.
and it will scroll in loop
You can build a single ImageSource based on multiple images if you wanted to follow your current approach. I have 2 png's (Desert1.png and Desert2.png in an Images folder) and use DataBinding to set the ImageBrush ImageSource to a property defined on the code behind:
<!- Your original xaml ... only difference is the binding -->
<ImageBrush ImageSource="{Binding CombinedImage}"
Stretch="None" TileMode="Tile"
ViewportUnits="Absolute" Viewport="0,0,1024,768"/>
Here's a sample of the code behind (feel free to refactor / use / abuse as you see fit):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xaml;
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var uriSource1 = new Uri(#"pack://application:,,,/Images/Desert1.png", UriKind.Absolute);
BitmapImage bitmapImage1 = new BitmapImage(uriSource1);
var uriSource2 = new Uri(#"pack://application:,,,/Images/Desert2.png", UriKind.Absolute);
BitmapImage bitmapImage2 = new BitmapImage(uriSource2);
this.DataContext = this;
List<BitmapImage> images = new List<BitmapImage>() { bitmapImage1, bitmapImage2 };
CombinedImage = GetCombinedImage(images);
}
private static RenderTargetBitmap GetCombinedImage(IEnumerable<BitmapImage> images )
{
// Get total width of all images
int totalWidthOfAllImages = images.Sum(p => (int)p.Width);
// Get max height of all images
int maxHeightOfAllImages = images.Max(p => (int)p.Height);
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
double left = 0;
foreach (BitmapImage image in images)
{
drawingContext.DrawImage(image, new Rect(left, 0, image.Width, image.Height));
left += image.Width;
}
}
RenderTargetBitmap bmp = new RenderTargetBitmap(totalWidthOfAllImages, maxHeightOfAllImages, 96, 96, PixelFormats.Default);
bmp.Render(drawingVisual);
return bmp;
}
public ImageSource CombinedImage { get; private set; }
}
}
I have code for image slider. I created using user control for windows phone
Please check with this video http://www.screencast.com/t/XnhHwQFY For first time you need to change logic.
But, I think same code you can use for WPF also
ImageSlider.xaml - Create user control
<UserControl x:Class="ImageSliderDemo.ImageSlider"
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"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<Canvas Height="220" x:Name="imageSliderCanvas" Width="451">
<Image x:Name="imageViewOne"
Canvas.Left="0"
Canvas.Top="0"
Height="220" Width="440" Canvas.ZIndex="9">
<Image.RenderTransform>
<TranslateTransform />
</Image.RenderTransform>
</Image>
<Image x:Name="imageViewTwo"
Canvas.Left="0"
Height="220" Width="440" Canvas.ZIndex="10">
<Image.RenderTransform>
<TranslateTransform />
</Image.RenderTransform>
</Image>
</Canvas>
<StackPanel x:Name="PART_Host" />
</Grid>
</UserControl>
ImageSlider.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Markup;
namespace ImageSliderDemo
{
public partial class ImageSlider : UserControl
{
private const int LOWER_ZINDEX = 9, UPPER_ZINDEX = 11, POSITION_FROM480 = 480, POSITION_TO0 = 0;
private int nextImage = 1;
#region "Image Slider Properies"
#region "Property - Length Readonly"
public static readonly DependencyProperty LengthProperty = DependencyProperty.Register("Length", typeof(int), typeof(ImageSlider), new PropertyMetadata(0));
public int Length
{
get { return (int)GetValue(LengthProperty); }
private set { SetValue(LengthProperty, value); }
}
#endregion
#region "Property - Begin Delay Readonly"
public static readonly DependencyProperty BeginDelayProperty = DependencyProperty.Register("BeginDelay", typeof(double), typeof(ImageSlider), new PropertyMetadata(5000.00));
public double BeginDelay
{
get { return (double)GetValue(BeginDelayProperty); }
set { SetValue(BeginDelayProperty, value); }
}
#endregion
#region "Property - Animation Duration Readonly"
public static readonly DependencyProperty AnimationDurationProperty = DependencyProperty.Register("AnimationDuration", typeof(double), typeof(ImageSlider), new PropertyMetadata(900.00));
public double AnimationDuration
{
get { return (double)GetValue(AnimationDurationProperty); }
set { SetValue(AnimationDurationProperty, value); }
}
#endregion
#region "Property - Images"
public static readonly DependencyProperty ImagesProperty = DependencyProperty.Register("Images", typeof(List<SliderImage>), typeof(ImageSlider), new PropertyMetadata(null));
public List<SliderImage> Images
{
get { return (List<SliderImage>)GetValue(ImagesProperty); }
set { SetValue(ImagesProperty, value); }
}
#endregion
#endregion
public ImageSlider()
{
InitializeComponent();
}
/// <summary>
/// This Start method used begin the animation
/// </summary>
public void Start()
{
if (this.Images != null)
{
this.Length = this.Images.Count;
hidePrevious(imageViewOne);
showNext(imageViewTwo);
}
else
{
MessageBox.Show("Please add atleast two images");
}
}
#region "Animation methods"
private void showNext(Image imageView)
{
TranslateTransform trans = imageView.RenderTransform as TranslateTransform;
DoubleAnimation animation = new DoubleAnimation();
animation.To = POSITION_TO0;
animation.Duration = TimeSpan.FromMilliseconds(this.AnimationDuration);
animation.From = POSITION_FROM480;
animation.BeginTime = TimeSpan.FromMilliseconds(this.BeginDelay);
Storyboard.SetTarget(animation, trans);
Storyboard.SetTargetProperty(animation, new
PropertyPath(TranslateTransform.XProperty));
// Create storyboard, add animation, and fire it up!
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
Canvas.SetZIndex(imageView, UPPER_ZINDEX);
imageView.Visibility = Visibility.Visible;
if (nextImage > this.Length)
{
nextImage = 1;
}
BitmapImage nextBitmapImage = new BitmapImage(new Uri(this.Images[nextImage-1].Path, UriKind.Relative));
imageView.Source = nextBitmapImage;
nextImage++;
}
private void hidePrevious(Image imageView)
{
TranslateTransform trans = imageView.RenderTransform as TranslateTransform;
DoubleAnimation animation = new DoubleAnimation();
animation.To = - POSITION_FROM480;
animation.Duration = TimeSpan.FromMilliseconds(this.AnimationDuration);
animation.From = POSITION_TO0;
animation.BeginTime = TimeSpan.FromMilliseconds(this.BeginDelay);
Storyboard.SetTarget(animation, trans);
Storyboard.SetTargetProperty(animation, new
PropertyPath(TranslateTransform.XProperty));
// Create storyboard, add animation, and fire it up!
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
animation.Completed += hideAnimation_Completed;
}
private void hideAnimation_Completed(object sender, EventArgs e)
{
if (Canvas.GetZIndex(imageViewOne) > Canvas.GetZIndex(imageViewTwo))
{
Canvas.SetZIndex(imageViewOne, LOWER_ZINDEX);
hidePrevious(imageViewOne);
showNext(imageViewTwo);
}
else
{
Canvas.SetZIndex(imageViewTwo, LOWER_ZINDEX);
hidePrevious(imageViewTwo);
showNext(imageViewOne);
}
}
#endregion
}
}
Ctrl + B , Just build once
SliderImage.cs -- Add new class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ImageSliderDemo
{
public class SliderImage
{
public string Name { get; set; }
public string Path { get; set; }
public SliderImage(string name, string path)
{
this.Name = name;
this.Path = path;
}
}
}
then do this steps
MainPage.xaml
add at top of xaml page xmlns:local="clr-namespace:[YOUR_PROJECT_NAMESPACE]"
then add just add this below in xaml
<local:ImageSlider x:Name="imageSlider"/>
MainPage.xaml.cs load images
List<SliderImage> images = new List<SliderImage>();
images.Add(new SliderImage("One", "Images/1.png"));
images.Add(new SliderImage("Two", "Images/2.png"));
images.Add(new SliderImage("Three", "Images/3.png"));
images.Add(new SliderImage("Four", "Images/4.png"));
imageSlider.Images = images;
imageSlider.Start();
Note : I used ImageSliderDemo as my namespace. If your using different please make sure you updated in user control as well. And I found only first time it is show same image twice. you can change the logic in ImageSlider.xaml.cs file

Connect a line between two ellipses

I'm trying to connect a line between two ellipses where if one was dragged the line would move with it. I have a canvas and inside that are two stackpanels... in each stackpanel is an ellipse on the left... content control in the middle... and another ellipse on the right. The idea is to connect a line between the right ellipse from one stackpanel to the left ellipse in the second stackpanel. So far I have this but can't seem to get much farther as the propertypath being used to do the binding doesn't make too much sense to me... which is why I have a Canvas in there right now.
Line line = new Line();
line.Stroke = connectedEllipse.Fill;
line.StrokeThickness = 2;
Binding x1 = new Binding();
Binding x2 = new Binding();
Binding y1 = new Binding();
Binding y2 = new Binding();
x1.Path = new PropertyPath(Canvas.LeftProperty);
x2.Path = new PropertyPath(Canvas.LeftProperty);
y1.Path = new PropertyPath(Canvas.TopProperty);
y2.Path = new PropertyPath(Canvas.TopProperty);
x1.Source = y1.Source = connectedEllipse;
x2.Source = y2.Source = (sender as Ellipse);
line.SetBinding(Line.X1Property, x1);
line.SetBinding(Line.X2Property, x2);
line.SetBinding(Line.Y1Property, y1);
line.SetBinding(Line.Y2Property, y2);
Ok I've hacked up some code which doesn't use the attached properties method. This probably isn't "good" code since I wrote it up in 20 minutes but it will get you started.
MainWindow.xaml
<Window x:Class="EllipseTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:EllipseTest"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" >
<Window.Resources>
<ControlTemplate x:Key="template1">
<Ellipse Width="60" Height="30" Fill="Blue" />
</ControlTemplate>
</Window.Resources>
<Canvas Name="canvas">
<my:ExtendedThumb x:Name="thumb1" Canvas.Left ="0" Canvas.Top="0" DragDelta="myThumb_DragDelta" Template="{StaticResource template1}" />
<my:ExtendedThumb x:Name="thumb2" Canvas.Left ="50" Canvas.Top="20" DragDelta="myThumb_DragDelta" Template="{StaticResource template1}" />
</Canvas>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace EllipseTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Path path;
public MainWindow()
{
InitializeComponent();
}
private void myThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
ExtendedThumb thumb = e.Source as ExtendedThumb;
Canvas.SetLeft(thumb, Canvas.GetLeft(thumb) + e.HorizontalChange);
Canvas.SetTop(thumb, Canvas.GetTop(thumb) + e.VerticalChange);
if (thumb == thumb1)
UpdateLine(thumb, thumb2);
else
UpdateLine(thumb1, thumb);
}
private void UpdateLine(ExtendedThumb firstThumb, ExtendedThumb secondThumb)
{
double left1 = Canvas.GetLeft(firstThumb);
double top1 = Canvas.GetTop(firstThumb);
double left2 = Canvas.GetLeft(secondThumb);
double top2 = Canvas.GetTop(secondThumb);
thumb1.ConnectingLine.StartPoint = new Point(left1 +firstThumb.ActualWidth / 2, top1 + firstThumb.ActualHeight / 2);
thumb1.ConnectingLine.EndPoint = new Point(left2 + secondThumb.ActualWidth / 2, top2 + secondThumb.ActualHeight / 2);
thumb2.ConnectingLine.StartPoint = new Point(left2 + secondThumb.ActualWidth / 2, top2 + secondThumb.ActualHeight / 2);
thumb2.ConnectingLine.EndPoint = new Point(left1 + firstThumb.ActualWidth / 2, top1 + firstThumb.ActualHeight / 2);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
path = new Path();
path.Stroke = Brushes.Black;
path.StrokeThickness = 2;
canvas.Children.Add(path);
LineGeometry line = new LineGeometry();
path.Data = line;
thumb1.ConnectingLine = line;
thumb2.ConnectingLine = line;
UpdateLine(thumb1, thumb2);
}
}
}
ExtendedThumb.cs
using System;
using System.Collections.Generic;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Linq;
using System.Text;
namespace EllipseTest
{
public class ExtendedThumb : Thumb
{
public LineGeometry ConnectingLine { get; set; }
public ExtendedThumb() : base() { ConnectingLine = new LineGeometry(); }
}
}
Also, I got the idea from the contents of this link: http://denisvuyka.wordpress.com/2007/10/13/wpf-draggable-objects-and-simple-shape-connectors/

Dragging a WPF Slider thumb with a busy UI thread results in unexpected values

EDIT: There was a lock taken for a long time in the Slider.ValueChanged event. Removing this stops the weirdness. Bad practice, but the behavior still doesn't make sense to me. It probably has to do with the message queue, but I'd like an explanation if possible.
When there is significant work on the UI thread*, the WPF Slider does not interact with the mouse as expected. If I drag the thumb in one direction, the thumb will often advance in front of the mouse cursor, and then go back. The movement should result in only increasing ValueChanged events, but the events sometimes decrease. Sometimes this oscillation happens behind the mouse cursor, too. It seems that the mouse's position is predicted by its current velocity.
Can I change this behavior, or am I doing something wrong?
Toggling IsSnapToTickEnabled doesn't help.
*Assigning a large BitmapSource to an Image. The BitmapSource is created in a worker thread.
<Window x:Class="WPFSliderBug.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">
<Grid>
<Image Name="image1" Stretch="Fill" />
<Slider HorizontalAlignment="Right" Name="slider1" VerticalAlignment="Stretch" Orientation="Vertical" />
</Grid>
</Window>
xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Threading;
namespace WPFSliderBug
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private volatile bool m_run = true;
private double m_sliderValue;
public MainWindow()
{
InitializeComponent();
this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
this.slider1.Minimum = 1;
this.slider1.Maximum = 30;
this.slider1.SmallChange = 0.5;
this.slider1.LargeChange = 0.5;
this.slider1.TickFrequency = 0.5;
this.slider1.TickPlacement = System.Windows.Controls.Primitives.TickPlacement.Both;
this.slider1.ValueChanged += new RoutedPropertyChangedEventHandler<double>(slider1_ValueChanged);
Thread t = new Thread((unused_state) =>
{
while (m_run)
{
BitmapSource bmp;
lock (this)
{
bmp = ToBitmapSource();
bmp.Freeze();
}
this.Dispatcher.Invoke(new Action(delegate()
{
image1.Source = bmp;
}));
}
});
t.Start();
}
void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
lock (this)
{
m_sliderValue = e.NewValue;
}
}
void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
m_run = false;
}
public BitmapSource ToBitmapSource()
{
Random rng = new Random();
double dpi = 96;
int bytesPerPixel = 1;
int width = 2048;
int height = 2048;
int stride = ((width * 32 + 31) & ~31) / 8;
UInt32[] pixelData = new UInt32[width * height];
for (int i = 0; i < pixelData.Length; ++i)
{
double r = rng.NextDouble();
r = Math.Sin(r) * Math.Cos(r) + Math.Asin(r);
pixelData[i] = (uint)(r * UInt32.MaxValue);
}
BitmapSource bmpSource = BitmapSource.Create(width, height, dpi, dpi,
PixelFormats.Bgr32, null, pixelData, stride);
return bmpSource;
}
}
}

How to create a semi transparent form in WPF

I have to develop a semi-transparent form in WPF, but controls should not be transparent.
I have tried different things like setting opacity=0.5 but no result.
I know that AllowTransparency can be set to True only if WindowStyle set to None, but I need to show Border as well
UPDATE:
Pavlo Glazkov, What is your opinion for this solution
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" Opacity="1" AllowsTransparency="True" WindowStyle="None" Background="Transparent">
<Grid Background="Transparent">
<Border Margin="2,2,12,34" Name="border1" BorderBrush="Lavender" BorderThickness="5" CornerRadius="20,0,20,0"></Border>
<Button Height="23" Margin="93,101,110,0" Name="button1" VerticalAlignment="Top" Background="CadetBlue" Foreground="White">Hello WPF</Button>
<Button Height="24" Margin="0,8,20,0" Name="button2" VerticalAlignment="Top" HorizontalAlignment="Right" Width="21" Click="button2_Click">X</Button>
</Grid>
</Window>
First, you need to set AllowTransperency to True. Then, you can set the background of the window to a transparent (to desired extent) brush:
<Window x:Class="MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStyle="None"
AllowsTransparency="True"
Background="{DynamicResource WindowBackground}">
<Window.Resources>
<SolidColorBrush x:Key="WindowBackground"
Color="White"
Opacity="0.5"/>
</Window.Resources>
...
</Window>
Please note that AllowTransperency can be set to True only if WindowStyle set to None.
Update:
If you don't want to set WindowStyle to None and would like to keep standart border and window buttons there is an alternative that will work only on Windows Vista/7 with Windows Aero theme.
The trick is that you can extend the "Glass" area to the whole window using the following code:
public static class WindowUtils
{
/// <summary>
/// Extends the glass area into the client area of the window
/// </summary>
/// <param name="window">Window to extend the glass on.</param>
/// <param name="thikness">Thickness of border to extend.</param>
public static void ExtendGlass(this Window window, Thickness thikness) {
try {
int isGlassEnabled = 0;
Win32.DwmIsCompositionEnabled(ref isGlassEnabled);
if (Environment.OSVersion.Version.Major > 5 && isGlassEnabled > 0) {
// Get the window handle
var helper = new WindowInteropHelper(window);
var mainWindowSrc = HwndSource.FromHwnd(helper.Handle);
if (mainWindowSrc != null) {
if (mainWindowSrc.CompositionTarget != null) {
mainWindowSrc.CompositionTarget.BackgroundColor = Colors.Transparent;
}
// Get the dpi of the screen
System.Drawing.Graphics desktop =
System.Drawing.Graphics.FromHwnd(mainWindowSrc.Handle);
float dpiX = desktop.DpiX / 96;
float dpiY = desktop.DpiY / 96;
// Set Margins
var margins = new MARGINS {
cxLeftWidth = (int)(thikness.Left * dpiX),
cxRightWidth = (int)(thikness.Right * dpiX),
cyBottomHeight = (int)(thikness.Bottom * dpiY),
cyTopHeight = (int)(thikness.Top * dpiY)
};
window.Background = Brushes.Transparent;
Win32.DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, ref margins);
}
}
else {
window.Background = SystemColors.WindowBrush;
}
}
catch (DllNotFoundException) {
}
}
}
public class Win32
{
[DllImport("dwmapi.dll")]
public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
[DllImport("dwmapi.dll")]
public static extern int DwmIsCompositionEnabled(ref int en);
[DllImport("user32.dll")]
public static extern bool SetCursorPos(int X, int Y);
[DllImport("User32", EntryPoint = "ClientToScreen", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern int ClientToScreen(IntPtr hWnd, [In, Out] POINT pt);
}
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
[StructLayout(LayoutKind.Sequential)]
public class POINT
{
public int x = 0;
public int y = 0;
}
To extend the glass to the whole window you need to call the ExtendGlass extension method in a SizeChanged event handler of the window and pass a Thickness that covers whole window:
public MyWindow() {
InitializeComponent();
SizeChanged += OnSizeChanged;
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e) {
double horisontalThickness = Width / 2;
double verticalThickness = Height / 2;
var glassThickness = new Thickness(horisontalThickness, verticalThickness, horisontalThickness, verticalThickness);
this.ExtendGlass(glassThickness);
}
You could try this, it will create a Glass Background for your Window (looks like the Vista and Windows7 transparency effect)
Here is some further explanation from Microsoft.

How can i get startX and startY position?

How can i get the startX and startY position of the rectToGetXAndY. This piece of functionality is very critical to my application but it is driving me crazy. The only approach that comes to my mind is to ask the user to manually click on the top left border of the grid and then handle mouseleftbuttondown event. Obviously this is not the solution i want. Here is my code :-
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="DelSilverlightApp.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"
d:DesignHeight="600" d:DesignWidth="800">
<Grid x:Name="LayoutRoot" Background="DarkSlateGray">
<Grid x:Name="rectToGetXAndY" Background="HotPink" Width="300" Height="300" HorizontalAlignment="Center" VerticalAlignment="Center">
</Grid>
</Grid>
</UserControl>
EDIT :-
This the code behind :-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace DelSilverlightApp
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
GeneralTransform gt = rectToGetXAndY.TransformToVisual(null);
Point p = gt.Transform(new Point(0, 0));
MessageBox.Show(p.X + " " + p.Y);
}
}
}
Thanks in advance :)
I made it work using #AnthonyWJones' code using the following:
XAML
<UserControl x:Class="GetPositionUi.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"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="DarkSlateGray">
<Grid x:Name="rectToGetXAndY"
Background="HotPink"
Width="300"
Height="300"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock x:Name="PositionTextBlock" Text="{Binding Path=ReferencePosition}"/>
</Grid>
</Grid>
</UserControl>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace GetPositionUi
{
public partial class MainPage : UserControl
{
#region ReferencePosition
/// <summary>
/// ReferencePosition Dependency Property
/// </summary>
public static readonly DependencyProperty ReferencePositionProperty =
DependencyProperty.Register("ReferencePosition", typeof(Point), typeof(MainPage),
new PropertyMetadata((Point)(new Point(0, 0)),
new PropertyChangedCallback(OnReferencePositionChanged)));
/// <summary>
/// Gets or sets the ReferencePosition property. This dependency property
/// indicates the reference position of the child element.
/// </summary>
public Point ReferencePosition
{
get { return (Point)GetValue(ReferencePositionProperty); }
set { SetValue(ReferencePositionProperty, value); }
}
/// <summary>
/// Handles changes to the ReferencePosition property.
/// </summary>
private static void OnReferencePositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MainPage)d).OnReferencePositionChanged(e);
}
/// <summary>
/// Provides derived classes an opportunity to handle changes to the ReferencePosition property.
/// </summary>
protected virtual void OnReferencePositionChanged(DependencyPropertyChangedEventArgs e)
{
}
#endregion
public MainPage()
{
InitializeComponent();
}
protected override Size ArrangeOverride(Size finalSize)
{
var arrangedSize = base.ArrangeOverride(finalSize);
GeneralTransform gt = rectToGetXAndY.TransformToVisual(LayoutRoot);
Point p = gt.Transform(new Point(0, 0));
ReferencePosition = p;
return arrangedSize;
}
}
}
The key here is letting the base arrange the controls first, then use the transform to find the position and finally returning the new arrangedSize.
I would not recommend showing a message box at this point, but you can use the dependency property changed callback to do anything you want with the updated position.
In Silveright you can use this code to determine the current X and Y position of rectToGetXAndY relative to LayoutRoot:-
GeneralTransform gt = rectToGetXAndY.TransformToVisual(LayoutRoot);
Point p = gt.Transform(new Point(0, 0));
You can use the VisualTreeHelper...
Vector vector = VisualTreeHelper.GetOffset(rectToGetXAndY);
Point currentPoint = new Point(vector.X, vector.Y);

Resources