Рейтинг@Mail.ru

Как создать безрамочное окно в WPF

Опубликовано в Полезные советы

Чтобы создать окно без рамок и без стандартных элементов управления, в файле разметки в свойствах окна достаточно добавить 3 атрибута: WindowStyle, AllowsTransparency и Background.

<Window x:Class="BorderlessWindow"
        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"
        WindowStyle="None"
        AllowsTransparency="True"
        Background="Transparent"
        MouseLeftButtonDown="Window_MouseLeftButtonDown"
        Title="Hello, Soltau.ru"
        Width="200" Height="200">
    <Grid>
        <Rectangle Fill="Yellow" Opacity="0.7" RadiusX="40" RadiusY="40" />
        <Button Width="100" Height="30" Content="Закрыть" Click="Button_Click" />
    </Grid>
</Window>

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

Public Class BorderlessWindow

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        Me.Close()
    End Sub

    Private Sub Window_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
        Me.DragMove()
    End Sub

End Class

Выглядеть это будет примерно так:

Окно без рамок в WPF
Окно без рамок в WPF
Подробнее ...

Красивое диалоговое окно в .NET

Опубликовано в Полезные советы

Чтобы вместо стандартного MessageBox в приложении WPF использовать более современное и «красивое» окно, можно использовать средства самой Windows. Напишем класс-помощник, который будет выводить диалоговое окно, используя системную библиотеку comctl32.dll.

Imports System.Runtime.InteropServices

''' <summary>
''' "Красивое" диалоговое окно.
''' </summary>
Public Module TaskDialogHelper

    <DllImport("comctl32.dll", CharSet:=CharSet.Unicode, PreserveSig:=False)>
    Public Function TaskDialog(hwndParent As IntPtr, hInstance As IntPtr, title As String, mainInstruction As String, content As String, buttons As TaskDialogButtons, icon As TaskDialogIcon) As TaskDialogResult
    End Function

    Public Enum TaskDialogResult As Integer
        Ok = 1
        Cancel = 2
        Retry = 4
        Yes = 6
        No = 7
        Close = 8
    End Enum

    <Flags>
    Public Enum TaskDialogButtons As Integer
        Ok = &H1
        Yes = &H2
        No = &H4
        Cancel = &H8
        Retry = &H10
        Close = &H20
    End Enum

    Public Enum TaskDialogIcon As Integer
        Shield = 65532
        Information 
        [Error] 
        Warning 
    End Enum

End Module

Также в манифесте проекта необходимо раскомментировать следующий участок:

  <dependency>
    <dependentAssembly>
      <assemblyIdentity
          type="win32"
          name="Microsoft.Windows.Common-Controls"
          version="6.0.0.0"
          processorArchitecture="*"
          publicKeyToken="6595b64144ccf1df"
          language="*"
        />
    </dependentAssembly>
  </dependency>

Использовать код можно таким образом:

Dim dr = TaskDialogHelper.TaskDialog(New System.Windows.Interop.WindowInteropHelper(Me).Handle,
    IntPtr.Zero,
    "Лаконичный заголовок окна",
    "Здесь будет основной текст сообщения.",
    "А здесь вспомогательный.",
    TaskDialogHelper.TaskDialogButtons.Yes Or TaskDialogHelper.TaskDialogButtons.No,
    TaskDialogHelper.TaskDialogIcon.Information)

Желательно также при выводе данного окна проверять версию операционной системы: данное окно можно использовать в Windows Vista и более современных (версия больше 6):

If (System.Environment.OSVersion.Version.Major >= 6) Then 
    …
Подробнее ...

Изменяемая асинхронно наблюдаемая коллекция ObservableCollection

Опубликовано в Полезные советы

Наблюдаемые коллекции ObservableCollection в WPF можно изменять толкько в потоке пользовательского интерфейса. Однако можно несколько изменить данную коллекцию таким образом, чтобы можно было это делать из фонового потока. Например, вот так:

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Collections.Specialized
Imports System.Diagnostics
Imports System.Windows.Threading

Public Class ObservableCollectionThreadSafe(Of T)
    Inherits ObservableCollection(Of T) 'наследуем от наблюдаемой коллекции

    'Переопределяем событие изменения коллекции
    Public Shadows Event CollectionChanged As NotifyCollectionChangedEventHandler

#Region "КОНСТРУКТОРЫ"

    Public Sub New()
        MyBase.New()
    End Sub

    Public Sub New(items As IEnumerable(Of T))
        MyBase.New(items)
    End Sub

#End Region '/КОНСТРУКТОРЫ

    Protected Overrides Sub OnCollectionChanged(e As NotifyCollectionChangedEventArgs)
        Using MyBase.BlockReentrancy() 'используем BlockReentrancy(), который запрещает выполнение повторных попыток изменения коллекции
            Dim eventHandler As NotifyCollectionChangedEventHandler = Me.CollectionChangedEvent
            If (eventHandler IsNot Nothing) Then
                Dim delegates As [Delegate]() = eventHandler.GetInvocationList()
                For Each handler As NotifyCollectionChangedEventHandler In delegates 'идём по списку вызовов 
                    Dim dispatcherObject As DispatcherObject = TryCast(handler.Target, DispatcherObject)
                    If (dispatcherObject IsNot Nothing) AndAlso (Not dispatcherObject.CheckAccess()) Then 'Если подписчик - DispatcherObject И другой поток
                        dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, Me, New Object() {e}) 'вызываем обработчик в целевом потоке диспетчера
                    Else
                        handler(Me, e) 'иначе запускаем обработчик как есть
                    End If
                Next
            End If
        End Using
    End Sub

End Class
Подробнее ...

Запрет выделения элементов ListBox / ListView (WPF)

Опубликовано в Полезные советы

Чтобы запретить выделение элементов элемента ListBox или ListView, можно определить это с помощью такого стиля:

<ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
         <Setter Property="Focusable" Value="False" />
    </Style>
</ListBox.ItemContainerStyle>

Второй вариант – использовать вместо ListBox элемент ItemsControl.

Подробнее ...

Как определить текущую привязку Binding элемента UI

Опубликовано в Полезные советы

Допустим, что мы задали в XAML для текстового элемента TextBlock привязку и хотим узнать её в застраничном коде. Это делается так:

    Dim be As BindingExpression = myTextBlock.GetBindingExpression(TextBlock.TextProperty)
    Dim bnd As Binding = be.ParentBinding
    Dim bindingPath As String = bnd.Path.Path
Подробнее ...

Аналог StartupPath в WPF

Опубликовано в Полезные советы

В приложениях Windows Forms была возможность определить каталог, из которого запускалось приложение, так:

    Dim startup As String = Application.StartupPath

В WPF данная возможность не работает. Теперь для определения текущей директории приложения нужно вызвать следующий код:

    Dim startup As String = System.AppDomain.CurrentDomain.BaseDirectory
Подробнее ...

Observable collection с уведомлением при добавлении диапазона значений

Опубликовано в Полезные советы

В .NET есть такой перечислимый тип как ObservableCollection. Его особенность в том, что эта коллекция при изменении её элементов (добавлении или удалении), уведомляет наблюдающие за ней классы об этом изменении. Это бывает полезно, например, когда к данной коллекции привязаны элементы пользовательского интерфейса. Но если необходимо добавить в коллекцию сразу множество элементов, то добавление каждого элемента будет уведомлять об изменении коллекции каждый раз. Это вызовет избыточную нагрузку на пользовательский интерфейс, и он может даже зависнуть на какое-то время. Чтобы этого избежать, можно написать свой собственный класс, который будет наследовать от ObservableCollection и содержать метод добавления множества элементов за один раз, а уведомлять об этом единожды. Вот как например это можно сделать:

Imports System.Collections.Specialized

''' <summary>
''' ObservableCollection с поддержой добавления множества элементов.
''' </summary>
Public Class ObservableRangeCollection(Of T)
    Inherits ObjectModel.ObservableCollection(Of T)

#Region "CTORs"

    Public Sub New()
        MyBase.New()
    End Sub

    Public Sub New(collection As IEnumerable(Of T))
        MyBase.New(collection)
    End Sub

#End Region '/CTORs

#Region "METHODS"

    ''' <summary>
    ''' Добавляет в коллекцию несколько элементов и в конце уведомляет об этом.
    ''' </summary>
    Public Sub AddRange(collection As IEnumerable(Of T))
        For Each item As T In collection
            Items.Add(item)
        Next
        OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection))
    End Sub

#End Region '/METHODS

End Class

По аналогии с методом AddRange можно добавить методы для удаления, вставки или перемещения набора элементов коллекции.

Подробнее ...
Подписаться на этот канал RSS