Đầu tiên, tạo một C# mới (hoặc VB.NET .. bất cứ điều gì đá thuyền của bạn) thư viện lớp, và thêm một WPF UserControl mới, và thiết kế giao diện người dùng của bạn:
Xây dựng dự án.
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);
}
}
}
Một DelegateCommand
là một điều rất tốt đẹp chút đó là khắp nơi trên Stack Overflow, vì vậy đừng ngần ngại tìm kiếm nếu bạn có bất cứ thắc mắc:
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);
}
}
dạng WinForms sẽ cần phải gán sự kiểm soát WPF của DataContext
- phơi bày một phương pháp để làm điều đó:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void SetDataContext(ViewModel1 viewModel)
{
hostedWPFControl.DataContext = viewModel;
}
}
Ngoài ra, không được có bất kỳ mã nào ở đây.
WPF thích mô hình MVVM, WinForms thích MVP (tra cứu Model-View-Presenter). Phần WPF đang được lưu trữ trong WinForms, chúng tôi sẽ làm cho một người dẫn chương trình - đó là đối tượng mã VBA sẽ sử dụng:
[ComVisible(true)]
public interface IPresenter1
{
void Show();
}
Vâng, đó chỉ là một giao diện . Giữ trên, chúng ta cần một:
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("18F3B8A8-EC60-4BCE-970A-6C0ABA145705")]
[ComVisible(true)]
public interface IPresenterEvents
{
void ExecuteCommand1(object message);
void ExecuteCommand2();
}
Giao diện IPresenterEvents
là của bạn "chìm sự kiện" giao diện, rằng mã VBA sẽ cần phải thực hiện, nhưng tôi sẽ nhận được nó. Trước tiên, chúng tôi cần phải trình bày người trình bày thực tế:
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();
}
}
Bây giờ, hãy vào thuộc tính của dự án và chọn hộp kiểm "Đăng ký COM interop", sau đó xây dựng dự án; trong tab [Debug], chọn bắt đầu hành động "Bắt đầu chương trình bên ngoài" và xác định tệp EXCEL.EXE trên máy của bạn: khi bạn nhấn F5, Visual Studio sẽ khởi chạy Excel với trình gỡ lỗi được đính kèm và sau đó bạn có thể mở VBE (Alt + F11), thêm một tham chiếu đến .tlb (loại thư viện) mà bạn vừa xây dựng (bạn sẽ tìm thấy nó trong thư mục dự án .net của bạn, dưới \bin\debug\theprojectname.tlb
, giả sử một bản dựng gỡ lỗi), và nên làm điều đó .
Có một số vấn đề ở đây, rằng tôi sẽ trở lại để sửa chữa sau:
- Phương pháp
Dispose()
không được tiếp xúc, và sẽ không được rõ ràng hoặc ngầm gọi bất cứ lúc nào, mà là ... bẩn.
- Trong khi mọi thứ có vẻ như nó đang làm việc từ quan điểm của trình gỡ lỗi C#, tôi không thể có được trình xử lý VBA darn để chạy. Đó có lẽ là một vấn đề lớn nếu bạn có ý định thực hiện logic trong VBA, không chỉ đưa lên giao diện người dùng. OTOH bạn có quyền truy cập vào mã .net, cũng có thể triển khai logic trình bày trong chính trình bày, trong C#/VB.NET, và sau đó bạn không cần phải xử lý sự kiện này để làm việc.
Dù sao, tôi đã thêm mã này vào ThisWorkbook
:
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
Và khi tôi chạy ThisWorkbook.DoSomething
từ cửa sổ ngay lập tức (Ctrl + G), tôi có được điều này:
Theo lý thuyết (ít nhất theo MSDN), đó là tất cả những gì bạn cần làm. Như tôi đã nói các trình xử lý sự kiện này không được gọi vì một lý do nào đó, nhưng hey, bạn có các nút sáng bóng của mình! ... và tất cả sức mạnh của WPF để thiết kế giao diện người dùng của bạn ngay bây giờ :)
tôi rất muốn biết điều đó. – DeerSpotter
* Tôi có phải sử dụng những thứ màu xám trông giống như chúng đến từ Windows 2000 * - tôi nghĩ chúng thực sự từ Win95. Nếu bạn muốn * sáng bóng và mới *, bạn có thể làm cho giao diện người dùng của bạn với WPF/XAML trong một thư viện lớp .net có thể nhìn thấy COM (.dll) và sử dụng * đó * từ mã VBA của bạn. Tùy thuộc vào kiểu mã hóa của bạn, * có thể * có nghĩa là những thay đổi kiến trúc nghiêm trọng (ví dụ nếu bạn quen với việc thực hiện tất cả các logic trong các nút bấm '' Nhấp chuột ...) –
Dịch: Nếu bạn biết đủ lập trình để có thể làm nó, bạn biết rằng bạn không muốn. – Kaz