Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
Ну, т.е. отправные точки такие:
1) Есть некоторый опыт работы с этими "интерфейсами" в .Net
Диалог вида OpenFileDialog но для выбора папки, а не файла

2) Есть опыт кастомизации диалогов XP-шного стиля (на VB6 и в .Net), не так чтоб много наплодил, но кой-какой багаж есть
Типа картинка с примером

3) Есть пример для VB6 как кастомизировать диалоги "нового типа" (с поясняющими картинками по ссылке).
Никогда сей пример в VB6 не изучал, просто в курсе что есть такой.
[VB6] Using the new IFileDialog interface for customizable Open/Save (TLB, Vista+)

4) Есть статья Майкрософт, как заниматься кастомизацией оного (C++ пример)
IFileDialog, IFileOpenDialog, and IFileSaveDialog:Customizing the Dialog

Ну, известные мне "исходники" сформулировал.

Собственно надо сваять SaveAs "нового образца", добавив одну галку, два label, два текстбокса, где-нибудь "внизу диалога" вполне сойдет, на большее пока не претендую, задача полагаю выполнимая. (В старом интерфейсе сваял, но чет плоховато на 10-ках он уже смотрится).

М.б. знает кто хорошие не навороченные до огромных размеров примеры, лучше если сразу на VB.Net, ну на худой конец на C#?

Вектор движения такой пока: предполагаю переработать свой OpenFolder в SaveAs (рука как бы не очень на это набита даже без кастомизаций, обычно хватает .Net-контрола), опосля чего думать в направлении интерфейса IFileDialogCustomize.
1 сен 18, 04:20    [21660993]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
hVostt
Member

Откуда:
Сообщений: 15397
Дмитрий77,

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

Но. Кого волнует такой уровень проработки? ахаххах.. ржака.

Создавай форму, размещай контролы и пиши обработчики, а там как-нибудь допинаешь до приемлимого на свой взгляд состояния.
2 сен 18, 01:39    [21661530]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
hVostt
написать действительно хороший новый диалог сохранения ...
Создавай форму, размещай контролы и пиши обработчики...

Мне нужен штатный, но дополненый своими контролами. Причем новый, вида что появились в Висте (ну и на десятке они же).
Дмитрий77
Вектор движения такой пока: предполагаю переработать свой OpenFolder в SaveAs (рука как бы не очень на это набита даже без кастомизаций,.

Без кастомизаций уже осилил:

+
  Private Sub ButtonSaveAs_Click(sender As Object, e As EventArgs) Handles ButtonSaveAs.Click
    Using fsDlg = New IISaveFileDialog
      fsDlg.Filter = "Text Files (*.txt)|*.txt|All files (*.*)|*.*"
      fsDlg.FilterIndex = 1
      fsDlg.FileName = "test.txt"
      fsDlg.DefaultExt = "txt"
      fsDlg.InitialFolder = GetFolderPath(SpecialFolder.DesktopDirectory)
      fsDlg.Title = "Моя тестовая шапка"
      fsDlg.OverwritePrompt = False
      Dim res As DialogResult = fsDlg.ShowDialog(Me)
      If res = DialogResult.OK Then
        MsgBox(fsDlg.File)
      ElseIf res = DialogResult.Cancel Then
        MsgBox("Cancel")
      End If
    End Using
  End Sub


#Region "Constants"

  'Shell Reference > Shell Constants, Enumerations, and Flags
  ' FILEOPENDIALOGOPTIONS enumeration
  Public Const FOS_OVERWRITEPROMPT As UInteger = &H2 'OFN_OVERWRITEPROMPT - When saving a file, prompt before overwriting an existing file of the same name. This is a default value for the Save dialog.
  Public Const FOS_STRICTFILETYPES As UInteger = &H4 'OFN_EXTENSIONDIFFERENT - In the Save dialog, only allow the user to choose a file that has one of the file name extensions specified through IFileDialog::SetFileTypes.
  Public Const FOS_NOCHANGEDIR As UInteger = &H8 ' OFN_NOCHANGEDIR - Don't change the current working directory.
  Public Const FOS_PICKFOLDERS As UInteger = &H20 'Present an Open dialog that offers a choice of folders rather than files.
  Public Const FOS_FORCEFILESYSTEM As UInteger = &H40 'Ensures that returned items are file system items (SFGAO_FILESYSTEM).
  Public Const FOS_ALLNONSTORAGEITEMS As UInteger = &H80 'Enables the user to choose any item in the Shell namespace, not just those with SFGAO_STREAM or SFAGO_FILESYSTEM attributes. This flag cannot be combined with FOS_FORCEFILESYSTEM.
  Public Const FOS_NOVALIDATE As UInteger = &H100 'Do not check for situations that would prevent an application from opening the selected file, such as sharing violations or access denied errors.
  Public Const FOS_ALLOWMULTISELECT As UInteger = &H200 'OFN_ALLOWMULTISELECT - Enables the user to select multiple items in the open dialog. Note that when this flag is set, the IFileOpenDialog interface must be used to retrieve those items.
  Public Const FOS_PATHMUSTEXIST As UInteger = &H800 'OFN_PATHMUSTEXIST - The item returned must be in an existing folder. This is a default value.
  Public Const FOS_FILEMUSTEXIST As UInteger = &H1000 'OFN_FILEMUSTEXIST - The item returned must exist. This is a default value for the Open dialog.
  Public Const FOS_CREATEPROMPT As UInteger = &H2000 'OFN_CREATEPROMPT - Prompt for creation if the item returned in the save dialog does not exist. Note that this does not actually create the item.
  Public Const FOS_SHAREAWARE As UInteger = &H4000 'OFN_SHAREAWARE - In the case of a sharing violation when an application is opening a file, call the application back through OnShareViolation for guidance. This flag is overridden by FOS_NOVALIDATE.
  Public Const FOS_NOREADONLYRETURN As UInteger = &H8000 'OFN_NOREADONLYRETURN - Do not return read-only items. This is a default value for the Save dialog.
  Public Const FOS_NOTESTFILECREATE As UInteger = &H10000 'OFN_NOTESTFILECREATE - Do not test whether creation of the item as specified in the Save dialog will be successful. If this flag is not set, the calling application must handle errors, such as denial of access, discovered when the item is created.
  Public Const FOS_HIDEMRUPLACES As UInteger = &H20000 'OFN_NONETWORKBUTTON - Hide the list of places from which the user has recently opened or saved items. This value is not supported as of Windows 7.
  Public Const FOS_HIDEPINNEDPLACES As UInteger = &H40000 'OFN_NOLONGNAMES - Windows 7 and later. Hide all of the standard namespace locations (such as Favorites, Libraries, Computer, and Network) shown in the navigation pane.
  Public Const FOS_NODEREFERENCELINKS As UInteger = &H100000 'OFN_NODEREFERENCELINKS - Shortcuts should not be treated as their target items. This allows an application to open a .lnk file rather than what that file is a shortcut to.
  Public Const FOS_DONTADDTORECENT As UInteger = &H2000000 'OFN_DONTADDTORECENT - Do not add the item being opened or saved to the recent documents list (SHAddToRecentDocs).
  Public Const FOS_FORCESHOWHIDDEN As UInteger = &H10000000 'OFN_FORCESHOWHIDDEN - Include hidden and system items.
  Public Const FOS_DEFAULTNOMINIMODE As UInteger = &H20000000 'Indicates to the Save As dialog box that it should open in expanded mode. Expanded mode is the mode that is set and unset by clicking the button in the lower-left corner of the Save As dialog box that switches between Browse Folders and Hide Folders when clicked. This value is not supported as of Windows 7.
  Public Const FOS_FORCEPREVIEWPANEON As UInteger = &H40000000 'Indicates to the Open dialog box that the preview pane should always be displayed.
  Public Const FOS_SUPPORTSTREAMABLEITEMS As Integer = &H80000000 'Indicates that the caller is opening a file as a stream (BHID_Stream), so there is no need to download that file.

  ' SIGDN enumeration
  Public Const SIGDN_FILESYSPATH As UInteger = &H80058000UI

#End Region

#Region "Structures"

  'Shell Reference > Shell Structures
  ' COMDLG_FILTERSPEC structure
  <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode, Pack:=4)>
  Public Structure COMDLG_FILTERSPEC
    <MarshalAs(UnmanagedType.LPWStr)>
    Dim pszName As String
    <MarshalAs(UnmanagedType.LPWStr)>
    Dim pszSpec As String
  End Structure

#End Region

#Region "COM"
...
  <ComImport(), ClassInterface(ClassInterfaceType.None), TypeLibType(TypeLibTypeFlags.FCanCreate), Guid("C0B4E2F3-BA21-4773-8DBA-335EC946EB8B")> _
  Friend Class FileSaveDialogRCW
  End Class

  'Shell Interfaces -> IFileDialog
  <ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
  Friend Interface IFileDialog
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    <PreserveSig()> _
    Function Show(<[In](), [Optional]()> ByVal hwndOwner As IntPtr) As UInteger
    'IModalWindow 

    '<MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    'Function SetFileTypes(<[In]()> ByVal cFileTypes As UInteger, <[In](), MarshalAs(UnmanagedType.LPArray)> ByVal rgFilterSpec As IntPtr) As UInteger
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetFileTypes(<[In]()> ByVal cFileTypes As UInteger, <[In](), MarshalAs(UnmanagedType.LPArray)> ByVal rgFilterSpec As COMDLG_FILTERSPEC()) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetFileTypeIndex(<[In]()> ByVal iFileType As UInteger) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function GetFileTypeIndex(ByRef piFileType As UInteger) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function Advise(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal pfde As IntPtr, ByRef pdwCookie As UInteger) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function Unadvise(<[In]()> ByVal dwCookie As UInteger) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetOptions(<[In]()> ByVal fos As UInteger) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function GetOptions(ByRef fos As UInteger) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Sub SetDefaultFolder(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem)

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetFolder(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function GetFolder(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function GetCurrentSelection(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetFileName(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function GetFileName(<MarshalAs(UnmanagedType.LPWStr)> ByRef pszName As String) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetTitle(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszTitle As String) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetOkButtonLabel(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszText As String) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetFileNameLabel(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszLabel As String) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function GetResult(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function AddPlace(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem, ByVal fdap As UInteger) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetDefaultExtension(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszDefaultExtension As String) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function Close(<MarshalAs(UnmanagedType.[Error])> ByVal hr As UInteger) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetClientGuid(<[In]()> ByRef guid As Guid) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function ClearClientData() As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function SetFilter(<MarshalAs(UnmanagedType.[Interface])> ByVal pFilter As IntPtr) As UInteger
  End Interface


  'Shell Interfaces -> IShellItem
  <ComImport(), Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
  Friend Interface IShellItem
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function BindToHandler(<[In]()> ByVal pbc As IntPtr, <[In]()> ByRef rbhid As Guid, <[In]()> ByRef riid As Guid, <Out(), MarshalAs(UnmanagedType.[Interface])> ByRef ppvOut As IntPtr) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function GetParent(<MarshalAs(UnmanagedType.[Interface])> ByRef ppsi As IShellItem) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function GetDisplayName(<[In]()> ByVal sigdnName As UInteger, ByRef ppszName As IntPtr) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function GetAttributes(<[In]()> ByVal sfgaoMask As UInteger, ByRef psfgaoAttribs As UInteger) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function Compare(<[In](), MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem, <[In]()> ByVal hint As UInteger, ByRef piOrder As Integer) As UInteger
  End Interface

#End Region

Public Class IISaveFileDialog
  Implements IDisposable

  Private Const S_OK As UInteger = &H0

  'Shell Reference > Shell Functions
  Private Declare Unicode Function SHCreateItemFromParsingName Lib "shell32.dll" _
   (ByVal pszPath As String, ByVal pbc As IntPtr, ByRef riid As Guid, ByRef ppv As IShellItem) As Integer

  'local variable(s) to hold property value(s)
  Private m_Filter As String
  Private m_FilterIndex As Integer
  Private m_FileName As String
  Private m_DefaultExt As String
  Private m_InitialFolder As String
  Private m_DefaultFolder As String
  Private m_Title As String
  Private m_OverwritePrompt As Boolean = True 'по умолчанию выводить штатный диалог о перезаписи
  Private m_File As String 'сюда пишем выбранный файл с путем

  ''' <summary>
  ''' Gets/sets the file types that the dialog can save.
  ''' </summary>
  Public Property Filter() As String
    Get
      Return m_Filter
    End Get
    Set(ByVal value As String)
      m_Filter = value
    End Set
  End Property

  ''' <summary>
  ''' Gets/sets the file types that the dialog can save.
  ''' </summary>
  Public Property FilterIndex As Integer
    Get
      Return m_FilterIndex
    End Get
    Set(ByVal value As Integer)
      m_FilterIndex = value
    End Set
  End Property

  ''' <summary>
  ''' Gets/sets the file name that appears in the File name edit box when that dialog box is opened.
  ''' </summary>
  Public Property FileName() As String
    Get
      Return m_FileName
    End Get
    Set(ByVal value As String)
      m_FileName = value
    End Set
  End Property

  ''' <summary>
  ''' Gets/sets the default extension to be added to file names.
  ''' </summary>
  Public Property DefaultExt() As String
    Get
      Return m_DefaultExt
    End Get
    Set(ByVal value As String)
      m_DefaultExt = value
    End Set
  End Property

  ''' <summary>
  ''' Gets/sets folder in which dialog will be open.
  ''' </summary>
  Public Property InitialFolder() As String
    Get
      Return m_InitialFolder
    End Get
    Set(ByVal value As String)
      m_InitialFolder = value
    End Set
  End Property

  ''' <summary>
  ''' Gets/sets directory in which dialog will be open if there is no recent directory available.
  ''' </summary>
  Public Property DefaultFolder() As String
    Get
      Return m_DefaultFolder
    End Get
    Set(ByVal value As String)
      m_DefaultFolder = value
    End Set
  End Property

  ''' <summary>
  ''' Gets selected file.
  ''' </summary>
  Public Property File() As String
    Get
      Return m_File
    End Get
    Private Set(ByVal value As String)
      m_File = value
    End Set
  End Property

  ''' <summary>
  ''' Gets/sets the title of the dialog.
  ''' </summary>
  Public Property Title() As String
    Get
      Return m_Title
    End Get
    Set(ByVal value As String)
      m_Title = value
    End Set
  End Property

  ''' <summary>
  ''' Gets/sets the title of the dialog.
  ''' </summary>
  Public Property OverwritePrompt() As Boolean
    Get
      Return m_OverwritePrompt
    End Get
    Set(ByVal value As Boolean)
      m_OverwritePrompt = value
    End Set
  End Property


  Public Function ShowDialog(ByVal owner As IWin32Window) As DialogResult
    If Environment.OSVersion.Version.Major >= 6 Then
      Dim frm = DirectCast(New FileSaveDialogRCW(), IFileDialog)

      Dim options As UInteger
      frm.GetOptions(options)
      options = options Or FOS_NOCHANGEDIR Or FOS_FORCEFILESYSTEM Or FOS_NOVALIDATE Or FOS_NOTESTFILECREATE Or FOS_DONTADDTORECENT
      If Me.OverwritePrompt Then 'подтверждать перезапись существующего файла
        options = options Or FOS_OVERWRITEPROMPT
      Else
        options = options And Not FOS_OVERWRITEPROMPT
      End If
      frm.SetOptions(options)

      ' Set the filter
      If Not String.IsNullOrEmpty(Me.Filter) Then
        Dim filterElements As String() = Me.Filter.Split(New Char() {"|"c})
        Dim num_elements As Integer = filterElements.Length
        'число элементов должно быть кратно двум, вообще формат фильтра на совести вызывающего кода
        If num_elements Mod 2 <> 0 Then num_elements = num_elements - 1
        If num_elements > 0 Then
          Dim mas_filter As COMDLG_FILTERSPEC() = New COMDLG_FILTERSPEC(num_elements / 2 - 1) {}
          For x As Integer = 0 To num_elements - 1 Step 2
            mas_filter(x / 2).pszName = filterElements(x)
            mas_filter(x / 2).pszSpec = filterElements(x + 1)
          Next
          frm.SetFileTypes(CUInt(mas_filter.Length), mas_filter)

          ' Set the filter index (1-based)
          If Me.FilterIndex > 0 AndAlso Me.FilterIndex <= mas_filter.Length Then _
           frm.SetFileTypeIndex(CUInt(Me.FilterIndex))
        End If
      End If

      ' Set the default file name
      If Me.FileName IsNot Nothing Then
        frm.SetFileName(Me.FileName)
      End If

      ' Default extension
      If Not String.IsNullOrEmpty(Me.DefaultExt) Then
        frm.SetDefaultExtension(Me.DefaultExt)
      End If

      If Not String.IsNullOrEmpty(Me.InitialFolder) Then
        Dim directoryShellItem As IShellItem = Nothing
        Dim riid = New Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")
        'IShellItem
        If SHCreateItemFromParsingName(Me.InitialFolder, IntPtr.Zero, riid, directoryShellItem) = S_OK Then
          frm.SetFolder(directoryShellItem)
        End If
      End If

      If Not String.IsNullOrEmpty(Me.DefaultFolder) Then
        Dim directoryShellItem As IShellItem = Nothing
        Dim riid = New Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")
        'IShellItem
        If SHCreateItemFromParsingName(Me.DefaultFolder, IntPtr.Zero, riid, directoryShellItem) = S_OK Then
          frm.SetDefaultFolder(directoryShellItem)
        End If
      End If

      If Me.Title IsNot Nothing Then
        frm.SetTitle(Me.Title)
      End If

      If frm.Show(owner.Handle) = S_OK Then
        Dim shellItem As IShellItem = Nothing
        If frm.GetResult(shellItem) = S_OK Then
          Dim pszString As IntPtr
          If shellItem.GetDisplayName(SIGDN_FILESYSPATH, pszString) = S_OK Then
            If pszString <> IntPtr.Zero Then
              Try
                Me.File = Marshal.PtrToStringAuto(pszString)
                Return DialogResult.OK
              Finally
                Marshal.FreeCoTaskMem(pszString)
              End Try
            End If
          End If
        End If
      End If
      Return DialogResult.Cancel
    Else
      '!!!не надо это использовать на XP/2003 -ясно что работать не будет
      Return DialogResult.Cancel
    End If
  End Function

  Public Sub Dispose() Implements IDisposable.Dispose
    'just to have possibility of Using statement.
  End Sub

End Class

Естественно ничего нового относительно того штатного что уже есть в .Net это не дает.
Но на базе сего можно двигаться дальше:
Дмитрий77
опосля чего думать в направлении интерфейса IFileDialogCustomize.

Ну собсно все ссылки от чего плясать я выложил в первом посту.
Пример MSDN на C++ и кой-чего есть тут
http://www.ookii.org/software/dialogs/
Хотя сей мутный монстропроджект скомпилировать мне так и не удалось, но можно кой-чего подглядывать в коде, например те же GUID-ы, и "декларации" интерфейса IFileDialogCustomize там кстати есть, хотя примеров с кастомизацией несмотря на монстроразмах там походу нет.
А так больше ничего особо и не нагуглил.
2 сен 18, 03:27    [21661548]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
Ну вот вроде дорвался до чего хотел.
IFileDialogCustomize:
+
 'Shell Interfaces -> IFileDialogCustomize
  <ComImport, Guid("e6fdd21a-163f-4975-9c8c-a69f1ba37034"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
  Friend Interface IFileDialogCustomize
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub EnableOpenDropDown(
    <[In]> ByVal dwIDCtl As Integer)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub AddMenu(
    <[In]> ByVal dwIDCtl As Integer,
    <[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszLabel As String)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub AddPushButton(
    <[In]> ByVal dwIDCtl As Integer,
    <[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszLabel As String)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub AddComboBox(
    <[In]> ByVal dwIDCtl As Integer)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub AddRadioButtonList(
    <[In]> ByVal dwIDCtl As Integer)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub AddCheckButton(
    <[In]> ByVal dwIDCtl As Integer,
    <[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszLabel As String,
    <[In]> ByVal bChecked As Boolean)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub AddEditBox(
    <[In]> ByVal dwIDCtl As Integer,
    <[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszText As String)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub AddSeparator(
    <[In]> ByVal dwIDCtl As Integer)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub AddText(
    <[In]> ByVal dwIDCtl As Integer,
    <[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszText As String)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub SetControlLabel(
    <[In]> ByVal dwIDCtl As Integer,
    <[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszLabel As String)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub GetControlState(
    <[In]> ByVal dwIDCtl As Integer,
    <Out> ByRef pdwState As CDCONTROLSTATE)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub SetControlState(
    <[In]> ByVal dwIDCtl As Integer,
    <[In]> ByVal dwState As CDCONTROLSTATE)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub GetEditBoxText(
    <[In]> ByVal dwIDCtl As Integer,
    <Out> ByVal ppszText As IntPtr)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub SetEditBoxText(
    <[In]> ByVal dwIDCtl As Integer,
    <[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszText As String)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub GetCheckButtonState(
    <[In]> ByVal dwIDCtl As Integer,
    <Out> ByRef pbChecked As Boolean)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub SetCheckButtonState(
    <[In]> ByVal dwIDCtl As Integer,
    <[In]> ByVal bChecked As Boolean)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub AddControlItem(
    <[In]> ByVal dwIDCtl As Integer,
    <[In]> ByVal dwIDItem As Integer,
    <[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszLabel As String)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub RemoveControlItem(
    <[In]> ByVal dwIDCtl As Integer,
    <[In]> ByVal dwIDItem As Integer)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub RemoveAllControlItems(
    <[In]> ByVal dwIDCtl As Integer)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub GetControlItemState(
    <[In]> ByVal dwIDCtl As Integer,
    <[In]> ByVal dwIDItem As Integer,
    <Out> ByRef pdwState As CDCONTROLSTATE)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub SetControlItemState(
    <[In]> ByVal dwIDCtl As Integer,
    <[In]> ByVal dwIDItem As Integer,
    <[In]> ByVal dwState As CDCONTROLSTATE)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub GetSelectedControlItem(
    <[In]> ByVal dwIDCtl As Integer,
    <Out> ByRef pdwIDItem As Integer)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub SetSelectedControlItem(
    <[In]> ByVal dwIDCtl As Integer,
    <[In]> ByVal dwIDItem As Integer)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub StartVisualGroup(
    <[In]> ByVal dwIDCtl As Integer,
    <[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszLabel As String)
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub EndVisualGroup()
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>
    Sub MakeProminent(
    <[In]> ByVal dwIDCtl As Integer)
  End Interface


Ну пихаем "свои" контролы туда:
  Public Function ShowDialog(ByVal owner As IWin32Window) As DialogResult
      Dim frm = DirectCast(New FileSaveDialogRCW(), IFileDialog)
...
      Dim cstm As IFileDialogCustomize = CType(frm, IFileDialogCustomize)
      cstm.StartVisualGroup(1300, "")
      'cstm.AddCheckButton(1307, "This is my checkbox that I want to place in the firts string", True)
      cstm.AddCheckButton(1307, "This is my checkbox", True)
      cstm.EndVisualGroup()
      cstm.StartVisualGroup(1308, "")
      cstm.AddText(1301, "Label 1:")
      cstm.AddEditBox(1302, "This is my option 1 value")
      cstm.EndVisualGroup()
      cstm.StartVisualGroup(1303, "")
      cstm.AddText(1304, "Label 2:")
      cstm.AddEditBox(1305, "This is my option 2 value")
      cstm.EndVisualGroup()

      If frm.Show(owner.Handle) = S_OK Then
...

Ну и фигово.

На картинке справа: сделано в "старом" диалоге, там хорошо.
Суть: все выровнено, интервалы соблюдены.
Первая строка - checkbox, вторая -label+textbox, третья - по типу второй, ширина текстбоксов следует ширине комбобоксов, при снятии чекбокса лейблы и текстбоксы становятся Enabled=False.

На картинке слева: "новый" диалог, иначе как бардаком это не назовешь.
Ширина контролов - как он решил, расположение пляшет ако попало.
Ну и че с этим делать? Как им задавать расположение-размеры?
Ну хотя б чтоб чекбокс был в "верхней" строчке, а группы "label+textbox" в нижней.
Ну событие для чекбокса еще как-то надо родить, чтоб "при снятии чекбокса лейблы и текстбоксы становятся Enabled=False"

Т.е. автоматика добаления своих контролов в "новом" то есть, но она бардачная какая-то.

К сообщению приложен файл. Размер - 113Kb
2 сен 18, 06:59    [21661558]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Cat2
Member

Откуда: Petroskoi, Karjala
Сообщений: 145601
Дмитрий77,

Попробуйте все добавляемые Вами контролы красиво разместить на UserControl, а на диалог добавляйте уже его.
Хотя и вручную можно выравнять, создавая и добавляя контролы по одиночке - нужных размеров и в нужную позицию.
2 сен 18, 17:00    [21661822]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3351
не проще сделать диалог, в котором будут 2 эти поле и поле с именем файла, котором будет выбираться стандартным диалоговым окном? какой сакральный смысл пихать контролы в стандартный диалог?
2 сен 18, 17:08    [21661829]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
Cat2
Попробуйте все добавляемые Вами контролы красиво разместить на UserControl, а на диалог добавляйте уже его.
Хотя и вручную можно выравнять, создавая и добавляя контролы по одиночке - нужных размеров и в нужную позицию.

Ну вот я так примерно и делал в диалоге старого типа (доп. контролы на отдельной форме, где задано начальное позиционирование, потом диалог назначается как Parent, через сабклассинг допиливается позиционирование при изменении размеров диалога и т.п.).
Примеры: правая картинка выше или картинка по этой ссылке: см. картинку. Добавляешь чего хочешь. Но гимор скажу еще тот, один такой аккуратно сваять.

В "новом" диалоге это не пройдет (ну или какой-то совсем гимор, чем заниматься счас точно неохота). Но там как бы есть штатные методы добавления ограниченного набора контролов, типа label, checkbox, textbox и т.д. о чем и речь.
Ну в принципе, приемлимых результатов добиться таки можно (считаю пока устроит).
Например в моем случае так:
      Dim cstm As IFileDialogCustomize = CType(frm, IFileDialogCustomize)
      cstm.AddCheckButton(1301, "Include cover page into the file to be saved", True)
      cstm.MakeProminent(1301)
      cstm.StartVisualGroup(1302, "")
      cstm.AddText(1303, "Field #1:")
      cstm.AddEditBox(1304, "")
      cstm.EndVisualGroup()
      cstm.StartVisualGroup(1305, "")
      cstm.AddText(1306, "Field #2:")
      cstm.AddEditBox(1307, "")
      cstm.EndVisualGroup()

MakeProminent располагает чекбокс рядом с Save. Две пары label+textbox аккуратно расположены в ряд выше.
Результат на картинки ниже, вполне.

Теперь надо бы добавить события в мой класс. Пока не знаю как это имплементировать. Надо копать примеры, они сильно навороченные.
Событий 2 типа.
1) штатный набор, описываемый интерфейсом IFileDialogEvents interface
+
  <ComImport, Guid("973510DB-7D7F-452B-8975-74A85828D354"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
  Friend Interface IFileDialogEvents
    ' NOTE: some of these callbacks are cancelable - returning S_FALSE means that 
    ' the dialog should not proceed (e.g. with closing, changing folder); to 
    ' support this, we need to use the PreserveSig attribute to enable us to return
    ' the proper HRESULT
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    <PreserveSig()> _
    Function OnFileOk(<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfd As IFileDialog) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    <PreserveSig()> _
    Function OnFolderChanging(<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfd As IFileDialog, <[In], MarshalAs(UnmanagedType.[Interface])> ByVal psiFolder As IShellItem) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function OnFolderChange(<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfd As IFileDialog) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function OnSelectionChange(<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfd As IFileDialog) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function OnShareViolation(<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfd As IFileDialog,
    <[In], MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem, <Out> ByRef pResponse As FDE_SHAREVIOLATION_RESPONSE) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function OnTypeChange(
    <[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfd As IFileDialog) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function OnOverwrite(
    <[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfd As IFileDialog,
    <[In], MarshalAs(UnmanagedType.[Interface])> ByVal psi As IShellItem, <Out> ByRef pResponse As FDE_OVERWRITE_RESPONSE) As UInteger
  End Interface
2) дополнительный набор описываемый как я понял интерфейсом IFileDialogControlEvents
События контролов, добавляемых через IFileDialogCustomize
Применительно к моему примеру, это даст мне возможность реагировать на снятие/установку галки в чекбокс - OnCheckButtonToggled.
В общем, с событиями осталось разобраться, и будет если не шоколадка, то карамелька.

К сообщению приложен файл. Размер - 78Kb
2 сен 18, 18:46    [21661866]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
Я вот чего-то не врублюсь.
Есть интерфейс IFileDialogControlEvents (в модуле m_IFileDialog)

  <ComImport, Guid("36116642-D713-4b97-9B83-7484A9D00433"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
  Friend Interface IFileDialogControlEvents
    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function OnItemSelected(<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfdc As IFileDialogCustomize, <[In]> ByVal dwIDCtl As Integer, <[In]> ByVal dwIDItem As Integer) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function OnButtonClicked(<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfdc As IFileDialogCustomize, <[In]> ByVal dwIDCtl As Integer) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function OnCheckButtonToggled(<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfdc As IFileDialogCustomize, <[In]> ByVal dwIDCtl As Integer, <[In]> ByVal bChecked As Boolean) As UInteger

    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)> _
    Function OnControlActivating(<[In], MarshalAs(UnmanagedType.[Interface])> ByVal pfdc As IFileDialogCustomize, <[In]> ByVal dwIDCtl As Integer) As UInteger
  End Interface


Делаю класс типа так:
Friend Class IIFileDialogEvents
  'Implements IFileDialogEvents
  Implements IFileDialogControlEvents

  Const S_OK As UInteger = 0
…

  Public Function OnItemSelected(ByVal pfdc As IFileDialogCustomize, ByVal dwIDCtl As Integer, ByVal dwIDItem As Integer) As UInteger
    Return S_OK
  End Function

  Public Function OnButtonClicked(ByVal pfdc As IFileDialogCustomize, ByVal dwIDCtl As Integer) As UInteger
    Return S_OK
  End Function

  Public Function OnCheckButtonToggled(ByVal pfdc As IFileDialogCustomize, ByVal dwIDCtl As Integer, ByVal bChecked As Boolean) As UInteger
    Return S_OK
  End Function

  Public Function OnControlActivating(ByVal pfdc As IFileDialogCustomize, ByVal dwIDCtl As Integer) As UInteger
    Return S_OK
  End Function
End Class

Он мне пишет 4 ошибки про каждую ф-цию, типа
Ошибка	4	Class "IIFileDialogEvents" должен реализовывать 
"Function OnItemSelected(pfdc As IFileDialogCustomize, dwIDCtl As Integer, dwIDItem As Integer) As UInteger"
для интерфейса "m_IFileDialog.IFileDialogControlEvents".

Дык вроде прописал их все по формату, че ему не нравится?
И примеров на VB.Net ни хрена нету, разбираю муть на C#, в мути в оригинале так

+
   [ComImport,
    Guid(IIDGuid.IFileDialogControlEvents),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IFileDialogControlEvents
    {

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void OnItemSelected([In, MarshalAs(UnmanagedType.Interface)] IFileDialogCustomize pfdc, [In] int dwIDCtl, [In] int dwIDItem);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void OnButtonClicked([In, MarshalAs(UnmanagedType.Interface)] IFileDialogCustomize pfdc, [In] int dwIDCtl);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void OnCheckButtonToggled([In, MarshalAs(UnmanagedType.Interface)] IFileDialogCustomize pfdc, [In] int dwIDCtl, [In] bool bChecked);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void OnControlActivating([In, MarshalAs(UnmanagedType.Interface)] IFileDialogCustomize pfdc, [In] int dwIDCtl);
    }
 

   class VistaFileDialogEvents : Ookii.Dialogs.Wpf.Interop.IFileDialogEvents, Ookii.Dialogs.Wpf.Interop.IFileDialogControlEvents
    {
        const uint S_OK = 0;
        const uint S_FALSE = 1;
        const uint E_NOTIMPL = 0x80004001;

        private VistaFileDialog _dialog;

        public VistaFileDialogEvents(VistaFileDialog dialog)
        {
            if( dialog == null )
                throw new ArgumentNullException("dialog");

            _dialog = dialog;
        }

        #region IFileDialogEvents Members

        public Ookii.Dialogs.Wpf.Interop.HRESULT OnFileOk(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd)
        {
            if( _dialog.DoFileOk(pfd) )
                return Ookii.Dialogs.Wpf.Interop.HRESULT.S_OK;
            else
                return Ookii.Dialogs.Wpf.Interop.HRESULT.S_FALSE;
        }

        public Ookii.Dialogs.Wpf.Interop.HRESULT OnFolderChanging(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd, Ookii.Dialogs.Wpf.Interop.IShellItem psiFolder)
        {
            return Ookii.Dialogs.Wpf.Interop.HRESULT.S_OK;
        }

        public void OnFolderChange(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd)
        {
        }

        public void OnSelectionChange(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd)
        {
        }

        public void OnShareViolation(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd, Ookii.Dialogs.Wpf.Interop.IShellItem psi, out NativeMethods.FDE_SHAREVIOLATION_RESPONSE pResponse)
        {
            pResponse = NativeMethods.FDE_SHAREVIOLATION_RESPONSE.FDESVR_DEFAULT;
        }

        public void OnTypeChange(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd)
        {
        }

        public void OnOverwrite(Ookii.Dialogs.Wpf.Interop.IFileDialog pfd, Ookii.Dialogs.Wpf.Interop.IShellItem psi, out NativeMethods.FDE_OVERWRITE_RESPONSE pResponse)
        {
            pResponse = NativeMethods.FDE_OVERWRITE_RESPONSE.FDEOR_DEFAULT;
        }

        #endregion

        #region IFileDialogControlEvents Members

        public void OnItemSelected(Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize pfdc, int dwIDCtl, int dwIDItem)
        {
        }

        public void OnButtonClicked(Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize pfdc, int dwIDCtl)
        {
        }

        public void OnCheckButtonToggled(Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize pfdc, int dwIDCtl, bool bChecked)
        {
        }

        public void OnControlActivating(Ookii.Dialogs.Wpf.Interop.IFileDialogCustomize pfdc, int dwIDCtl)
        {
        }

        #endregion


    }

Нады мне как-то на события диалога и его доп. контролов подписку оформить, сижу туплю как это сделать.
2 сен 18, 23:26    [21662079]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
Дмитрий77
Он мне пишет 4 ошибки про каждую ф-цию, типа
Ошибка	4	Class "IIFileDialogEvents" должен реализовывать 
"Function OnItemSelected(pfdc As IFileDialogCustomize, dwIDCtl As Integer, dwIDItem As Integer) As UInteger"
для интерфейса "m_IFileDialog.IFileDialogControlEvents".

Все, понял. Гребаный синтаксис. В vb.net надо
Implements IFileDialogControlEvents.<Function name> еще ляпать в определение каждой ф-ции
т.е
  Public Function OnItemSelected(ByVal pfdc As IFileDialogCustomize, ByVal dwIDCtl As Integer, _
   ByVal dwIDItem As Integer) As UInteger _
   Implements IFileDialogControlEvents.OnItemSelected
    Return S_OK
  End Function
вместо
  Public Function OnItemSelected(ByVal pfdc As IFileDialogCustomize, ByVal dwIDCtl As Integer, _
   ByVal dwIDItem As Integer) As UInteger
    Return S_OK
  End Function

Знать бы еще как это все сожрать потом.
2 сен 18, 23:39    [21662087]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
Нады мне как-то на события диалога и его доп. контролов подписку оформить...как это все сожрать потом

В общем доосилил таки эту кухню.
Идея такая.
Создается вспомогательный класс (IIFileDialogEvents), имплементирующий оба типа событий, т.е. интерфейсы IFileDialogEvents и IFileDialogControlEvents. Там должны присутствовать все функции, входящие в эти интерфейсы, хотя бы в качестве ничего не делающей "рыбы". Плюс передаем туда ссылку на основной класс(IISaveFileDialog), представляющий диалог.
Friend Class IIFileDialogEvents
  Implements IFileDialogEvents
  Implements IFileDialogControlEvents

  Const S_OK As UInteger = 0
  'Const S_FALSE As UInteger = 1
  'Const E_NOTIMPL As Integer = &H80004001
  Private _dialog As IISaveFileDialog

  Public Sub New(ByVal dialog As IISaveFileDialog)
    _dialog = dialog
  End Sub

  Public Function OnFileOk(ByVal pfd As IFileDialog) As UInteger _
   Implements IFileDialogEvents.OnFileOk
    _dialog.DoOnFileOk()
    Return S_OK
  End FunctionPublic Sub OnCheckButtonToggled(ByVal pfdc As IFileDialogCustomize, ByVal dwIDCtl As Integer, ByVal bChecked As Boolean) _
   Implements IFileDialogControlEvents.OnCheckButtonToggled
    _dialog.DoOnCheckButtonToggled(dwIDCtl, bChecked)
  End Sub
...


Из основного класса подписываем диалог пулять события во вспомогательный
  Public Sub New()
    frm = DirectCast(New FileSaveDialogRCW(), IFileDialog)
...
  End Sub

  Public Function ShowDialog(ByVal owner As IWin32Window) As DialogResult
...
      Dim cookie As UInteger
      frm.Advise(New IIFileDialogEvents(Me), cookie) ' подписываемся

      If frm.Show(owner.Handle) = S_OK Then

…

      frm.Unadvise(cookie) 'не забыть отписаться


А во вспомогательном вызываем публичную ф-цию основного, которая генерирует событие
Friend Class IIFileDialogEvents
  Implements IFileDialogEvents
  Implements IFileDialogControlEvents
…

  Public Sub OnCheckButtonToggled(ByVal pfdc As IFileDialogCustomize, ByVal dwIDCtl As Integer, ByVal bChecked As Boolean) _
   Implements IFileDialogControlEvents.OnCheckButtonToggled
    _dialog.DoOnCheckButtonToggled(dwIDCtl, bChecked)
  End Sub


Т.е. генерируем событие для диалога:
Public Class IISaveFileDialog
  Implements IDisposable
...
  Public Event OnCheckButtonToggled(ByVal dwIDCtl As Integer, ByVal bChecked As Boolean)
  Public Sub DoOnCheckButtonToggled(ByVal dwIDCtl As Integer, ByVal bChecked As Boolean)
    RaiseEvent OnCheckButtonToggled(dwIDCtl, bChecked)
  End Sub


Ну и имеем приемлимый код:

  Dim WithEvents fsDlg As IISaveFileDialog

  Private Sub ButtonSaveAs_Click(sender As Object, e As EventArgs) Handles ButtonSaveAs.Click
    fsDlg = New IISaveFileDialog
    With fsDlg
      .Filter = "Text Files (*.txt)|*.txt|All files (*.*)|*.*"
      .FilterIndex = 1
      .FileName = "test.txt"
      .DefaultExt = "txt"
      .InitialFolder = GetFolderPath(SpecialFolder.DesktopDirectory)
      .Title = "Моя тестовая шапка"
      .OverwritePrompt = False

      'custom controls
      .AddCheckButton(1301, "Include cover page into the file to be saved", True)
      .MakeProminent(1301)
      .StartVisualGroup(1302, "")
      .AddText(1303, "Field #1:")
      .AddEditBox(1304, "1234567890")
      .EndVisualGroup()
      .StartVisualGroup(1305, "")
      .AddText(1306, "Field #2:")
      .AddEditBox(1307, "Вася Пупкин")
      .EndVisualGroup()

      Dim res As DialogResult = fsDlg.ShowDialog(Me)
      If res = DialogResult.OK Then
        MsgBox(fsDlg.File)
        Dim add_cover As Boolean = CType(fsDlg.Tag(0), Boolean)
        Dim field_1 As String = CType(fsDlg.Tag(1), String)
        Dim field_2 As String = CType(fsDlg.Tag(2), String)
        MsgBox("add_cover=" & add_cover & ";Field #1=" & field_1 & ";Field #2=" & field_2)
      ElseIf res = DialogResult.Cancel Then
        MsgBox("Cancel")
      End If
      fsDlg.Dispose()
    End With
  End Sub

  Private Sub fsDlg_OnCheckButtonToggled(dwIDCtl As Integer, bChecked As Boolean) Handles fsDlg.OnCheckButtonToggled
    If dwIDCtl = 1301 Then
      fsDlg.SetControlState(1303, IIf(bChecked, CDCONTROLSTATE.CDCS_VISIBLE Or CDCONTROLSTATE.CDCS_ENABLED, CDCONTROLSTATE.CDCS_VISIBLE))
      fsDlg.SetControlState(1304, IIf(bChecked, CDCONTROLSTATE.CDCS_VISIBLE Or CDCONTROLSTATE.CDCS_ENABLED, CDCONTROLSTATE.CDCS_VISIBLE))
      fsDlg.SetControlState(1306, IIf(bChecked, CDCONTROLSTATE.CDCS_VISIBLE Or CDCONTROLSTATE.CDCS_ENABLED, CDCONTROLSTATE.CDCS_VISIBLE))
      fsDlg.SetControlState(1307, IIf(bChecked, CDCONTROLSTATE.CDCS_VISIBLE Or CDCONTROLSTATE.CDCS_ENABLED, CDCONTROLSTATE.CDCS_VISIBLE))
    End If
  End Sub

  Private Sub fsDlg_OnFileOk() Handles fsDlg.OnFileOk
    'лучше здесь сохранять значения кастом-контролов
    fsDlg.Tag(0) = fsDlg.GetCheckButtonState(1301) 'add cover
    fsDlg.Tag(1) = fsDlg.GetEditBoxText(1304) 'Field #1
    fsDlg.Tag(2) = fsDlg.GetEditBoxText(1307) 'Field #2
  End Sub


Класс оформил универсально, с возможностью дописывания общих ф-ций если надо будет, но рыбы на все события и кастом-элементы вставил.
Глюк правда один заметил (применительно к моему диалогу): если фокус на кастом-текстбоксе, снимаем галку мышкой с чекбокса,
текстбокс становится Enabled=false, но рамка блин черная, а не серая получается, ну во всяком случае на Win10. Побороть не сумел.
Ну, на всякий случай прилагаю проект, м.б. кому пригодится, вещь вроде неплохая получилась.

К сообщению приложен файл (VistaSaveFileDialog_Test.zip - 49Kb) cкачать
3 сен 18, 06:54    [21662175]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
hVostt
Member

Откуда:
Сообщений: 15397
Дмитрий77
Friend Class IIFileDialogEvents


Небольшие замечания, можешь проигнорить, но пройти мимо не мог.

1. В .NET приняты соглашения, которых нужно придерживаться.

Здесь лучше бы подошли такие названия:

CustomFileDialogEvents
DmitryFileDialogEvents
...

2. Неправильно вызывать fsDlg.Dispose() тогда, когда можно использовать блок Using

3. Раз уж ты создал новый расширяющий класс, не нужно использовать поле Tag для доступа к кастомным полям. Добавь для них отдельные поля в классе. Или хотя бы словарь.

Ибо такое

Дмитрий77
Dim field_1 As String = CType(fsDlg.Tag(1), String)


Форменное издевательство над тем, кто будет сопровождать код в дальнейшем (включая себя, безусловно).
3 сен 18, 07:37    [21662188]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
hVostt
Здесь лучше бы подошли такие названия:

CustomFileDialogEvents
DmitryFileDialogEvents

Ну тогда уж MyFileDialogEvents. Но это ИМХО ерунда все.

hVostt
2. Неправильно вызывать fsDlg.Dispose() тогда, когда можно использовать блок Using

У меня и было изначально Using. Но я за пределами основных операций с диалогом объявил
  Dim WithEvents fsDlg As IISaveFileDialog

поэтому Using не катит.
А .Dispose() как раз в классе пустой, именно для Using
  Public Sub Dispose() Implements IDisposable.Dispose
    'just to have possibility of Using statement.
  End Sub


hVostt
3. Раз уж ты создал новый расширяющий класс, не нужно использовать поле Tag для доступа к кастомным полям. Добавь для них отдельные поля в классе. Или хотя бы словарь.

Ибо такое

Дмитрий77
Dim field_1 As String = CType(fsDlg.Tag(1), String)


Форменное издевательство над тем, кто будет сопровождать код в дальнейшем (включая себя, безусловно).


Отдельные поля -частный случай конкретного применения.
Tag(i) - типа храним чего угодно и сколько угодно.
Мне надо взять значения из двух TextBox на момент закрытия диалога.
Эти значения доступны на момент нажатия кнопки OK, мы достаем их из события нажатия Save и пихаем обратно в класс,
  Private Sub fsDlg_OnFileOk() Handles fsDlg.OnFileOk
    'лучше здесь сохранять значения кастом-контролов
    fsDlg.Tag(0) = fsDlg.GetCheckButtonState(1301) 'add cover
    fsDlg.Tag(1) = fsDlg.GetEditBoxText(1304) 'field_1
    fsDlg.Tag(2) = fsDlg.GetEditBoxText(1307) 'field_2
ecipient name
  End Sub


потом достаем из обратно Tag когда уже диалог закрыт.
Мог обойтись просто переменными в вызывающем коде (в форме), но захотелось вот так, но это "универсально", в другой раз будет три текстбокса и еще чего нибудь и т.д.

А насчет "сопровождающих код", мои коды кроме меня никто не сопровождает, а тебе напр. переделать несложно, если считаешь синтаксис вопиющим.
В принципе, я обычно пишу простые коды (ну мне так кажется).
Аналогичная кухня
http://www.ookii.org/software/dialogs/
там все "по науке" (C#), но столько всего что умучаешься что-то выдрать,
не говоря о том что проект тот воообще не скомпилировался (какие-то заумные ошибки про какие-то "сборки", уши вянут), понаворочают ссылок на всякие "либы", и своих классов нагородят по 50 модулей на проект, и тащатся от этого. Я не считаю что там лучше и понятней.
Я диалог сделал, мою задачу выполняет. Причем класс сгодится и для выполнения других задач, например добавить стрелку с меню к кнопке Save, или там радио-группу, combobox и т.п. Но он конечно реализует своего рода "штатную" кастомизацию, т.е. свою картинку с тулбаром и treeview, как я это делал в старых диалогах, оно не пририсует.
Ну, и ограниченная свобода в расположении/размерах контролов кот. добавляешь.
Но для большинства чуть нестандартных задач вполне неплохое дополнение.
3 сен 18, 09:29    [21662256]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
hVostt
Member

Откуда:
Сообщений: 15397
Дмитрий77
Ну тогда уж MyFileDialogEvents. Но это ИМХО ерунда все.


Нет, вовсе не ерунда. Но спорить не будем, указал больше для тех, кто желает развиваться в направлении профессиональной хорошо оплачиваемой разработки. Кому это не нужно, проходят мимо :)


Дмитрий77
У меня и было изначально Using. Но я за пределами основных операций с диалогом объявил


Ок.


Дмитрий77
Отдельные поля -частный случай конкретного применения.
Tag(i) - типа храним чего угодно и сколько угодно.


Это понятно. Но так делать не стоит.

Дмитрий77
Мог обойтись просто переменными в вызывающем коде (в форме), но захотелось вот так, но это "универсально", в другой раз будет три текстбокса и еще чего нибудь и т.д.


В том и дело, когда "потом будет", концы искать придётся, тратить на это время, и держать в голове. Ну понятное дело совершать ошибки, которые потом героически исправлять.


Дмитрий77
А насчет "сопровождающих код", мои коды кроме меня никто не сопровождает, а тебе напр. переделать несложно, если считаешь синтаксис вопиющим.
В принципе, я обычно пишу простые коды (ну мне так кажется).


Это вопрос культуры кодинга. Может быть тебе придётся когда-нибудь работать в команде, предложат хорошие условия и оплату, а у тебя уже комплект вредных привычек, с которыми бороться очень тяжело.

Ну или не тебе, а тому кто читает этот тред :)

В общем, это просто ремарка.
3 сен 18, 10:39    [21662365]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
hVostt
Дмитрий77
Friend Class IIFileDialogEvents


Небольшие замечания, можешь проигнорить, но пройти мимо не мог.

1. В .NET приняты соглашения, которых нужно придерживаться.

Здесь лучше бы подошли такие названия:

CustomFileDialogEvents
DmitryFileDialogEvents


Ну бог с ним, убедил.
Вместо
IISaveFileDialog
IIFileDialogEvents

сделал
IVistaSaveFileDialog
IVistaFileDialogEvents

"Vista" -понятно, эти диалоги там появились, приставка "I" - сделан на базе интерфейсной кухне, понимаю что это класс а не интерфейс, но даб не путать с теми же .Net-контролами - мне так удобней и понятней.
Убрал бы "Vista", но ISaveFileDialog IFileDialogEvents -ориг. названия интерфейсов.
Т.е. к примеру класс для выбора папок (в этом же проекте) у меня называется ISelectFolderDialog и вообще но проблем.

Приложил проект с новыми "именами", для "сопровождающих код".

К сообщению приложен файл (VistaSaveFileDialog_Test.zip - 49Kb) cкачать
3 сен 18, 18:44    [21663039]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
Дмитрий77
Но он конечно реализует своего рода "штатную" кастомизацию, т.е. свою картинку с тулбаром и treeview, как я это делал в старых диалогах, оно не пририсует.
Ну, и ограниченная свобода в расположении/размерах контролов кот. добавляешь.

Вообще я тут пример из Microsoft SDK глянул,
они там умудряются какие-то PropertyItems воткнуть, вместе с календарем и т.п. (но все одно пляшут).
Разбирать не стал, уже итак 3 дня потратил. Пора с этим заканчивать, вставить свою наработку в свой App и на этом все пока.

Это так, для поддержания темы.
Пример на всякий случай прилагаю (выдернут из SDK, качать ее целиком чтоб взглянуть вряд ли кто будет).
С++ компилируется в VC++ 2005, но думаю легко импортируется в VS2013 и им подобные.

К сообщению приложен файл (CommonFileDialog.zip - 35Kb) cкачать
3 сен 18, 19:01    [21663048]     Ответить | Цитировать Сообщить модератору
 Re: Кастомизация (добавление своих элементов) в "новых" диалогах SaveAs/Open  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4343
Дмитрий77
Cat2
Попробуйте все добавляемые Вами контролы красиво разместить на UserControl, а на диалог добавляйте уже его.
Хотя и вручную можно выравнять, создавая и добавляя контролы по одиночке - нужных размеров и в нужную позицию.

Ну вот я так примерно и делал в диалоге старого типа (доп. контролы на отдельной форме, где задано начальное позиционирование, потом диалог назначается как Parent, через сабклассинг допиливается позиционирование при изменении размеров диалога и т.п.).
...Добавляешь чего хочешь. Но гимор скажу еще тот, один такой аккуратно сваять.

В "новом" диалоге это не пройдет

А вообще м.б. и можно.
Вот интересные рассуждения
IFileDialog and Subclassing control on it
В упомянутом мной коде от MS есть кусочек - суть добыть hwnd диалога.
https://msdn.microsoft.com/en-us/library/windows/desktop/bb776913(v=vs.85).aspx#OnFileOk
The calling process can use the window handle of the dialog itself as the parent of the UI. That handle can be obtained by first calling IOleWindow::QueryInterface and then calling IOleWindow::GetWindow with the handle as shown in this example.

Отчего бы нет:
  Private m_InitDone As Boolean = False
...
    frm = DirectCast(New FileSaveDialogRCW(), IFileDialog)
... 
...
  Public Event OnFolderChanging()
  Public Event OnInitDone(ByVal hwnd As IntPtr)
  Public Sub DoOnFolderChanging()
    If m_InitDone = False Then
      m_InitDone = True
      Dim hwnd As IntPtr
      Dim ole As IOleWindow = CType(frm, IOleWindow)
      ole.GetWindow(hwnd)
      RaiseEvent OnInitDone(hwnd)
    End If
    RaiseEvent OnFolderChanging()
  End Sub


+
  ''' <summary>
  ''' Implemented and used by containers and objects to obtain window handles
  ''' and manage context-sensitive help.
  ''' </summary>
  ''' <remarks>
  ''' The IOleWindow interface provides methods that allow an application to obtain
  ''' the handle to the various windows that participate in in-place activation,
  ''' and also to enter and exit context-sensitive help mode.
  ''' </remarks>
  <ComImport(), Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
  Public Interface IOleWindow
    ''' <summary>
    ''' Returns the window handle to one of the windows participating in in-place activation
    ''' (frame, document, parent, or in-place object window).
    ''' </summary>
    ''' <param name="phwnd">Pointer to where to return the window handle.</param>
    Sub GetWindow(<System.Runtime.InteropServices.Out()> ByRef phwnd As IntPtr)

    ''' <summary>
    ''' Determines whether context-sensitive help mode should be entered during an
    ''' in-place activation session.
    ''' </summary>
    ''' <param name="fEnterMode"><c>true</c> if help mode should be entered;
    ''' <c>false</c> if it should be exited.</param>
    Sub ContextSensitiveHelp(<[In](), MarshalAs(UnmanagedType.Bool)> ByVal fEnterMode As Boolean)
  End Interface

Handle получил, но нормально воткнуть туда чего-то или расчистить место под "воткнуть" с ходу не удалось.
Если фишку удастся просечь, то можно пичкать его чем угодно по той технике, что использовал для старых диалогов.

"OnFolderChanging" это первое событие которое всегда срабатывает (первый раз вроде как до появления на экран),
т.е. OnInitDone разумно брать из первого OnFolderChanging, больше нет ничего чтоб подцепиться , там же делать инициализацию-рисовку всего,
потом чего нибудь сабклассить, видимо handle диалога и там делать поправки (позиция, размеры).

Не уверен, что хочу счас этим заниматься. Ну есть у меня парочка "крутых" диалогов, которые в старом стиле и соотв. некоторый соблазн "обновить" их.
4 сен 18, 06:58    [21663364]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить