Setting wall parameters using WPF

here an example

Iconverter + Binding

code (IronPython3)

import clr    
import sys
import System

clr.AddReference("IronPython.Wpf")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")

from System.IO import StringReader
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
import System.Windows.Controls 
from System.Windows.Controls import *
from System.Windows.Data import IMultiValueConverter, Binding, MultiBinding, IValueConverter
from System.Windows.Media import Brushes
import wpf

class NonNumericConverter(IMultiValueConverter):
    #
    def __init__(self):
        super().__init__()

    def Convert(self, values, targetType, parameter, culture):
        text = values[0]
        out_intValue = clr.Reference[System.Int32]()
        out_decimalValue = clr.Reference[System.Decimal]()
        if System.Int32.TryParse(text, out_intValue) or System.Decimal.TryParse(text, out_decimalValue):
            return Brushes.White
        else:
            return Brushes.Tomato

    def ConvertBack(self, value, targetType, parameter, culture):
        raise NotImplementedError()
    
class MyWindow(Window):
    LAYOUT = '''
        <Window 
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window5"
            Height="300"
            Width="300">
            <Grid>
                <TextBox
                    Grid.Column="0"
                    Grid.Row="0"
                    VerticalAlignment="Top"
                    Height="20"
                    Margin="86,128,84,0"
                    x:Name="textBox" />
            </Grid>
        </Window>'''
                
    def __init__(self):
        super().__init__()
        self.ui = wpf.LoadComponent(self, StringReader(MyWindow.LAYOUT))
        # Create the binding
        binding = MultiBinding()
        converter = NonNumericConverter()
        binding.Converter = converter
        # Bind the Text property of the TextBox
        text_binding = Binding("Text")
        text_binding.Source = self.textBox
        binding.Bindings.Add(text_binding)
        # Apply the binding to the Background property
        self.textBox.SetBinding(TextBox.BackgroundProperty , binding)

objWpf = MyWindow()
objWpf.ShowDialog()

OUT = 0
5 Likes

Thanks a lot @c.poupin

I’m on the move at the moment. I’ll try it later using pyrevit to see how it goes

Thanks.

3 Likes

@c.poupin

After testing your code, I didn’t realize that you suggested using the IronPython3 engine to get it working. (I noticed that I’m using Revit 2023 and have IronPython2 installed), which causes an error in both python engines (Cpython3 and IronPython2 ) related to the missing wpf module and it gives me this error:

image

After doing some research on the web, I found a temporary solution to access IronPython.Wpf and use WPF modules by adding this line to your code:

from IronPython.Modules import Wpf as wpf

However, I still have an error related to loading xaml code in both Python engines, as follows:

If I use Cpython 3 engine, It gives me this error:

and if I use IronPython2 engine it gives me this error

So how can I solve this issue?

Another question: can I upgrade from IronPython2 to IronPython3 in Revit 2023? If so, how can I do that?

Edit:
I also tried to test your example where you used the IronPython2 engine with WPF, but it didn’t work for me and also WPF module is missing
image

Thanks.

Code for Ironpython2 (just remove super().__init__() special syntax for Python3)

import clr    
import sys
import System
clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
#
ipy2_assembly = System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(lambda a :all(x in a.FullName for x in  ["IronPython.Modules", "2.7"]))
assembly_ipy2_Directory = System.IO.Path.GetDirectoryName( ipy2_assembly.Location )
parent_ipy2_Directory = System.IO.Directory.GetParent(assembly_ipy2_Directory).FullName
#
sys.path.append(parent_ipy2_Directory + "\\extra\\IronPython.StdLib.2.7.9")
sys.path.append(parent_ipy2_Directory + "\\bin")

clr.AddReference("IronPython.Wpf")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")

from System.IO import StringReader
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
import System.Windows.Controls 
from System.Windows.Controls import *
from System.Windows.Data import IMultiValueConverter, Binding, MultiBinding, IValueConverter
from System.Windows.Media import Brushes
import wpf

class NonNumericConverter(IMultiValueConverter):
    #
    def Convert(self, values, targetType, parameter, culture):
        text = values[0]
        out_intValue = clr.Reference[System.Int32]()
        out_decimalValue = clr.Reference[System.Decimal]()
        if System.Int32.TryParse(text, out_intValue) or System.Decimal.TryParse(text, out_decimalValue):
            return Brushes.White
        else:
            return Brushes.Tomato

    def ConvertBack(self, value, targetType, parameter, culture):
        raise NotImplementedError()
    
class MyWindow(Window):
    LAYOUT = '''
        <Window 
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window5"
            Height="300"
            Width="300">
            <Grid>
                <TextBox
                    Grid.Column="0"
                    Grid.Row="0"
                    VerticalAlignment="Top"
                    Height="20"
                    Margin="86,128,84,0"
                    x:Name="textBox" />
            </Grid>
        </Window>'''
                
    def __init__(self):
        self.ui = wpf.LoadComponent(self, StringReader(MyWindow.LAYOUT))
        # Create the binding
        binding = MultiBinding()
        converter = NonNumericConverter()
        binding.Converter = converter
        # Bind the Text property of the TextBox
        text_binding = Binding("Text")
        text_binding.Source = self.textBox
        binding.Bindings.Add(text_binding)
        # Apply the binding to the Background property
        self.textBox.SetBinding(TextBox.BackgroundProperty , binding)

objWpf = MyWindow()
objWpf.ShowDialog()

OUT = 0

for CPython3/PythonNet2 it’s a bit more complex, I’ll post the code later if you really need it

2 Likes

@c.poupin

Again, it’s not working!

try to add

clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
#
ipy2_assembly = System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(lambda a :all(x in a.FullName for x in  ["IronPython.Modules", "2.7"]))
assembly_ipy2_Directory = System.IO.Path.GetDirectoryName( ipy2_assembly.Location )
parent_ipy2_Directory = System.IO.Directory.GetParent(assembly_ipy2_Directory).FullName
#
sys.path.append(parent_ipy2_Directory + "\\extra\\IronPython.StdLib.2.7.9")
sys.path.append(parent_ipy2_Directory + "\\bin")

I updated my post above

2 Likes

Sorry @c.poupin I add your last code but it’s still not working and wpf module is not loaded!!?

I searched for the IronPython 2.7 DLL in C:\Program Files (x86), and it does not exist. Could I be missing an installation of IronPython 2.7?

Thanks.

I don’t know, the wpf module is normally already present in the DSIronpython2 package.

I’m making a new correction, give it a try,

@c.poupin
This code is driving me crazy, and I don’t know why it won’t work. :rage:

I checked my IronPython package and WPF dll are there

I tried your last correction but it still gives me the same error and wpf is not loaded

Question: As I explained in post #23, why does adding the following line give me an error related to the LoadComponent function, which is part of wpf and not wpf itself? Does this mean that wpf is loaded in this case?

from IronPython.Modules import Wpf as wpf

Thanks.

try to update DSIronPython2 package to 2.5

there is maybe a conflict with another addin, pyRevit?, RevitPythonShell?

1 Like

@c.poupin

I updated the DSIronPython2 package to version 2.5 as you suggested, and I confirm that there’s a conflict either with pyRevit or RevitPythonShell :roll_eyes:

With those two add-ins disabled, as you can see below, I can run your first script without needing to append sys with the WPF module (I only removed the super().__init__() syntax specific to Python 3 to make it work).

image

The question now is how to solve this issue permanently without disabling pyrevit and RevitPythonShell, as I need to use them!?

Thanks.

First make sure you’re on the latest version. Then if the issue persists reach out to the add-in provider - Dynamo and the community can’t help you here, only they can.

2 Likes

@c.poupin
I finally solved my issue by updating pyrevit from version 4.8.13 to 4.8.16, and I can now run your code in Dynamo without needing to disable pyrevit.

Question:
When I type a float number, the color of the input textbox changes to tomato. Does that mean the float number is not defined properly?

Thanks.

hi, try to see if it wouldn’t come from the decimal separator, or .
may be a lead or not
Sincerely
christian.stan

2 Likes

the syntax for the Net Framework is a little bit different

code for IronPython2 + Net Framework 4.8
import clr    
import sys
import System

clr.AddReference("IronPython.Wpf")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")

from System.IO import StringReader
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
import System.Windows.Controls 
from System.Windows.Controls import *
from System.Windows.Data import IMultiValueConverter, Binding, MultiBinding, IValueConverter
from System.Windows.Media import Brushes
import wpf

class NonNumericConverter(IMultiValueConverter):
    #

    def Convert(self, values, targetType, parameter, culture):
        text = values[0]
        out_intValue = clr.Reference[System.Int32]()
        out_decimalValue = clr.Reference[System.Decimal]()
        style = System.Globalization.NumberStyles.Number 
        culture = System.Globalization.CultureInfo.CreateSpecificCulture("en-GB")
        if System.Int32.TryParse(text, out_intValue) or System.Decimal.TryParse(text, style, culture, out_decimalValue):
            return Brushes.White
        else:
            return Brushes.Tomato

    def ConvertBack(self, value, targetType, parameter, culture):
        raise NotImplementedError()
    
class MyWindow(Window):
    LAYOUT = '''
        <Window 
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window5"
            Height="300"
            Width="300">
            <Grid>
                <TextBox
                    Grid.Column="0"
                    Grid.Row="0"
                    VerticalAlignment="Top"
                    Height="20"
                    Margin="86,128,84,0"
                    x:Name="textBox" />
            </Grid>
        </Window>'''
                
    def __init__(self):
        self.ui = wpf.LoadComponent(self, StringReader(MyWindow.LAYOUT))
        # Create the binding
        binding = MultiBinding()
        converter = NonNumericConverter()
        binding.Converter = converter
        # Bind the Text property of the TextBox
        text_binding = Binding("Text")
        text_binding.Source = self.textBox
        binding.Bindings.Add(text_binding)
        # Apply the binding to the Background property
        self.textBox.SetBinding(TextBox.BackgroundProperty , binding)

objWpf = MyWindow()
objWpf.ShowDialog()

OUT = 0
code for IronPython3 + Net Core6+
import clr    
import sys
import System

clr.AddReference("IronPython.Wpf")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")

from System.IO import StringReader
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
import System.Windows.Controls 
from System.Windows.Controls import *
from System.Windows.Data import IMultiValueConverter, Binding, MultiBinding, IValueConverter
from System.Windows.Media import Brushes
import wpf

class NonNumericConverter(IMultiValueConverter):
    #
    def __init__(self):
        super().__init__()

    def Convert(self, values, targetType, parameter, culture):
        text = values[0]
        out_intValue = clr.Reference[System.Int32]()
        out_decimalValue = clr.Reference[System.Decimal]()
        if System.Int32.TryParse(text, out_intValue) or System.Decimal.TryParse(text, out_decimalValue):
            return Brushes.White
        else:
            return Brushes.Tomato

    def ConvertBack(self, value, targetType, parameter, culture):
        raise NotImplementedError()
    
class MyWindow(Window):
    LAYOUT = '''
        <Window 
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window5"
            Height="300"
            Width="300">
            <Grid>
                <TextBox
                    Grid.Column="0"
                    Grid.Row="0"
                    VerticalAlignment="Top"
                    Height="20"
                    Margin="86,128,84,0"
                    x:Name="textBox" />
            </Grid>
        </Window>'''
                
    def __init__(self):
        super().__init__()
        self.ui = wpf.LoadComponent(self, StringReader(MyWindow.LAYOUT))
        # Create the binding
        binding = MultiBinding()
        converter = NonNumericConverter()
        binding.Converter = converter
        # Bind the Text property of the TextBox
        text_binding = Binding("Text")
        text_binding.Source = self.textBox
        binding.Bindings.Add(text_binding)
        # Apply the binding to the Background property
        self.textBox.SetBinding(TextBox.BackgroundProperty , binding)

objWpf = MyWindow()
objWpf.ShowDialog()

OUT = 0
2 Likes

I tested the code in IronPython2, and it works fine. So far, I’ve gotten what I was looking for, and that resolves my issue.

Thanks a lot @c.poupin

1 Like