How do you retrieve the contents of a RichTextBox in ironpython?
XAML:
<RichTextBox
x:Name = "Sheet_Name"
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="174,62,0,0"
Width="348"
Height="476" />
This is the ironpython:
import clr
clr.AddReference('System.Windows.Forms')
clr.AddReference('IronPython.Wpf')
from pyrevit import script
xamlfile = script.get_bundle_file('ui.xaml')
import wpf
from System import*
class MyWindow(Windows.Window):
def __init__(self):
wpf.LoadComponent(self, xamlfile)
def Create_Sheets(self,sender,args):
RTB = self.Sheet_Number
TR = TextRange(RTB.Document.ContentStart, RTB.Document.ContentEnd).Text
def Help(self,sender,args):
print('Help')
MyWindow().ShowDialog()
The above method does not work as TextRange is not defined.
Edit:
above works if the following is imported:
from System.Windows.Documents import TextRange
<Button Click="MyClickMethod" /> works fine; the XAML type provider exposes MyClickMethod as a virtual method in the code-behind.
On the other hand, override this.MyDoubleClickMethod (_, _) gets the pretty red underlining for <ListBox MouseDoubleClick="MyDoubleClickMethod" />, and of course my program fails to compile.
If ListBox events aren't supported, then it sure would have been nice to know this before I got three days into coding my application. Is FsXaml well documented anywhere (and I don't mean the source code)? What's the generally accepted work-around for my problem?
EDIT : Here are my code files (minus AssemblyInfo.fs and App.* boilerplate), in Solution Explorer order:
MainViewModel.fs:
namespace MyWpf.ViewModels
open ViewModule
open ViewModule.FSharp
type MainViewModel () as self =
inherit ViewModelBase ()
let myItems = self.Factory.Backing (<# self.MyItems #>, Array.empty)
do
self.MyItems <- [| "cheeseburger"; "French fries"; "chocolate shake" |]
member this.MyItems
with get () = lock myItems (fun () -> myItems.Value)
and private set value = lock myItems (fun () -> myItems.Value <- value)
MainView.xaml.fs:
namespace MyWpf.Views
open System.Windows
type MainViewBase = FsXaml.XAML<"MainView.xaml">
type MainView () =
inherit MainViewBase ()
override this.MyDoubleClickMethod (_, _) = MessageBox.Show "click!" |> ignore
MainView.xaml:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:viewModels="clr-namespace:MyWpf.ViewModels;assembly=MyWpf">
<UserControl.DataContext>
<viewModels:MainViewModel />
</UserControl.DataContext>
<Grid>
<ListBox
Name="MyList"
Width="300"
Height="224"
Margin="10,4,10,4"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ItemsSource="{Binding MyItems}"
MouseDoubleClick="MyDoubleClickMethod" />
</Grid>
</UserControl>
MainWindow.xaml.fs:
namespace MyWpf.Windows
type MainWindow = FsXaml.XAML<"MainWindow.xaml">
MainWindow.xaml:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:views="clr-namespace:MyWpf.Views;assembly=MyWpf"
Width="320"
Height="240"
ResizeMode="CanMinimize"
WindowStartupLocation="CenterScreen">
<Grid>
<views:MainView />
</Grid>
</Window>
I am trying to insert a datagrid into popup, but it is't not working correctly (popup contains empty datagrid). I've tried to put my datagrid outside popup and it's worked. I guess popup behaves like seperate window, so I wonder if I supposed to create another ViewModel class for my popup, or is there another way to solve that?
My View xaml code:
<UserControl x:Class="MyApplication.Views.AddArrivalView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-MyApplication.Views" >
<Grid>
<StackPanel Orientation="Horizontal" Margin="5">
//<Some textblocks>
</StackPanel>
<Popup Width="700" Height="300" IsOpen="true">
<DataGrid x:Name="SuggestedCars"
AutoGenerateColumns="true"
IsReadOnly="True">
</DataGrid>
</Popup>
</Grid>
</UserControl>
My ViewModel
namespace MyApplication.ViewModels
{
class AddArrivalViewModel : PropertyChangedBase
{
private BindableCollection<Cars> _suggestedCars;
public BindableCollection<Cars> SuggestedCars
{
get
{
return _suggestedCars;
}
set
{
_suggestedCars = value;
NotifyOfPropertyChange("SuggestedCars");
}
}
public AddArrivalViewModel()
{
SuggestedCars = new BindableCollection<Cars>();
//add some test cars to collection
SuggestedCars.Add(new Cars() { Brand = "Opel", Model = "Corsa", Registration = "000000", ID = 0 });
}
}
}
I have a listbox and a combobox described the XAML code below and I am trying to populate this listbox and combobox from within IronPython code and not XAML.
How can I populate this lists from within code?
On the list I need multiple columns.
<ComboBox
x:Name="comboBox1"
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="53,14.223,0,0"
Width="54"
Height="19" />
<ListBox
x:Name="listBox1"
Grid.Column="0"
Grid.Row="0"
VerticalAlignment="Top"
Margin="0,30.223,14.5,0"
Height="368.639" HorizontalAlignment="Right" Width="442.619" />
Using the accepted answer from following SO post: How do I bind to a ListBox in IronPython? I managed to populate and bind the m the combobox and list from Ironpython code.
I will put all the code here in case anyone find himself/herself in the same situation:
First there is the need of change in the XAML for the listbox to specify the binding:
<DataTemplate x:Key="DataTemplate1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=lproperty, FallbackValue=Property}" />
<TextBlock Text="{Binding Path=lvalue, FallbackValue=Value}" Grid.Column="1" HorizontalAlignment="Right" Margin="0,0,-60,0" Width="360" />
</Grid>
</DataTemplate>
then you need to also bind the listbox content to this template:
<ListBox
x:Name="listBox1"
Grid.Column="0"
Grid.Row="0"
VerticalAlignment="Top"
Margin="0,30.223,14.5,0"
Height="368.639" HorizontalAlignment="Right" Width="442.619"
ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate1}"/>
I will put also here the entire code that populates the combobox and listbox ssince it is not that big:
import wpf
from System.Windows import Application
from Window1 import Window1
from System.Windows.Controls import(ComboBox,
ComboBoxItem, ListBox, ListBoxItem)
from System.Collections.ObjectModel import *
from System.ComponentModel import *
from System.Windows.Controls import *
import pyevent
entries = {
1 : ('Email', 'test.user#gmail.com' ),
2 : ('Address', 'new york'),
3 : ('Notes', 'this is a dummy form'),
4 : ('Mobile Phone', '57234985734'),
5 : ('Work Fax', '5432578943'),
6 : ('Work Phone', '32465765765')
}
politetitles = {
1 : ('Mr' ),
2 : ('Ms'),
3 : ('Mrs'),
4 : ('Sir'),
}
class NotifyPropertyChangedBase(INotifyPropertyChanged):
"""INotifyProperty Helper"""
PropertyChanged = None
def __init__(self):
(self.PropertyChanged, self._propertyChangedCaller) = pyevent.make_event()
def add_PropertyChanged(self, value):
if self.PropertyChanged is not None:
self.PropertyChanged += value
def remove_PropertyChanged(self, value):
if self.PropertyChanged is not None:
self.PropertyChanged -= value
def OnPropertyChanged(self, propertyName):
if self.PropertyChanged is not None:
self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))
class myListEntry(NotifyPropertyChangedBase):
#property
def lvalue(self):
return self._lvalue
#lvalue.setter
def lvalue(self, value):
self._lvalue = value
self.OnPropertyChanged("lvalue")
#property
def lproperty(self):
return self._lproperty
#lproperty.setter
def lproperty(self, value):
self._lproperty = value
self.OnPropertyChanged("lproperty")
window = Window1()
#print window
app = Application()
combo = ComboBox()
titleitems = politetitles.items()
for key, data in titleitems:
item = ComboBoxItem()
item.Content = data
item.FontSize = 8
combo.Items.Add(item)
window.comboBox1.ItemsSource = combo.Items
listitems = entries.items()
listb = ObservableCollection[myListEntry]()
for key, data in listitems:
item = ListBoxItem()
lineitem = myListEntry()
lineitem.lproperty=data[0]
lineitem.lvalue=data[1]
listb.Add(lineitem)
window.listBox1.ItemsSource = listb
print listb
app.Run(window)
In one project I have an Editor Class:
namespace TestXamlInherit234
{
public class CustomerEditor : BaseEditor
{
public CustomerEditor()
{
TheMessage.Text = "changed222";
}
}
}
which inherits from a WPF User Control in another project:
using System.Windows.Controls;
namespace Core
{
public partial class BaseEditor : UserControl
{
public TextBlock TheMessage
{
get
{
return TheMessage2;
}
}
public BaseEditor()
{
InitializeComponent();
}
}
}
<UserControl x:Class="Core.BaseEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<TextBlock x:Name="TheMessage2" Text="This is in the base editor"/>
</Grid>
</UserControl>
This works when both classes are in the same project but when they are in two different projects, I get a XamlParseException error.
Try:
<Core:BaseEditor x:Class="TestXamlInherit234.CustomerEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Core="yourcorenamespace"
Height="300" Width="300">
<Grid>
<TextBlock x:Name="TheMessage2" Text="This is in the base editor"/>
</Grid>
</Core:BaseEditor>
WPF's support for inheriting any kind of UserControls is very limited. When I did this to work around the lack of generics support I had to define my control in code and derive from ContentControl.