2015-12-29 2 views
2

У меня возникли проблемы, на которые я надеюсь, что вы сможете помочь! Я пытаюсь обновить этот параметр grid.Width в цикле while, во время сна (500). Но, когда я нажимаю скрипт запуска в своей программе, весь графический интерфейс останавливается. Я уже пробовал запустить сценарий в другом потоке и использовать BackgroundWorker, но все же в обоих случаях они блокируют мой графический интерфейс приложения до завершения скрипта. Не могли бы вы взглянуть на следующий код, пожалуйста?IronPython как язык сценариев для C# WPF VS 2015

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

using System.IO; 
using System.Threading; 
using IronPython.Hosting; 
using Microsoft.Scripting; 
using Microsoft.Scripting.Hosting; 

namespace WpfApplication1 
{ 
/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    string script; 
    ScriptEngine engine; 
    ScriptScope scope; 
    Thread threadScript; 

    public MainWindow() 
    { 
     InitializeComponent(); 

     engine = Python.CreateEngine(); 
     scope = engine.CreateScope(); 
     string variableName = "isto"; 
     object gridMier = gridScript; 
     scope.SetVariable(variableName, gridMier); 
    } 

    public void rodarScript() 
    { 
     this.Dispatcher.Invoke((Action)(() => 
     { 
      try 
      { 
       //PARTE PARA ADICIONAR BIBLIOTECAS BASICAS PARA DESENVOLVIMENTO COM OS SCRIPTS 
       script = @"#Reference the WPF assemblies 
import clr 
clr.AddReferenceByName(""PresentationFramework, Version = 3.0.0.0, Culture =  neutral, PublicKeyToken = 31bf3856ad364e35"") 
clr.AddReferenceByName(""PresentationCore, Version=3.0.0.0, Culture=neutral,  PublicKeyToken=31bf3856ad364e35"") 
import System.Windows 
def getMyObject(): 
    return isto 

objeto = getMyObject() 

#Atalhos de referencias para adicionar 
Thickness = System.Windows.Thickness 
from System.Threading.Thread import Sleep 
Debug = System.Diagnostics.Debug"; 

       script = script + "\n" + textBoxScript.Text; 
       var source = engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements); 
       //var compiled = source.Compile(); 
       //var result = compiled.Execute(scope); 
       source.Execute(scope); 
      } 
      catch (Exception qualquerExcecaoEncontrada) 
      { 
       MessageBox.Show(qualquerExcecaoEncontrada.ToString(), "Scripting Test do Mier", MessageBoxButton.OK); 
      } 
     })); 
    } 

    private void buttonScript_Click(object sender, RoutedEventArgs e) 
    { 
     threadScript = new Thread(rodarScript); 
     threadScript.Start(); 
    } 
} 
} 

пример кода в IronPython (textBoxScript.Text)

for num in range(1,100): 
    objeto.Width = objeto.Width + 1 
    Sleep(500) 

Этот простой код, работающий на волоске, блокирует весь мой GUI в течение 50 секунд. Любая помощь будет оценена!

Thanks, Lucas.

+0

Во всех смыслах и задачах 'threadScript' никогда не используется. Вы сразу же «Dispatcher.Invoke» возвращаетесь к потоку пользовательского интерфейса. – Mitch

+0

Извините, Митч не понял этого. threadScript используется, когда я нажимаю на эту кнопку, которую я имею в приложении. buttonScript_Click запускает его. –

+0

Вы начинаете его, но сразу же возвращаетесь к потоку пользовательского интерфейса. Вы никогда не работаете с 'threadScript'. Если это не имеет смысла, вы должны, вероятно, попытаться лучше понять, что делает 'Dispatcher.Invoke': он запускает произвольный метод в потоке пользовательского интерфейса и ждет результата. Итак, весь код, который вы используете в 'rodarScript', работает в потоке пользовательского интерфейса, а не в' threadScript'. – Mitch

ответ

1

Создание отдельной темы, а затем размещение полного содержимого в Dispatcher.Invoke не имеет смысла. Потому что вы снова синхронизировались с нитью ui (время воя). Вы должны использовать только те вещи, которые должны быть (доступ к пользовательскому интерфейсу). Сначала удалите, что с rodarScript и использовать его только для script = script + "\n" + textBoxScript.Text;:

public void rodarScript() 
    { 
     try 
     { 
      //PARTE PARA ADICIONAR BIBLIOTECAS BASICAS PARA DESENVOLVIMENTO COM OS SCRIPTS 
      script = @"#..."; 

      this.Dispatcher.Invoke((Action)(() => 
      { 
       script = script + "\n" + textBoxScript.Text; 
      })); 

      var source = engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements); 
      //var compiled = source.Compile(); 
      //var result = compiled.Execute(scope); 
      source.Execute(scope); 
     } 
     catch (Exception qualquerExcecaoEncontrada) 
     { 
      MessageBox.Show(qualquerExcecaoEncontrada.ToString(), "Scripting Test do Mier", MessageBoxButton.OK); 
     } 
    } 

(Удалены IP-код).

Затем добавить простой метод, который принимает экземпляр PythonFunction и добавить его в качестве переменной, например:

public void ExecuteInUI(object obj) 
{ 
    this.Dispatcher.BeginInvoke((Action)(() => 
    { 
     var op = engine.CreateOperations(scope); 
     op.Invoke(obj); 
    })); 
} 

Добавить в переменной:

scope.SetVariable("execute_in_ui", new Action<object>(ExecuteInUI)); 

Тогда вы должны chagne СВОЙ Python немного, потому что вы только хотите использовать BeginInvoke при доступе к ui:

def inc_width(): 
    objeto.Width = objeto.Width + 1 

for num in range(1,100): 
    execute_in_ui(inc_width) 
    Sleep(500) 

Итак, мы передаем информацию о функции inc_width на C# и выполним ее там ExecuteInUI. Тогда полный код будет выглядеть следующим образом:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

using System.IO; 
using System.Threading; 
using IronPython.Hosting; 
using Microsoft.Scripting; 
using Microsoft.Scripting.Hosting; 

namespace AsyncIronPython 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     string script; 
     ScriptEngine engine; 
     ScriptScope scope; 
     Thread threadScript; 

     public MainWindow() 
     { 
      InitializeComponent(); 

      engine = Python.CreateEngine(); 
      scope = engine.CreateScope(); 
      string variableName = "isto"; 
      object gridMier = gridScript; 
      scope.SetVariable(variableName, gridMier); 
      scope.SetVariable("execute_in_ui", new Action<object>(ExecuteInUI)); 
     } 

     public void ExecuteInUI(object obj) 
     { 
      this.Dispatcher.BeginInvoke((Action)(() => 
      { 
       var op = engine.CreateOperations(scope); 
       op.Invoke(obj); 
      })); 
     } 

     public void rodarScript() 
     { 
      try 
      { 
       //PARTE PARA ADICIONAR BIBLIOTECAS BASICAS PARA DESENVOLVIMENTO COM OS SCRIPTS 
       script = @"#Reference the WPF assemblies 
import clr 
clr.AddReferenceByName(""PresentationFramework, Version = 3.0.0.0, Culture =  neutral, PublicKeyToken = 31bf3856ad364e35"") 
clr.AddReferenceByName(""PresentationCore, Version=3.0.0.0, Culture=neutral,  PublicKeyToken=31bf3856ad364e35"") 
import System.Windows 
def getMyObject(): 
    return isto 

objeto = getMyObject() 

#Atalhos de referencias para adicionar 
Thickness = System.Windows.Thickness 
from System.Threading.Thread import Sleep 
Debug = System.Diagnostics.Debug"; 

       this.Dispatcher.Invoke((Action)(() => 
       { 
        script = script + "\n" + textBoxScript.Text; 
       })); 

       var source = engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements); 
       //var compiled = source.Compile(); 
       //var result = compiled.Execute(scope); 
       source.Execute(scope); 
      } 
      catch (Exception qualquerExcecaoEncontrada) 
      { 
       MessageBox.Show(qualquerExcecaoEncontrada.ToString(), "Scripting Test do Mier", MessageBoxButton.OK); 
      } 
     } 

     private void buttonScript_Click(object sender, RoutedEventArgs e) 
     { 
      threadScript = new Thread(rodarScript); 
      threadScript.Start(); 
     } 
    } 
} 

XAML:

<Window x:Class="AsyncIronPython.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:AsyncIronPython" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid x:Name="gridScript"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="30" /> 
     </Grid.RowDefinitions> 

     <TextBox x:Name="textBoxScript" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="3" AcceptsReturn="True" AcceptsTab="True" /> 
     <Button x:Name="buttonScript" Click="buttonScript_Click" VerticalAlignment="Center" HorizontalAlignment="Stretch" Content="Execute" Grid.Row="1" Margin="3" /> 

    </Grid> 
</Window> 

Надеется, что это помогает.

0

Спасибо @BengEg и людям, это именно то, что я искал. Я пытался создавать анимации в текстовых блоках, сетках, пользовательских элементах управления вообще, используя скрипт IronPython внутри C# WPF. Таким образом, у меня возникли проблемы с поиском способа сделать это, поскольку пользовательские элементы управления используются другими потоками в моей программе. Итак, вот окончательный «код сценария тестирования».

CSharp

using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using System.Threading.Tasks; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Data; 
    using System.Windows.Documents; 
    using System.Windows.Input; 
    using System.Windows.Media; 
    using System.Windows.Media.Imaging; 
    using System.Windows.Navigation; 
    using System.Windows.Shapes; 

    using System.IO; 
    using System.Threading; 
    using IronPython.Hosting; 
    using Microsoft.Scripting; 
    using Microsoft.Scripting.Hosting; 

    namespace AsyncIronPython 
    { 
     /// <summary> 
     /// Interaction logic for MainWindow.xaml 
     /// </summary> 
     public partial class MainWindow : Window 
     { 
      string script; 
      ScriptEngine engine; 
      ScriptScope scope; 
      Thread threadScript; 

      public MainWindow() 
      { 
       InitializeComponent(); 

       engine = Python.CreateEngine(); 
       scope = engine.CreateScope(); 
       scope.SetVariable("objetoEditavel", gridScript); 
       scope.SetVariable("execute_in_ui", new Action<object>(ExecuteInUI)); 
      } 

      public void ExecuteInUI(object obj) 
      { 
       this.Dispatcher.BeginInvoke((Action)(() => 
       { 
        var op = engine.CreateOperations(scope); 
        op.Invoke(obj); 
       })); 
      } 

      public void rodarScript() 
      { 
       try 
       { 
        //PARTE PARA ADICIONAR BIBLIOTECAS BASICAS PARA DESENVOLVIMENTO COM OS SCRIPTS 
        script = @"#Reference the WPF assemblies 
    import clr 
    clr.AddReferenceByName(""PresentationFramework, Version = 3.0.0.0, Culture =  neutral, PublicKeyToken = 31bf3856ad364e35"") 
    clr.AddReferenceByName(""PresentationCore, Version=3.0.0.0, Culture=neutral,  PublicKeyToken=31bf3856ad364e35"") 
    import System.Windows 
    def getMyObject(): 
     return objetoEditavel 

    objeto = getMyObject() 

    #Atalhos de referencias para adicionar 
    Thickness = System.Windows.Thickness 
    from System.Threading.Thread import Sleep 
    Debug = System.Diagnostics.Debug"; 

        this.Dispatcher.Invoke((Action)(() =>{script = script + "\n" + textBoxScript.Text;})); 

        var source = engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements); 
        source.Execute(scope); 
       } 
       catch (Exception qualquerExcecaoEncontrada) 
       { 
        MessageBox.Show(qualquerExcecaoEncontrada.ToString(), "Scripting Test do Mier", MessageBoxButton.OK); 
       } 
      } 

      private void buttonScript_Click(object sender, RoutedEventArgs e) 
      { 
       threadScript = new Thread(rodarScript); 
       threadScript.Start(); 
      } 
     } 
    } 

XAML

<Window x:Class="AsyncIronPython.MainWindow" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:local="clr-namespace:AsyncIronPython" 
      mc:Ignorable="d" 
      Title="MainWindow" Height="350" Width="525"> 
     <Grid> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="*" /> 
       <RowDefinition Height="30" /> 
      </Grid.RowDefinitions> 

      <TextBox x:Name="textBoxScript" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="261,3,3,3" AcceptsReturn="True" AcceptsTab="True" Background="#FFFFD6D6" /> 
      <Button x:Name="buttonScript" Click="buttonScript_Click" VerticalAlignment="Center" HorizontalAlignment="Stretch" Content="Execute" Grid.Row="1" Margin="3" /> 
      <Grid x:Name="gridScript" HorizontalAlignment="Left" Height="50" Margin="10,10,0,0" VerticalAlignment="Top" Width="50" Background="Black"/> 

     </Grid> 
    </Window> 

IronPython сценария внутри gridScript (в основном будут создавать анимацию этого черного ящика сетки, чтобы расти в интервале 50 миллисекунд.

def inc_width(): 
     objeto.Width = objeto.Width + 1 

    for num in range(1,100): 
     execute_in_ui(inc_width) 
     Sleep(50) 
Смежные вопросы