अप सीट, आप एक सवारी के लिए कर रहे हैं।
सबसे पहले, एक नया सी # बनाने के (या VB.NET .. जो कुछ भी अपनी नाव चट्टानों) वर्ग पुस्तकालय, और एक नया WPF UserControl जोड़ देंगे और अपने यूआई डिजाइन:
<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" />
</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" />
</Button>
<Button Width="128" Command="{Binding Command2}">
<TextBlock Text="Button2" />
</Button>
</StackPanel>
</Grid>
</UserControl>
बिल्ड परियोजना।
फिर, नई विधि जोड़ें एक WPF इंटरॉप ElementHost
नियंत्रण गोदी, और आप की मेजबानी WPF नियंत्रण के रूप में अपने WPF UserControl1
(जो भी आप यह कहा जाता है) को जोड़ने के लिए सक्षम होना चाहिए। है, तो आप प्रबंधित कोड लागू करने के लिए एक वर्ग की आवश्यकता होगी -
WPF नियंत्रण (मॉडल-व्यू-ViewModel तर्ज पर पढ़ वास्तव में किसी और और सब कुछ,) Command1
और Command2
ऊपर हुक करने के लिए डेटा बाइंडिंग का उपयोग करता है भाग।यदि आपका तर्क सभी 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);
}
}
}
एक DelegateCommand
एक बहुत ही अच्छी छोटी बात सभी स्टैक ओवरफ़्लो हो चुका है है, तो आप कोई प्रश्न हैं खोज करने के लिए संकोच नहीं करते:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void SetDataContext(ViewModel1 viewModel)
{
hostedWPFControl.DataContext = viewModel;
}
}
: ऐसा करने के लिए एक विधि का पर्दाफाश -
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);
}
}
WinForms विधि निर्दिष्ट करने के WPF नियंत्रण के DataContext
की आवश्यकता होगी 0
इसके अलावा, यहां कोई भी कोड नहीं होना चाहिए।
WPF MVVM पैटर्न पसंद करती है, WinForms एमवीपी (देखने मॉडल-व्यू-प्रस्तुतकर्ता) पसंद करती है।
[ComVisible(true)]
public interface IPresenter1
{
void Show();
}
हाँ, वह सिर्फ एक इंटरफ़ेस है: उस वस्तु VBA कोड का उपयोग करेगा है - WPF हिस्सा WinForms में होस्ट किया जा रहा है, हम एक प्रस्तोता बना देंगे। पर रखें, हम एक और की जरूरत है:
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("18F3B8A8-EC60-4BCE-970A-6C0ABA145705")]
[ComVisible(true)]
public interface IPresenterEvents
{
void ExecuteCommand1(object message);
void ExecuteCommand2();
}
IPresenterEvents
इंटरफ़ेस आपके "घटना सिंक" इंटरफेस है, कि VBA कोड को लागू करने की आवश्यकता होगी, लेकिन मैं इसे करने के लिए मिल जाएगा। पहले हम वास्तविक प्रस्तोता implment की जरूरत है:
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();
}
}
अब, परियोजना के गुण होते हैं और फिर जाँच करें कि चेकबॉक्स "COM इंटरॉप के लिए रजिस्टर", तो परियोजना का निर्माण; [डीबग] टैब में, का चयन करें "बाहरी प्रोग्राम प्रारंभ करें" शुरू करें, और अपनी मशीन पर EXCEL.EXE निष्पादन योग्य का पता लगाएं: जब आप F5 दबाते हैं, विजुअल स्टूडियो एक्सेल लॉन्च डीबगर के साथ लॉन्च करेगा, और फिर आप खोल सकते हैं वीबीई (Alt + F11), जिसे आपने अभी बनाया है .tlb (टाइप लाइब्रेरी) का संदर्भ जोड़ें (आप इसे \bin\debug\theprojectname.tlb
के तहत, अपनी डीनेट प्रोजेक्ट निर्देशिका में पाएंगे, डीबग बिल्ड मानते हैं), और इसे करना चाहिए ।
वहाँ कई मुद्दों यहाँ है कि मैं वापस आऊँगा बाद में तय करने के लिए कर रहे हैं,:
Dispose()
विधि उजागर नहीं है, और स्पष्ट या परोक्ष, किसी भी बिंदु पर नहीं कहा जा होगा जो गन्दा है।
- हालांकि सब कुछ ऐसा लगता है जैसे यह सी # डीबगर के दृष्टिकोण से काम कर रहा है, मुझे डर्न वीबीए हैंडलर चलाने के लिए नहीं मिल सका। यदि आप वीबीए में तर्क को लागू करना चाहते हैं तो यह शायद एक बड़ी समस्या है, न केवल यूआई लाएं। ओटीओएच आपके पास .NET कोड तक पहुंच है, साथ ही प्रस्तुतकर्ता में प्रस्तुतकर्ता तर्क को सी #/वीबी.नेट में भी लागू कर सकता है, और फिर आपको इन ईवेंट हैंडलर को काम करने की आवश्यकता नहीं है।
वैसे भी, मैं 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
और जब मैं तत्काल खिड़की (Ctrl + G) से ThisWorkbook.DoSomething
चलाने के लिए, मैं इस मिल:
सिद्धांत में (कम से कम MSDN के अनुसार), आपको बस इतना करना है। जैसा कि मैंने कहा था कि इन घटनाओं के हैंडलर किसी कारण से नहीं बुला रहे हैं, लेकिन हे, आपको अपने चमकदार बटन मिलते हैं! ... और अब आपके यूआई को डिज़ाइन करने के लिए डब्ल्यूपीएफ की सभी शक्ति :)
मुझे यह भी जानना अच्छा लगेगा। – DeerSpotter
* क्या मुझे इन ग्रे चीजों का उपयोग करना है जैसे वे विंडोज 2000 * से आते हैं - मुझे लगता है कि वे वास्तव में Win95 से हैं। यदि आप * चमकदार और नया * चाहते हैं, तो आप अपने यूआई को COM-visible .net क्लास लाइब्रेरी (.dll) में WPF/XAML के साथ बना सकते हैं, और * V * को अपने वीबीए कोड से उपयोग कर सकते हैं। आपकी कोडिंग शैली के आधार पर यह * गंभीर वास्तुशिल्प परिवर्तनों का अर्थ हो सकता है (यानी यदि आप बटन 'क्लिक' हैंडलर में सभी तर्क लागू करने के लिए उपयोग किए जाते हैं ...) –
अनुवाद: यदि आप पर्याप्त प्रोग्रामिंग करने में सक्षम होने के बारे में जानते थे यह, आप जानते होंगे कि आप नहीं चाहते हैं। – Kaz