Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WPF, Silverlight Новый топик    Ответить
 Всплывающее окно с затемнением формы  [new]
Nechto
Member

Откуда:
Сообщений: 825
Здравствуйте!
Помогите пожалуйста разобраться с концепцией. Имею следующую разметку с Frame-ом:
<Window>
<DockPane>

...

<DockPanel DockPanel.Dock="Top">
<Frame x:Name="Browser" NavigationUIVisibility="Hidden" />
</DockPanel>

</DockPanel>
</Window>
В данный Frame я выгружаю различные представления.

Для себя поставил задачу реализовать всплывающее окно, с затемнением основного окна. И когда начал думать как это сделать, я несколько запутался в каком направлении идти.
5 сен 15, 18:01    [18113179]     Ответить | Цитировать Сообщить модератору
 Re: Всплывающее окно с затемнением формы  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4030
Nechto
Здравствуйте!
Помогите пожалуйста разобраться с концепцией. Имею следующую разметку с Frame-ом:
<Window>
<DockPane>

...

<DockPanel DockPanel.Dock="Top">
<Frame x:Name="Browser" NavigationUIVisibility="Hidden" />
</DockPanel>

</DockPanel>
</Window>
В данный Frame я выгружаю различные представления.

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

Я делаю по другому.
Для затемнения формы лучше всего использовать Adorner. Само диалоговое окно я сделал как отдельный FrameworkElement, у этого элемента есть 2 свойства Content и ContentTemplate, Content это модель (View Model), ContentTemplate это шаблон DataTemplate.
И свойство IsOpen, а так же CommandBinding для открытия по команде.
В самом диалоговом окно содержимое можно задать в шаблоне, я для обработки нажатия кнопок использовать модель диалогового окна или маршрутизируемые команды (для 2ого, нужно сделать проброс команд из 1 окна в окно из которого открывается).
Затем либо с помощью триггера, либо с помощью Binding'а, либо с помощью Command'ы можно открыть окно. Если открывать через команду можно передать модель в параметрах.
Так же полезно будет создать свойство Style которое будет определять свойства открываемого (диалогового окна)
Как сделать затемнение?
При изменении свойства IsOpen, с помощью LogicalTree находите открытое окно. Это предпоследний элемент дерева, либо искать по типу Window.
Затем создаем свой AdornerDecorator, этот базовый класс от Decorator, который в свою очередь наследуется от FrameworkElement, а значит и Visual. Суть этого элемента в том, что его можно разместить поверх другого контрола (так же как Focus или самый начальный Adorner окна. Внутри разместить Visual элемент с чёрным цветом и полной прозрачностью, а затем с помощью ColorAnimation снижаем прозрачность.
Для производительность поверх черного квадрата можно создать квадрат с кистью VisualBrush, который будет копировать содержимое окна, тогда не будет постоянно видимых элементов управления.
После того как IsOpen снова становится False, мы выполняем обратную анимацию и удаляем Adorner.

Вот так. Код могу дать завтра, дома у меня нет, писать лень :)
5 сен 15, 20:56    [18113542]     Ответить | Цитировать Сообщить модератору
 Re: Всплывающее окно с затемнением формы  [new]
Nechto
Member

Откуда:
Сообщений: 825
Буду очень признателен за код вашего велосипеда.
А готовые велосипеды от есть?
7 сен 15, 07:21    [18116800]     Ответить | Цитировать Сообщить модератору
 Re: Всплывающее окно с затемнением формы  [new]
maratoss
Member

Откуда: от верблюда
Сообщений: 137
Nechto,

Можно же просто бэкграунд окна сделать прозрачным и черным, вот и будет затемнение
что-то вроде такого:

<Window x:Class="WpfApplication3.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"
        AllowsTransparency="True" WindowStyle="None">
    <Window.Background>
        <SolidColorBrush Opacity="0.5" Color="White"/>
    </Window.Background>
    <Grid>
        <Button Width="200" Height="50">button</Button>
    </Grid>
</Window>


Ну или можешь глянуть сюда http://mahapps.com/ там есть всплывашки
8 сен 15, 09:35    [18121572]     Ответить | Цитировать Сообщить модератору
 Re: Всплывающее окно с затемнением формы  [new]
Nechto
Member

Откуда:
Сообщений: 825
maratoss
Nechto,

Можно же просто бэкграунд окна сделать прозрачным и черным, вот и будет затемнение
что-то вроде такого:

<Window x:Class="WpfApplication3.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"
        AllowsTransparency="True" WindowStyle="None">
    <Window.Background>
        <SolidColorBrush Opacity="0.5" Color="White"/>
    </Window.Background>
    <Grid>
        <Button Width="200" Height="50">button</Button>
    </Grid>
</Window>


Ну или можешь глянуть сюда http://mahapps.com/ там есть всплывашки


Этот Dialog у mahapps, тоже самое что и Telerik http://docs.telerik.com/devtools/wpf/controls/radwindow/features/predefined-dialogs
15 сен 15, 07:58    [18149377]     Ответить | Цитировать Сообщить модератору
 Re: Всплывающее окно с затемнением формы  [new]
Nechto
Member

Откуда:
Сообщений: 825
Просто затемнение для меня мало. Мне нужно чтобы накладывался затемненный прозрачный слой на всю рабочую область окна, тем блокировав все что находится по этим слоем. А на этом слое мне нужен слой в котором я могу отображать контролы.
15 сен 15, 08:10    [18149399]     Ответить | Цитировать Сообщить модератору
 Re: Всплывающее окно с затемнением формы  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4030
вот вам рабочий пример, за вас делать всё мне лень, разбирайтесь и делайте как вам удобнее.
Лично я использую маршрутизируемые команды и самописный обвес для прослушивания этих команд и вызова соответствующих команд в ViewModel, их я в пример не привёл.
Окно открывается по свойство IsOpen = true, либо по маршрутизируемой команде OpenDialog, которую надо передать в диалог.
Стиль окна задается через WindowStyle, содержимое передается через ContentPresenter (содержимое, шаблонданных)
Затемнение происходит именно так, как вам и нужно (на сколько я понял).
View:
+
<Application x:Class="SizeVisualizer.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:sizeVisualizer="clr-namespace:SizeVisualizer"
             xmlns:system="clr-namespace:System;assembly=mscorlib"
             StartupUri="DemoWindow.xaml">
    <Application.Resources>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Width" Value="150"/>
            <Setter Property="Height" Value="32"/>
            <Setter Property="Margin" Value="5" />
        </Style>
        <system:String x:Key="DialogText">
            Здравствуйте!
Помогите пожалуйста разобраться с концепцией. Имею следующую разметку с Frame-ом:
В данный Frame я выгружаю различные представления.
Для себя поставил задачу реализовать всплывающее окно, с затемнением основного окна. И когда начал думать как это сделать, я несколько запутался в каком направлении идти.
        </system:String>
        <sizeVisualizer:MainModel x:Key="MainModel"/>
    </Application.Resources>
</Application>

<Window x:Class="SizeVisualizer.DemoWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:commonControls="clr-namespace:CommonControls;assembly=CommonControls"
        Title="DemoWindow" Height="300" Width="500"
        DataContext="{StaticResource MainModel}">
    <Window.Resources>
        <DataTemplate x:Key="DialogWindowTemplate">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <TextBlock Grid.Row="0" 
                           HorizontalAlignment="Center" VerticalAlignment="Center" 
                           TextWrapping="Wrap"
                           Text="{StaticResource DialogText}"/>
                <StackPanel Grid.Row="1"
                            Orientation="Horizontal" >
                    <Button Content="Ok" IsDefault="True"/>
                    <Button Content="Cancel" IsCancel="True"/>
                </StackPanel>
                
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <commonControls:DialogWindow x:Name="Dialog" Header="Dialog Window"
                                     Content="{Binding Dialog}"
                                     ContentTemplate="{StaticResource DialogWindowTemplate}" Margin="0,-10,0,10">
            <commonControls:DialogWindow.WindowStyle>
                <Style TargetType="{x:Type Window}">
                    <Setter Property="MaxWidth" Value="500"/>
                </Style>
            </commonControls:DialogWindow.WindowStyle>
        </commonControls:DialogWindow>

        <Button VerticalAlignment="Top" HorizontalAlignment="Left"
                Content="Open Dialog"
                Command="{x:Static commonControls:DialogWindow.OpenDialog}"
                CommandTarget="{Binding ElementName=Dialog}"/>
        <TextBox Width="300" VerticalAlignment="Center" HorizontalAlignment="Center"/>
    </Grid>
</Window>

ViewModel:

+
namespace SizeVisualizer
{
    public class MainModel
    {
        public string Value { set; get; }

        public MainModel()
        {
            Value = "Example";
        }

        public DialogModel Dialog { set; get; }
    }

    public class DialogModel
    {
        public string Value { set; get; }
    }
}


Control (Theme resource):
    <Style TargetType="{x:Type local:DialogWindow}">
        <Setter Property="Template" Value="{x:Null}"/>
    </Style>
    
    <Style TargetType="{x:Type local:DlgWindow}">
        <Setter Property="Background" Value="White"/>
        <Setter Property="BorderBrush" Value="#A0000000"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="ResizeMode" Value="CanResizeWithGrip"/>
        <Setter Property="SizeToContent" Value="WidthAndHeight"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:DlgWindow}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}" 
                            BorderThickness="{TemplateBinding BorderThickness}" 
                            CornerRadius="2" Margin="0,0,5,5">
                        <Border.Effect>
                            <DropShadowEffect Opacity="0.5" Color="{TemplateBinding BorderBrush}" ShadowDepth="5"/>
                        </Border.Effect>
                        <AdornerDecorator>
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" x:Name="HeaderRow"/>
                                    <RowDefinition Height="Auto" x:Name="HeaderSeparator"/>
                                    <RowDefinition Height="Auto" x:Name="ContentRow"/>
                                </Grid.RowDefinitions>
                            
                                <!-- HEADER -->
                                <ContentPresenter Content="{TemplateBinding Header}" Grid.Row="0" Margin="14,5" />
                            
                                <Rectangle Height="1" Fill="#E5E5E5" Grid.Row="1"  Margin="14,0"/>
                            
                                <!-- CONTENT -->
                                <ContentPresenter Grid.Row="2" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                            </Grid>
                        </AdornerDecorator>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Control code:
+

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

namespace CommonControls
{
    public class DialogWindow : ContentControl
    {

        public static ICommand OpenDialog = new RoutedCommand("OpenDialog", typeof (DialogWindow));

        private Popup a;
        private AdornerContainer _adornerContainer;
        private Visual _rootElement;
        private IAnimatable _border;

        public Style WindowStyle
        {
            get { return (Style)GetValue(WindowStyleProperty); }
            set { SetValue(WindowStyleProperty, value); }
        }
        
        public static readonly DependencyProperty WindowStyleProperty =
            DependencyProperty.Register("WindowStyle", typeof(Style), typeof(DialogWindow), new PropertyMetadata(null));
        
        public bool IsOpen
        {
            get { return (bool)GetValue(IsOpenProperty); }
            set { SetValue(IsOpenProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsOpen.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsOpenProperty =
            DependencyProperty.Register("IsOpen", typeof(bool), typeof(DialogWindow), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault , IsOpenChanged));


        private Window _openWindow = null;

        private static void IsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var dw = (DialogWindow)d;
            var isOpen = (bool) e.NewValue;
            var oldIsOpen = (bool) e.OldValue;
            if (isOpen && !oldIsOpen)
            {
                var window = Window.GetWindow(dw);
                if (window != null)
                {
                    var dialogWindow = new DlgWindow
                    {
                        Header = dw.Header,
                        MinWidth = 50,
                        MinHeight = 50,
                        Owner = window,
                        AllowsTransparency = true,
                        WindowStyle = System.Windows.WindowStyle.None,
                        ResizeMode = ResizeMode.NoResize,
                        WindowStartupLocation = WindowStartupLocation.CenterOwner,
                        DataContext = dw.DataContext,
                        Style = (Style)dw.GetValue(WindowStyleProperty),
                        Content = dw.Content,
                        ContentTemplate = dw.ContentTemplate,
                        ContentTemplateSelector = dw.ContentTemplateSelector
                    };

                    dialogWindow.AddHandler(CommandManager.CanExecuteEvent, new RoutedEventHandler(dw.OnRoutedEvent));
                    dialogWindow.AddHandler(CommandManager.ExecutedEvent, new RoutedEventHandler(dw.OnRoutedEvent));

                    dw.Blur();
                    dw._openWindow = dialogWindow;
                    dialogWindow.ShowDialog();

                    dialogWindow.RemoveHandler(CommandManager.CanExecuteEvent, new RoutedEventHandler(dw.OnRoutedEvent));
                    dialogWindow.RemoveHandler(CommandManager.ExecutedEvent, new RoutedEventHandler(dw.OnRoutedEvent));

                    dialogWindow.DataContext = null;

                    dw.Dispatcher.BeginInvoke(new Action(() => dw.IsOpen = false),
                        System.Windows.Threading.DispatcherPriority.ApplicationIdle);
                    dw.Clear();
                }
            }
            if (!isOpen && oldIsOpen && dw._openWindow != null)
            {
                dw._openWindow.Close();
            }
        }

        #region Animation
        private void Blur()
        {
            //Находим корневой визуальный объект
            var root = VisualTree.FindVisualRoot(this) as Visual;
            //Если это окно, то оно не может иметь Adorner так как у окна он уже есть, по этому находим ContentPresenter этого окна
            if (root is Window) root = VisualTree.FindChild<ContentPresenter>(root);
            if (root == null) return;
            _rootElement = root;
            //Получаем Adorner
            var adornerLayer = AdornerLayer.GetAdornerLayer(root);
            //Если адорнер всё равно не найден, просто не затемняем
            if (adornerLayer == null) return;
            //Создаем контейнер
            if (_adornerContainer == null)
            {
                _border = new Border
                {
                    Background = new SolidColorBrush(Colors.Black),
                    Opacity = 0.0
                };
                _adornerContainer = new AdornerContainer((UIElement)root) { Child = (UIElement)_border };
            }
            adornerLayer.Add(_adornerContainer);

            var animation = new DoubleAnimation
            {
                To = 0.5,
                Duration = TimeSpan.FromSeconds(0.3)
            };
            _border.BeginAnimation(OpacityProperty, animation);
        }


        private void Clear()
        {
            var animation = new DoubleAnimation
            {
                To = 0.0,
                Duration = TimeSpan.FromSeconds(0.3)
            };
            //По завершению анимации удаляем Adorner и удаляем все 
            animation.Completed += animation_Completed;
            _border.BeginAnimation(OpacityProperty, animation);
        }

        void animation_Completed(object sender, EventArgs e)
        {
            if (_rootElement != null)
            {
                var adornerLayer = AdornerLayer.GetAdornerLayer(_rootElement);
                if (_adornerContainer != null)
                {
                    adornerLayer.Remove(_adornerContainer);
                    _adornerContainer = null;
                    _border = null;
                }
                _rootElement = null;
            }
        }
        #endregion

        public object Header
        {
            get { return (object)GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        public static readonly DependencyProperty HeaderProperty =
            DependencyProperty.Register("Header", typeof(object), typeof(DialogWindow), new PropertyMetadata(null));

        static DialogWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DialogWindow), new FrameworkPropertyMetadata(typeof(DialogWindow)));
            FocusableProperty.OverrideMetadata(typeof(DialogWindow), new FrameworkPropertyMetadata(false));
        }

        public DialogWindow()
        {
            CommandBindings.Add(new CommandBinding(OpenDialog, OnOpenDialog));
        }

        private void OnOpenDialog(object sender, ExecutedRoutedEventArgs e)
        {
            IsOpen = true;
        }

        private void OnRoutedEvent(object sender, RoutedEventArgs e)
        {
            if (!e.Handled) RaiseEvent(e);
        }

    }
}

using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;

namespace CommonControls
{
    public class DlgWindow : Window
    {


        public object Header
        {
            get { return (object)GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }
        public static readonly DependencyProperty HeaderProperty =
            DependencyProperty.Register("Header", typeof(object), typeof(DlgWindow), new PropertyMetadata(null));


        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);
            DragMove();
        }

        static DlgWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DlgWindow), new FrameworkPropertyMetadata(typeof(DlgWindow)));
        }
        
        public IEnumerable<ICommand> Commands
        {
            get { return (IEnumerable<ICommand>)GetValue(CommandsProperty); }
            set { SetValue(CommandsProperty, value); }
        }

        public static readonly DependencyProperty CommandsProperty =
            DependencyProperty.Register("Commands", typeof(IEnumerable<ICommand>), typeof(DlgWindow), new PropertyMetadata(null));

        
    }
}



будут вопросы, пишите
15 сен 15, 10:51    [18150212]     Ответить | Цитировать Сообщить модератору
 Re: Всплывающее окно с затемнением формы  [new]
maratoss
Member

Откуда: от верблюда
Сообщений: 137
Nechto
Просто затемнение для меня мало. Мне нужно чтобы накладывался затемненный прозрачный слой на всю рабочую область окна, тем блокировав все что находится по этим слоем. А на этом слое мне нужен слой в котором я могу отображать контролы.


Вот прозрачный затемненный фон, который блокирует все что сзади и непрозрачные контролы на нем, по которым можно щелкать.
Или я неправильно понял?

К сообщению приложен файл. Размер - 46Kb
16 сен 15, 13:27    [18155750]     Ответить | Цитировать Сообщить модератору
Все форумы / WPF, Silverlight Ответить