Тэги

Silverlight (36) WPF (10) IIS (7) Visual Studio (7) SharePoint (6) .Net Framework (5) ODP.NET (5) ASP.NET (4) C# (4) common (4) Network Settings (3) JavaScript (2) MS Office (2) Resharper (2) WCF (2) WEB (2) XPath (2) XSLT (2) ADO.NET (1) APEX (1) CMD (1) CSS (1) EF (1) HTML (1) Hardware bugs (1) Java (1) MS SQL (1) Oracle (1) PDF (1) Version Control (1) XAML (1)

понедельник, 28 сентября 2009 г.

Создание изображения из экранного вывода WPF и Silverlight. Попросту Snapshot из Silverlight и WPF.



Мне не терпиться поделиться новостью, что несколькими строчками кода можно создать изображение из любого элемента Silverlight или WPF. Для этого не нужно использовать Windows API (хотя тоже можно, как вариант).

Применяются для получения изображений классы из пространства имен .NET Framework System.Windows.Media.Imaging и System.Windows.Media.
Можно получить снэпшет как с любого элемента, так и со всего окна сразу. Полученное изображение в Silverlight можно передать по WCF на сервер или даже предложить пользователю сохранить на диск.

Я создал примеры для WPF и Silverlight. Мне требуется их осмыслить, немного причесать перед выкладыванием, но срочный проект на работе забрал все мои ресурсы, в т.ч. свободного времени. Я заимусь этим позже, тк всеравно это будет использоватся по работе. Но я считаю, что мы все грамотные разработчики, поэтому для нас действует принцип: “Осведомлен, значит вооружен”.
Итак, я вас вооружил :) Погуглите, поищите в MSDN-форумах, походите по блогам. В том числе вы наткнетесь и на мои сырые примеры в комментариях.

И всетаки вот куски кода, скорее всего они будут вам очень полезны, если я не доберусь до этого поста.

Для Silverlight
_______________________________
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Media;

namespace SilverlightApplication2
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }        private void Button_Click(object sender, RoutedEventArgs e)
        {
            WriteableBitmap bit = new WriteableBitmap(this, null);
            bit.Render(this, new MatrixTransform());
            Image img = new Image();
            img.Source = bit;
            StackPanel1.Children.Clear();            Border border = new Border();
            var brush = new SolidColorBrush(SystemColors.ActiveBorderColor);
            border.BorderBrush = brush;
            border.BorderThickness = new Thickness(20);
            border.Child = img;            StackPanel1.Children.Add(border);
        }
    }
}
+===============================+
<UserControl x:Class="SilverlightApplication2.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:DesignWidth="640" d:DesignHeight="480">
    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="0">
            <TextBox Width="100"></TextBox>
            <TextBox Width="100"></TextBox>
            <Button Width="100" Content="Update" Click="Button_Click"></Button>
        </StackPanel>
        <StackPanel x:Name="StackPanel1" Grid.Column="1" VerticalAlignment="Center">
        </StackPanel>
    </Grid>
</UserControl>
______________________________________________Для WPF
_______________________________
<Window x:Class="CaptureBitmapImage.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"
        Background="Red"
        >
    <Grid>
        <Border>
            <Button Background="Yellow" Height="23" Name="button1" Width="75" Click="button1_Click">Button</Button>
        </Border>
    </Grid>
</Window>
+================================+
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;
using System.IO;namespace CaptureBitmapImage
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }        private void button1_Click(object sender, RoutedEventArgs e)
        {
            SaveWindowSnapshot(this, "!!!__!!!__MyWindowSnapshot.jpg");            // add Button name "button1" before
            SaveWindowSnapshot(button1, "!!!__!!!__MyButtonSnapshot.jpg");
        }        private void SaveWindowSnapshot(Visual targetVisual, string fileName)
        {
            Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
            double myDeviceDpiX = m.M11 * 96.0;
            double myDeviceDpiY = m.M22 * 96.0;            BitmapSource bitmapSource = captureVisualBitmap(
                targetVisual,
                myDeviceDpiX,
                myDeviceDpiY
                );            var imgStream = GrabSnapshotStream(bitmapSource, myDeviceDpiX, myDeviceDpiY, ImageFormats.JPG);
            using (imgStream)
            {
                imgStream.Position = 0;                var fileStream = new FileStream(@"c:/" + fileName, FileMode.OpenOrCreate);
                using (fileStream)
                {
                    for (int i = 0; i < imgStream.Length; i++)
                    {
                        fileStream.WriteByte((byte)imgStream.ReadByte());
                    }
                }
            }
        }        private static BitmapSource captureVisualBitmap(Visual targetVisual, double dpiX, double dpiY)
        {
            Rect bounds = VisualTreeHelper.GetDescendantBounds(targetVisual);            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(
                (int)(bounds.Width * dpiX / 96.0),
                (int)(bounds.Height * dpiY / 96.0),
                dpiX,
                dpiY,                //PixelFormats.Default
                PixelFormats.Pbgra32
                );            DrawingVisual drawingVisual = new DrawingVisual();
            using (DrawingContext drawingContext = drawingVisual.RenderOpen())
            {
                VisualBrush visualBrush = new VisualBrush(targetVisual);
                drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(), bounds.Size));
            }
            renderTargetBitmap.Render(drawingVisual);            return renderTargetBitmap;
        }        public static MemoryStream GrabSnapshotStream(BitmapSource bitmapSource, double dpiX, double dpiY, ImageFormats imageFormats)
        {
            BitmapEncoder bitmapEncoder;            switch (imageFormats)
            {
                case ImageFormats.PNG:
                    {
                        bitmapEncoder = new PngBitmapEncoder();
                        break;
                    }
                case ImageFormats.BMP:
                    {
                        bitmapEncoder = new BmpBitmapEncoder();
                        break;
                    }
                case ImageFormats.JPG:
                    {
                        bitmapEncoder = new JpegBitmapEncoder();
                        break;
                    }
                default:
                    throw new NotSupportedException("The Incorrect Logic");
            }            bitmapEncoder.Frames.Add(BitmapFrame.Create(bitmapSource));            // Create a MemoryStream with the image.
            // Returning this as a MemoryStream makes it easier to save the image to a file or simply display it anywhere.
            var memoryStream = new MemoryStream();
            bitmapEncoder.Save(memoryStream);            return memoryStream;
        }        public enum ImageFormats
        {
            PNG,
            BMP,
            JPG
        }
    }
}Источники:
Коллеги, погуглите, при случае привиду ссылки. Я сам гуглил.

четверг, 24 сентября 2009 г.

Silverlight не поддерживает RoutedEvent в EventTrigger, кроме Loaded



Если вы получили похожую ошибку:
Unhandled Error in Silverlight Application Attribute UIElement.MouseEnter value is out of range.
то давайте ее полечим.

Исходный код: Source for VS 2008

Книга "Введение в Silverlight 3" на странице 112 говорит “... обратите внимание, что RoutedEvent поддерживает только событие Loaded (Загружен).” Т.е. как в WPF, декларативно через XALM, это не работает.
Т.е. Silverlight 3 (и предшественники) для атрибута RoutedEvent в элементе EventTrigger в XALM разметке поддерживает только значение Loaded.

Но уже давно есть решение, например RoutedEvent on EventTrigger is giving error that Rectangle.MouseEnter value is out of range
Опишу его более подробно. Сначала посмотрим на разметку:

<UserControl x:Class="SilverlightAnimation.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:DesignWidth="640" d:DesignHeight="480">
<Grid Name="LayoutRoot" Margin="2" MouseEnter="LayoutRoot_MouseEnter" Background="Red">
<Grid.Resources>
<!--<Storyboard x:Name="LayoutRootStoryboard">-->
<Storyboard x:Key="LayoutRootStoryboard">
<DoubleAnimation
Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="Opacity"
From="1" To="0"
/>
</Storyboard>
</Grid.Resources>
<TextBlock Text="Как всикда, превед митвет!" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</UserControl>


и посмотрим на код обработчиика LayoutRoot_MouseEnter

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;


namespace SilverlightAnimation
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}


private void LayoutRoot_MouseEnter(object sender, MouseEventArgs e)
{
var element = (FrameworkElement)sender;
// если вы задали ключ x:Key или имя x:Name
var storyboard = (Storyboard)element.Resources["LayoutRootStoryboard"];
// строчка ниже будет работа только если вы задали имя x:Name
//var storyboard = (Storyboard)element.FindName("LayoutRootStoryboard");


storyboard.Begin();
}
}
}


Смысл этого в следующем:

  • Кидаем Storyboard в ресурсы любого элемента.

  • Если в коде мы легко получаем доступ к элементу, в ресурсах которого лежит Storyboard, то можем использовать обращение по ключю < Storyboard x:Key=”” >.
    Вот так мы будем доставать Storyboard :
    (Storyboard)element.Resources["LayoutRootStoryboard"];

  • Иначе можем идентифировать Storyboard по имени x:Name, но тогда оно должно быть уникальным в разметке XALM.
    Вот так получаем:
    (Storyboard)element.FindName("LayoutRootStoryboard");
    здесь element может быть любым элементом на странице

  • Запускаем анимацию методом .Begin()


вторник, 22 сентября 2009 г.

WPF-серия. Группы валидации в WPF



Пока разбирался с валидацией в WPF успел создать функционал групп валидации, наподобии ASP.NET. Сделал свои ананлог, но теперь, честно говоря, досканально поняв и поработав с валидацией в WPF и Silverlight, я бы сделал группы валидации по другому, а может и не стал бы делать вообще. Слишком большое поле для кастомизации, что-бы еще притаскивать на это “поле” группы валидации.

 

Выделение любого текста в GUI Silverlight и WPF



Задача сделать пользовательский интерфейс, в котором, как в браузере можно выделять любой текст.
Другими словами, чтоб любой текст на экране можно было выделить, а не талько в элементах для ввода текста.

В WPF для этого используется немного настроенный TextBox со свойством IsReadOnly=”true”
Используется следующий стиль
<Style x:Key="Texted" TargetType="TextBox">
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="IsTabStop" Value="False" />
</Style>


В Silverlight 3 этот фокус теперь не пройдет, тк появилось закрашивание серым цветом если IsReadOnly=”true”
Решается это следующим кастомным стилем (например разместите его в App.xaml в ResourceDictionary)
<Style x:Key="OnlySelectedTextBox" TargetType="TextBox">
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid x:Name="RootElement">
<Border x:Name="Border" Opacity="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1">
<ScrollViewer x:Name="ContentElement" BorderThickness="0" IsTabStop="False" Padding="{TemplateBinding Padding}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>


Далее можете на любой странице применять следующее
<TextBox Text="LaLa:" Style="{StaticResource OnlySelectedTextBox}"/>

Замечание!
Я немного сильно доработал шаблон контрола в этом стиле. Если вам нужно что-то более нежное с сохранением всего функционала TextBox, то используйте вот это preventing greyed-out effect when TextBox.IsReadOnly = true
Там говориться, что надо подправить полностью содрать через Expression Blend 3 стиль TextBox, задать ему имя, и поменять одну строчку в стиле, отвечающую за закрашивание
<Border x:Name="ReadOnlyVisualElement" Opacity="0" Background="#5EC9C9C9"/>
на
<Border x:Name="ReadOnlyVisualElement" Opacity="0"/>
Далее можно использовать как у меня <TextBox Text="LaLa:" Style="{StaticResource MyTextBoxStyle}"/>