Доброго времени суток уважаемые форумчане. Долго думал - в какой раздел написать, решил сюда. Собственно проблема: Есть у меня класс в проекте WPF, который загружает элементы управления из файла (XML). Из этого же файла он загружает скрипты на PowerShell. Эти скрипты я записываю в Runspace своего PowerShell. У меня стоит задача, в скрипте получить доступ к данным элементов формы (например, прочитать текст из TextBox-ов), для этого я загружаю свои элементы на форму, создаю Runspace, в который загружаю свой скрипт, и в этот же Runspace передаю все контролы по именам - в качестве переменных. Вот псевдокод (без использования файла, только идея)| Код | using System.Management.Automation; using System.Management.Automation.Runspaces;
namespace WpfApplication5 { public partial class TaskWnd : Window { readonly Runspace runspace; public TaskWnd( String path ) { InitializeComponent(); runspace = RunspaceFactory.CreateRunspace(); runspace.RunspaceConfiguration.Scripts.Reset(); // чтение файла конфигурации LoadConfig( path ); }
private void LoadConfig( String path ) { String XAMLCode = "<Grid xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" \nxmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"><StackPanel><TextBox Name=\"textBox1\">Hello</TextBox><Button Content=\"button1\" Name=\"button1\"></Button><Button Content=\"button2\" Name=\"button2\"></Button></StackPanel></Grid>"; // добавляем элементы на форму UIElement rootElement; rootElement = (UIElement)XamlReader.Load(new XmlTextReader(new StringReader(XAMLCode))); this.UIContent.Children.Clear(); this.UIContent.Children.Add(rootElement);
// заполнение функциями ScriptConfigurationEntry script = new ScriptConfigurationEntry("button2_Click", "$textBox1.Text"); //скрипт для обработки нажатия на кнопку runspace.RunspaceConfiguration.Scripts.Append(script); runspace.Open();
// Подключаем эти элементы к событиям ConnectObjectsToEvent(this); // Добавляем эти элементы в Runspace PowerShell AddObjectsToRunspace(this); }
private void AddObjectsToRunspace(FrameworkElement node) { System.Collections.IEnumerable allObj = LogicalTreeHelper.GetChildren(node); foreach (Object obj in allObj) { if (obj.GetType().ToString() == "System.Windows.Controls.Button") { Button RefButton = (Button)obj; runspace.SessionStateProxy.SetVariable(RefButton.Name, RefButton); } if (obj.GetType().ToString() == "System.Windows.Controls.TextBox") { TextBox RefText = (TextBox)obj; runspace.SessionStateProxy.SetVariable(RefText.Name, RefText); } try { AddObjectsToRunspace((FrameworkElement)obj); } catch // исключение, если обьект не есть контейнером { } } }
private void ConnectObjectsToEvent(DependencyObject node) { System.Collections.IEnumerable allObj = LogicalTreeHelper.GetChildren(node); foreach (Object obj in allObj) { if (obj.GetType().ToString() == "System.Windows.Controls.Button") { Button RefButton = (Button)obj; RefButton.Click += new RoutedEventHandler(all_Buttons_Click); } try { ConnectObjectsToEvent((DependencyObject)obj); } catch // исключение, если обьект не есть контейнером { } } }
// общий обработчик для всех кнопок private void all_Buttons_Click(object sender, RoutedEventArgs e) { Button refButton = (Button)sender; string sFuncName = String.Format("{0}_{1}", refButton.Name, "Click"); Pipeline pl = runspace.CreatePipeline(sFuncName); try { Collection<PSObject> objs = pl.Invoke(); // <----------- вот тут } catch (Exception ex) { MessageBox.Show(ex.Message); } } } }
|
В коде стрелочкой обозначено, где я хочу получить данные из TextBox, но почему-то получаю Null, хотя точно знаю что поле не пустое. Также возникает исключение - cross thread - если я в скрипте пропишу что-то такое $button1.Content=\"hello\". Подскажите, что в коде не так? Правильно ли я передал переменные в Runspace. И как обойти проблемы с работой в разных потоках. Спасибо. |