Ironpython wpf RichTextBox - wpf

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

Related

Data binding WPF + IRONPYTHON

I want to conncet wpfcode and ironpython. but I don't know how to use the
data binding in between xaml & py files. How should I do?
XAML :
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WpfApplication9" Height="300" Width="300">
<Grid>
<TextBlock Text="{Binding Path=time1()}" HorizontalAlignment="Left" Margin="10,117,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="272"/>
</Grid>
</Window>
IronPython :
import wpf
import time
from System.Windows import Application, Window
from time import localtime
class MyWindow(Window):
def __init__(self):
wpf.LoadComponent(self, 'test.xaml')
self.TextBlock.Text = time1()
def time1():
now = time.localtime()
setime = "%02d%02d%02d" % (now.tm_hour, now.tm_min, now.tm_sec)
while 1:
cnow = time.localtime()
ntime = "%02d%02d%02d" % (cnow.tm_hour, cnow.tm_min, cnow.tm_sec)
if int(ntime) != int(setime):
realtime = "%02d:%02d:%02d" % (cnow.tm_hour, cnow.tm_min, cnow.tm_sec)
print realtime
setime = ntime
if __name__ == '__main__':
Application().Run(MyWindow())
time1()
You should bind agains properties:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WpfApplication9" Height="300" Width="300">
<Grid>
<TextBlock Text="{Binding SomeMemer, Mode=TwoWay}" HorizontalAlignment="Left" Margin="10,117,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="272"/>
</Grid>
</Window>
IronPython:
import wpf
import time
from System.Windows import Application, Window
from time import localtime
class MyWindow(Window):
someMember = None
def __init__(self):
wpf.LoadComponent(self, 'test.xaml')
self.someMember = "Hello World"
#property
def SomeMember(self):
return self.someMember
#psetter.SomeMember
def SomeMember(self, value):
self.someMember = value
if __name__ == '__main__':
Application().Run(MyWindow())
time1()

Adding Dynamically Control in WPF on Button click

I have three Text Box called TxtDocumentTitle1, TxtDocumentTitle2,TxtDocumentTitle3 lastly there is a Add More Button. Client can Click Add more Button so that it generates Text box naming TxtDocumentTitle4. If more needed he/she can Add more Text Boxes.
Sample XAML code of View
<Grid Height="450" Width="700" Background="White">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="67,20,0,0" Name="textBlocKname" Text="Document Title1:" VerticalAlignment="Top" Width="110" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="67,87,0,0" Name="textBlockAddress" Text="Document Title2:" VerticalAlignment="Top" Width="110" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="67,154,0,0" Name="textBlockCompanyName" Text="Document Title3:" VerticalAlignment="Top" Width="110" />
<TextBox Height="46" Margin="67,37,87,0" Name="txtDocumentTitle1" VerticalAlignment="Top" FontSize="24" />
<TextBox Height="46" HorizontalAlignment="Left" Margin="67,106,0,0" Name="txtDocumentTitle3" VerticalAlignment="Top" Width="546" FontSize="24" />
<TextBox Height="46" HorizontalAlignment="Left" Margin="67,171,0,0" Name="txtDocumentTitle2" VerticalAlignment="Top" Width="546" FontSize="24" />
<Button Content="Add More" Height="37" HorizontalAlignment="Right" Margin="0,223,87,0" Name="btnAddmore" VerticalAlignment="Top" Width="102" />
</Grid>
You can achieve this easily via Binding. if your Window does not have a ViewModel open your window's xaml.cs and make it like this:
public Window1()
{
InitializeComponent();
DataContext = this;
}
public ObservableCollection<TextBoxVm> Items { get { return _items; } }
private ObservableCollection<TextBoxVm> _items = new ObservableCollection<TextBoxVm>();
if not, just add the two last lines to the viewModel of your window.
Now you need to define a class derived from DependencyObject and name it say TextBoxVm. create two DependencyPropertys in it (use propdp snippet) as follows:
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(TextBoxVm), new UIPropertyMetadata("default text",
(d,e)=>
{
var vm = (TextBoxVm)d;
var val = (string)e.NewValue;
MyDataService.FindAndUpdateItemInDatabase(vm.Id, val);//you can access database with something like this
}));
public string TitleText
{
get { return (string)GetValue(TitleTextProperty); }
set { SetValue(TitleTextProperty, value); }
}
public static readonly DependencyProperty TitleTextProperty =
DependencyProperty.Register("TitleText", typeof(string), typeof(TextBoxVm), new UIPropertyMetadata("default title"));
This would be the xaml code:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding TitleText}"/>
<TextBox Text="{Binding Text}"/>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Now the only thing left is to write Button logic. simply add TextBoxVm to Items when Button is clicked.
Items.Add(new TextBoxVm {
TitleText = string.Format("Document Title{0}:", Items.Count+1)
});
Edit Note:
this approach is standard MVVM (expect for the button click event, which should be done using Command). So if you want to add controls in code (which is not recommended) search this :
add control to wpf grid programmatically.
*Above Answer from Bizz Gives Solution of My Question * Beside that it Rise me a Question about *DependencyObject * after Few Research i found this about Dependancy Object which may be Helpful for New comer to WPF like me :)
What is DependencyObject??
Dependency object is the base object for all WPF objects. All the UI Elements like Buttons TextBox etc and the Content Elements like Paragraph, Italic, Span etc all are derived from Dependency Object.
Dependency objects are used for WPF property system. By default, what ever the property system we have in DOT Net CLR is very basic. But Dependency properies provide lots of addtional features/services to support Data Binding.
Once you create any property as a dependency property, then automatically you get following feature implemented for you. ie. Change Notification, Validation, Call Back, Inheritance, DataBinding, Styles, Default Values etc.
If you need to implement all these features on your own for all properties where you need these feature, then it will be a big process and head ache for you. So, these all coming out of the box from Dependency Object class.
Basically dependency object class contains a dictionary. So, when ever set any value or retrieve value, then it will change the value or read from that Dictionary. So, it is nothing but a key value pair.
For Detail Info abouT DependencyObject
http://www.codeproject.com/Articles/140620/WPF-Tutorial-Dependency-Property
http://www.pinfaq.com/32/what-is-dependency-object-in-wpf-where-should-i-use-it

Converting UI from Windows Forms to WPF databinding

I currently have an application with a user interface in Windows Forms. The code behind this user interface communicates with a service.
For example, I have the following code:
public partial class MainWindow : Window
{
private KeyLessAccessLogic ServiceLogic;
public MainWindow()
{
InitializeComponent();
ServiceLogic = new KeyLessAccessLogic();
//LoadValues();
}
public KeyLessAccessLogic MyServiceLogic
{
get { return ServiceLogic; }
set
{
ServiceLogic = value;
// RaisePropertyChanged("MyServiceLogic");
}
}
private void BindDataSource()
{
cmb_user_name.DataSource = null;
cmb_user_name.Sorted = false;
cmb_user_name.DataSource = ServiceLogic.Users;
cmb_user_name.DisplayMember = "name";
}
And my XAML:
<ComboBox Height="23" HorizontalAlignment="Left" Margin="6,71,0,0"
Name="cmb_user_update" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Path=MyServiceLogic.Users}" DisplayMemberPath="name" />
Now I recreated the UI in WPF, and I'm a bit lost on the new format. I do believe that example I gave here is one of the examples of the difference between WPF and Windows Forms.
How can I let my application know what the datasource should be of the Dropdown-box cmb_user_name? ServiceLogic is the central block of my service, accessing for example the database.
As a second thing, I have a listbox to show me some devices. I tried to approach the datasource differently to show what else I have tried:
<ListBox Height="100" HorizontalAlignment="Left" Margin="6,44,0,0"
Name="listBox_detected" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Path=ServiceLogic.TheDevicesList}" DisplayMemberPath="name" />
Use XAML for that:
<ComboBox ItemsSource="{Binding MyServiceLogic.Users}"
SelectedItem="{Binding User}"
DisplayMemberPath="name" />
Create a property ServiceLogic in your ViewModel to hold a ServiceLogic object:
private ServiceLogic myServiceLogic;
public ServiceLogic MyServiceLogic
{
get { return myServiceLogic; }
set
{
myServiceLogic = value;
RaisePropertyChanged("MyServiceLogic");
}
}
I assume Users is ObservableCollection. Or you can create a property which holds Users collection directly.

How can I put items in an XAML combobox/listbox using Ironpython code?

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)

Update text in adorner on button click

I have created my custom adorner to cover my main window with a gray canvas alongwith a textblock at center to show some status text while i was working on other window.
What i am currently doing is fetching the required adornerElement(ie Canvas with a textblock) from my resources and passing it to an adorner in my view constructor like this -
ResourceDictionary reportResourceDictionary = App.LoadComponent(new Uri("Resources/ReportResources.xaml", UriKind.Relative)) as ResourceDictionary;
UIElement adornerElement = reportResourceDictionary["RefreshingReportAdorner"] as UIElement;
mainWindowBlockMessageAdorner = new MainWindowBlockMessageAdorner(mainPanel, adornerElement);
But i want to update that text in textblock in some scenarios say if i click on some button in other window but how to update the text dynamically??
Adorner element from Resource file-
<Grid x:Key="RefreshingReportAdorner">
<Rectangle Fill="Gray"
StrokeThickness="1"
Stroke="Gray"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
<Border BorderBrush="Black"
BorderThickness="2"
Background="White"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock i18n:LanguageManager.VisualId="6"
Text="Some Text(Update dynamically)"
Padding="15,10,15,10"/>
</Border>
</Grid>
Let me know if additional code or approach required..
Have you tried to create some model and push it to RefreshingReportAdorner element's DataContext?
Code:
var reportResourceDictionary = App.LoadComponent(new Uri("Resources/ReportResources.xaml", UriKind.Relative)) as ResourceDictionary;
var adornerElement = reportResourceDictionary["RefreshingReportAdorner"] as FrameworkElement;
var model = new Model();
model.MyText = "Initial text";
adornerElement.DataContext = model;
mainWindowBlockMessageAdorner = new MainWindowBlockMessageAdorner(mainPanel, adornerElement);
...
model.MyText = "Text after click";
XAML:
<TextBlock i18n:LanguageManager.VisualId="6"
Text="{Binding MyText}"
Padding="15,10,15,10"/>
Model:
public class Item : INotifyPropertyChanged
{
private string _myText;
public string MyText
{
get
{
return this._myText;
}
set
{
this._myText= value;
this.OnPropertyChanged("MyText");
}
}
}

Resources