Кнопки стиля VBA Windows 7

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

Возможно ли использовать кнопки стиля Windows 7

в Excel VBA или мне нужно использовать эти серые вещи, похожие на них из

?

Я dont хочу использовать изображения, я имею в виду импорт этих "элементов управления ActiveX", я думаю, что это их имя.

2 ответа

Пристегнитесь, вы едете.

Сначала создайте новую библиотеку классов С# (или VB.NET.. любые камни вашей лодки) и добавьте новый UserControl WPF и создайте свой интерфейс:

<usercontrol x:class="ComVisibleUI.UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:ignorable="d" d:datacontext="ViewModel1" d:designheight="200" d:designwidth="300">
 <grid background="White">
 <grid.rowdefinitions>
 <rowdefinition height="*">
 <rowdefinition height="32">
 </rowdefinition></rowdefinition></grid.rowdefinitions>
 <textblock text="actual content here" foreground="DimGray" horizontalalignment="Center" verticalalignment="Center">
 <stackpanel grid.row="1" orientation="Horizontal" horizontalalignment="Right" margin="2">
 <button width="128" command="{Binding Command1}">
 <textblock text="Button1">
 </textblock></button>
 <button width="128" command="{Binding Command2}">
 <textblock text="Button2">
 </textblock></button>
 </stackpanel>
 </textblock></grid>
</usercontrol>

Создайте проект.

Затем добавьте новую форму, добавьте элемент управления WPF Interop ElementHost, и вы сможете добавить свой WPF UserControl1 (независимо от того, что вы его назвали) в качестве размещенного элемента управления WPF.

Элемент управления WPF использует привязки данных для подключения Command1 и Command2 (и все остальное, действительно - прочитано в шаблоне Model-View-ViewModel), поэтому вам понадобится класс для реализации управляемого кода часть. Если ваша логика - все VBA, это должно быть довольно тонким:

public class ViewModel1
{
 public ViewModel1()
 {
 _command1 = new DelegateCommand(ExecuteCommand1);
 _command2 = new DelegateCommand(ExecuteCommand2);
 }
 private readonly ICommand _command1;
 public ICommand Command1 { get { return _command1; } }
 public event EventHandler ExecutingCommand1;
 private void ExecuteCommand1(object parameter)
 {
 ExecuteHandler(ExecutingCommand1);
 }
 private readonly ICommand _command2;
 public ICommand Command2 { get { return _command2; } }
 public event EventHandler ExecutingCommand2;
 private void ExecuteCommand2(object parameter)
 {
 ExecuteHandler(ExecutingCommand2);
 }
 private void ExecuteHandler(EventHandler eventHandler)
 {
 var handler = eventHandler;
 if (handler != null)
 {
 handler.Invoke(this, EventArgs.Empty);
 }
 }
}

A DelegateCommand - очень приятная штука, которая переполнена Stack Overflow, поэтому не стесняйтесь искать, если у вас есть вопросы:

public class DelegateCommand : ICommand
{
 private readonly Action<object> _execute;
 private readonly Func<object, bool=""> _canExecute;
 public DelegateCommand(Action<object> execute, Func<object,bool> canExecute = null)
 {
 _execute = execute;
 _canExecute = canExecute;
 }
 public event EventHandler CanExecuteChanged;
 public bool CanExecute(object parameter)
 {
 return _canExecute == null ? true : _canExecute.Invoke(parameter);
 }
 public void Execute(object parameter)
 {
 _execute.Invoke(parameter);
 }
}

<p>Форма WinForms должна будет назначить элемент управления WPF <code>DataContext</code> - выставить метод для этого:</p>
<pre class="prettyprint linenums"><code>public partial class Form1 : Form
{
 public Form1()
 {
 InitializeComponent();
 }
 public void SetDataContext(ViewModel1 viewModel)
 {
 hostedWPFControl.DataContext = viewModel;
 }
}
</code>

Кроме этого, здесь не должно быть никакого кода.

WPF нравится шаблон MVVM, WinForms любит MVP (lookup Model-View-Presenter). Часть WPF, размещенная в WinForms, мы сделаем презентатором - объект, который будет использовать код VBA:

<code>[ComVisible(true)]
public interface IPresenter1
{
 void Show();
}
</code>

Да, это просто интерфейс. Подождите, нам нужно другое:

<code>[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("18F3B8A8-EC60-4BCE-970A-6C0ABA145705")]
[ComVisible(true)]
public interface IPresenterEvents
{
 void ExecuteCommand1(object message);
 void ExecuteCommand2();
}
</code>

Интерфейс IPresenterEvents - это ваш интерфейс "event sink", который должен реализовать код VBA, но я доберусь до него. Сначала нам нужно внедрить фактического докладчика:

<code>public delegate void Command1Delegate(string message);
public delegate void Command2Delegate();
[ComSourceInterfaces(typeof(IPresenterEvents))]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[Guid("FAF36F86-7CB3-4E0C-A016-D8C84F6B07D7")]
public class Presenter1 : IPresenter1, IDisposable
{
 private readonly Form _view;
 public Presenter1()
 {
 var view = new Form1();
 var viewModel = new ViewModel1();
 viewModel.ExecutingCommand1 += viewModel_ExecutingCommand1;
 viewModel.ExecutingCommand2 += viewModel_ExecutingCommand2;
 view.SetDataContext(viewModel);
 _view = view;
 }
 public event Command1Delegate ExecuteCommand1;
 private void viewModel_ExecutingCommand1(object sender, EventArgs e)
 {
 var handler = ExecuteCommand1;
 if (handler != null)
 {
 handler.Invoke("Hello from Command1!");
 }
 }
 public event Command2Delegate ExecuteCommand2;
 private void viewModel_ExecutingCommand2(object sender, EventArgs e)
 {
 var handler = ExecuteCommand2;
 if (handler != null)
 {
 handler.Invoke();
 }
 }
 public void Show()
 {
 _view.ShowDialog();
 }
 public void Dispose()
 {
 _view.Dispose();
 }
}
</code>

Теперь перейдите к свойствам проекта и установите флажок "Регистрация для COM-взаимодействия", затем создайте проект; на вкладке [Отладка] выберите действие "Запустить внешнюю программу" и найдите исполняемый файл EXCEL.EXE на вашем компьютере: при нажатии F5 Visual Studio запустит Excel с прикрепленным отладчиком, а затем вы можете открыть VBE (Alt + F11), добавьте ссылку на библиотеку .tlb(тип библиотеки), которую вы только что создали (вы найдете ее в директории проекта .net, в разделе \bin\debug\theprojectname.tlb, при условии, что она построена на отладку), и это должно сделать это.

Здесь есть несколько проблем, и я вернусь позже:

  • Метод Dispose() не отображается и не будет явно или неявно вызываться в любой точке, которая является... грязной.
  • В то время как все кажется, что он работает с точки зрения отладчика С#, я не мог заставить обработчики darn VBA работать. Вероятно, это большая проблема, если вы намерены реализовать логику в VBA, а не просто поднять пользовательский интерфейс. OTOH у вас есть доступ к .net-коду, может также реализовать логику презентатора в самом ведущем, в С#/VB.NET, и тогда вам не нужно будет обрабатывать эти обработчики событий.

В любом случае, я добавил этот код в ThisWorkbook:

<code>Option Explicit
Private WithEvents view As ComVisibleUI.Presenter1
Public Sub DoSomething()
 Set view = New ComVisibleUI.Presenter1
 view.Show
End Sub
Private Sub view_ExecuteCommand1(ByVal message As Variant)
 MsgBox message
End Sub
Private Sub view_ExecuteCommand2()
 MsgBox "Hello from WPF!"
End Sub
</code>

И когда я запускаю ThisWorkbook.DoSomething из непосредственного окна (Ctrl + G), я получаю следующее:

В теории (по крайней мере, согласно MSDN), все, что вам нужно сделать. Как я уже сказал, эти обработчики событий не вызываются по какой-то причине, но, эй, вы получаете свои блестящие кнопки!... и всю мощь WPF для разработки вашего пользовательского интерфейса сейчас:)


Я не знаю о решении, где вы можете использовать "кнопки стиля Windows 7". Тем не менее, я хотел бы отметить, что для программирования не требуется использовать вкладку "Разработчик" исключительно. Другими словами: просто потому, что вы хотите, чтобы кнопка не означала, что вы должны использовать именно это со вкладки "Разработчик". Фактически, почти любой форме в Excel может быть назначен макрос.

Самый простой способ получить кнопку, подобную кнопке "Стиль Windows 7", - это Insert a Rectangle или Rounded Rectangle в меню Shapes. "Необычная" серая окраска может быть легко достигнута при нажатии этой формы, а затем на вкладке Format для этой формы выберите один из предопределенных серого шкалы shape style. Эти кнопки выглядят очень похожими на то, что вы хотите, и можете легко assigned a macro щелкнуть правой кнопкой мыши по этим фигурам.

licensed under cc by-sa 3.0 with attribution.