Silverlight InlineCollection.Add(InlineUIContainer) missing? - silverlight

I'm having difficulty adding the inline of specific type InlineUIContainer into the InlineCollection (Content property) of a TextBlock. It appears the .Add() method of InlineCollection doesn't accept this type, however you can clearly set it through XAML without explicitly marking the content as a InlineContainer, as demonstrated in many examples:
http://msdn.microsoft.com/en-us/library/system.windows.documents.inlineuicontainer.aspx
Is it possible to programatically add one of these as in the following?
Target.Inlines.Add(new Run() { Text = "Test" });
Target.Inlines.Add(new InlineUIContainer() {
Child = new Image() { Source = new BitmapImage(new Uri("http://example.com/someimage.jpg")) } });
Target.Inlines.Add(new Run() { Text = "TestEnd" });
I have a feeling what's going on is that Silverlight is using a value converter to create the runs when specified in XAML as in the example which doesn't use InlineContainer, but I'm not sure where to look to find out.
The specific error I'm getting is as follows:
Cannot add value of type 'System.Windows.Documents.InlineUIContainer' to a 'InlineCollection' in a 'System.Windows.Controls.TextBlock'.

As pointed out by Jedidja, we need to use RichTextBox to do this in Silverlight.

You can't Add() Runs directly, but you can add Spans containing Runs.
Interestingly, you can also do this:
textBlock.Inlines.Clear();
textBlock.Inlines.Add(new Span());
textBlock.Inlines[0] = new Run();
Not that it's a good idea to hack around what the framework is actively trying to prevent you from doing.
P.S. If you can't figure out what XAML is doing, inspect the visual tree.

Related

Get Assembly where instance is declared in XAML

I have a framework.dll, customerFramework.dll and customer.exe.
Inside of the framework.dll is a customControl declared which can be placed in customerFramework.dll (in a XAML page/window) or in customer.exe (in a XAML page/window).
The customControl got a public DependencyProperty of type Uri. Visual Studio supports IntelliSense for its resources, so it is very easy to set these properties.
During runtime, the CustomControl tries to resolve the resources inside of framework.dll, but they are declared in:
customer.exe
To fix this issue, I have to set the following prefix: /customer;component/ballon.svg.
customerFramework.dll
To fix this issue, I have to set the following prefix: /customerFramework;component/ballon.svg.
But if I do so, I don't have any IntelliSense. So I would like to combine the right uri by adding the prefix in code behind.
What I want to know is the assembly name inside of the customControl, where the customControl has been placed.
If the customControl is placed in customerFramework.dll and I use the Assembly.() methods, I get the wrong informations (expected value: customerFramework):
GetEntryAssembly(): customer.exe
GetCallingAssembly(): framework.dll
GetExecutingAssembly(): framework.dll
Is there a hidden function to get this information?
sorry man i misunderstood the question .
please use reflection with stacktrace
var currentAssembly = Assembly.GetExecutingAssembly();
var callerAssemblies = new StackTrace().GetFrames()
.Select(x => x.GetMethod().ReflectedType.Assembly).Distinct()
.Where(x => x.GetReferencedAssemblies().Any(y => y.FullName == currentAssembly.FullName));
var initialAssembly = callerAssemblies.Last();
Code will be slow because it use reflection . good luck.

Change ItemList in a ComboBox depending from another ComboBox choice

first I must apologize because english isn't my mother language, but I'll try to be clear in what I'm asking.
I have a set of rows in a tableview, every row has diferent comboboxs per columns. So, the interaction between combobox must be per row. If in the Combobox A1, I select Item 1, in the Combobox A2 the itemlist will be updated.
My problem is that every combobox A2, B2, C2, etc. Is being updated according the choice in A1... same thing with B1,C1 combobox.
I need to updated just the A2, according to A1. B2 according to B1, etc.
I set the comboboxes by cellfactory, because I have to save the data from behind in a serializable object.
Hope is clear.
Regards.
This is pretty much a pain...
From a TableCell, you can observe the TableRow via it's tableRowProperty().
From the TableRow, you can observe the item in the row, via the table row's itemProperty().
And of course, from the item in the row, you can observe any properties defined in your model class, and update a list of items in the combo box accordingly.
The painful part is that any of these value can, and will at some point change. So the things you need to observe keep changing, and you have to manage adding and removing listeners as this happens.
The Bindings.select method is supposed to help manage things like this, but as of JavaFX 8, it prints huge stack traces to the output as warnings whenever it encounters a null value, which it does frequently. So I recommend doing you own listener management until that is fixed. (For some reason, the JavaFX team doesn't seem to consider this a big deal, even though encountering null values in the path defined in a Bindings.select is explicitly supported in the API docs.)
Just to make it slightly more unpleasant, the getTableRow() method in TableCell<S,T> returns a TableRow, instead of the more obvious TableRow<S>. (There may be a reason for this I can't see, but, well...). So your code is additionally littered with casts.
I created an example that works: apologies for it being based on US geography, but I had much of the example already written. I really hope I'm missing something and that there are easier ways to do this: please feel free to suggest something if anyone has better ideas.
On last note: the EasyBind library may provide a simpler way to bind to the properties along an arbitrary path.
As #James_D's example no longer runs due to link rot, and I was dealing with this same issue, here's how I figured out to create this effect.
View the full test case here.
I extend the builtin ComboBoxTableCell<S, T> to expose necessary fields. The custom TableCell has a Supplier<S> tableValue = (S) this.getTableRow().getItem(); used to access the applicable Data object. Additionally, I reflectively retrieve and store a reference to the cell's ComboBox. Because it is lazily instantiated in the superclass, I also have to set it via reflection before I can get it. Finally, I have to initialize the ComboBox as well, as it would be in javafx.scene.control.cell.CellUtils.createComboBox, since I'm manually creating it. It is important to expose these, as:
In the column's CellFactory, we finish initializing the ComboBoxCell. We just need to create a new instance of our custom ComboBoxTableCell and then when the comboBox is shown for the first time (e.g. we can be sure that we have a Data object associated with the cell), we bind the ComboBox#itemsProperty to a Bindings.When returning the proper ObservableList for the case.
CellFactory:
column1.setCellFactory(c -> {
TransparentComboBoxTableCell<Data, Enum> tcbtc = new TransparentComboBoxTableCell<>();
tcbtc.comboBox.setOnShown(e -> {
if (!tcbtc.comboBox.itemsProperty().isBound()) tcbtc.comboBox.itemsProperty().bind(
Bindings.when(tcbtc.tableValue.get().base.isEqualTo(BASE.EVEN)).then(evens).otherwise(
Bindings.when(tcbtc.tableValue.get().base.isEqualTo(BASE.ODD)).then(odds).otherwise(
FXCollections.emptyObservableList()
))
);
});
return tcbtc;
});
custom ComboBoxTableCell:
public static class TransparentComboBoxTableCell<S, T> extends ComboBoxTableCell<S, T> {
public TransparentComboBoxTableCell() {
this(FXCollections.observableArrayList());
}
public TransparentComboBoxTableCell(ObservableList<T> startingItems) {
super(startingItems);
try {
Field f = ComboBoxTableCell.class.getDeclaredField("comboBox");
f.setAccessible(true);
f.set(this, new ComboBox<>());
comboBox = (ComboBox<T>) f.get(this);
// Setup out of javafx.scene.control.cell.CellUtils.createComboBox
// comboBox.converterProperty().bind(converter);
comboBox.setMaxWidth(Double.MAX_VALUE);
comboBox.getSelectionModel().selectedItemProperty().addListener((ov, oldValue, newValue) -> {
if (this.isEditing()) {
this.commitEdit((T) newValue);
}
});
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
throw new Error("Error extracting 'comboBox' from ComboBoxTableCell", ex);
}
tableValue = () -> (S) this.getTableRow().getItem();
}
public final ComboBox<T> comboBox;
public final Supplier<S> tableValue;
}

How to detect the sender(button) of dynamical created bindings

I create some RibbonButtons dynamically and add them to a group according to an xml file. The follwoing function is carried out as often as entries found in the xml file.
private void ExtAppsWalk(ExternalAppsXml p, AppsWalkEventArgs args)
{
RibbonButton rBtn = new RibbonButton();
rBtn.Name = args.Name;
Binding cmdBinding = new Binding("ExtAppCommand");
rBtn.SetBinding(RibbonButton.CommandProperty, cmdBinding);
Binding tagBinding = new Binding("UrlTag");
tagBinding.Mode = BindingMode.OneWayToSource;
rBtn.SetBinding(RibbonButton.TagProperty, tagBinding);
rBtn.Label = args.Haed;
rBtn.Tag = args.Url;
rBtn.Margin = new Thickness(15, 0, 0, 0);
MyHost.ribGrpExtern.Items.Add(rBtn);
}
I tried to use the Tag property to store the Url's to be started when the respective button is clicked. Unfortunately the binding to the Tag property gives me the last inserted Url only.
What would be the best way to figure out which button is hit or to update the Tag property.
The datacontext is by default the context of the Viewmodel. The RibbonGroup to which the Buttons are added is created in the xaml file at designtime. I use that construct:
MyHost.ribGrpExtern.Items.Add(rBtn);
to add the buttons. It maight not really be conform with the mvvm pattern. May be someone else has a better idea to carry that out.
I foud a solution for my problem here and use the RelayCommand class. So I can pass objects (my Url) to the CommandHandler.
RibbonButton rBtn = new RibbonButton();
rBtn.Name = args.Name;
Binding cmdBinding = new Binding("ExtAppCommand");
rBtn.SetBinding(RibbonButton.CommandProperty, cmdBinding);
rBtn.CommandParameter = (object)args.Url;
private void ExtAppFuncExecute(object parameter)
{
if (parameter.ToString().....//myUrl

Making Silverlight 2 programs work in Silverlight 4

I am trying to make Jeff's testing program, written in Silverlight 2 (http://www.jeff.wilcox.name/2008/03/silverlight2-unit-testing/), work using Silverlight 4 and VS2010 and I get a NullReferenceException at this line:
chatSession.ConnectWithRemoteUser("ScottGu");
Any ideas why? Here's code:
public Page()
{
// commented out because it doesn't exist in the current context
// according to the compiler
// InitializeComponent();
// Retrieve ChatSession instance from XAML resource declaration
chatSession = new ChatSession();
chatSession = (ChatSession)Resources["ChatSessionDS"];
// Connect with Chat Server to chat with "ScottGu"
chatSession.ConnectWithRemoteUser("ScottGu");
}
First, if you had to comment out InitializeComponent(), I Feel bad about your application: InitializeComponent is generated by the VS tools when the XAML file of your page is parsed.
If it doesn't exist, it probably means that the class declared in the xaml file is different from the one in your c# file (different name or different namespace) Otherwise, maybe the XAML file action type in the VS property tab isn't set to "page".
second:
chatSession = new ChatSession();
chatSession = (ChatSession)Resources["ChatSessionDS"];
this looks strange.you create a new ChatSession, then replace it by an object saved in the page resources. Why do you create it firstplace if you put the instance out of scope at the next line?

Embedded IronPython scripts and converting types

I've got a WPF application that embeds IronPython to use as a scripting language. I've got an object model that IronPython scripts can use to do 'stuff'.
However I've come across a strange problem that I've solved in a way that I don't believe is correct.
In my script I want to type the following to set the location of an object in WPF.
map.CanvasLocation = 10,10
This comes up with an exception saying that it cannot convert from PythonTuple to System.Windows.Point.
I've currently solved that using a custom type converter in my c# object, but I'm not sure if this is the best way to do it.
Is there a way to tell IronPython or .Net in general how to convert from one type to another that can be extended at run time?
The way I do this is to use TypeDescriptor to add a type converter attribute to PythonTuple at runtime.
TypeDescriptor.AddAttributes(typeof(PythonTuple),
new TypeConverterAttribute(typeof(Converter)));
Then I use the following code to find the converter in the attribute setter (SetMemberAfter method)
var converter = TypeDescriptor.GetConverter(value);
if (converter.CanConvertTo(destinationType))
{
var destinationValue = converter.ConvertTo(value, destinationType);
return destinationValue;
}
else
{
throw new InvalidOperationException("Cannot convert from {0} to {1}".UIFormat(
value == null ? "null" : value.GetType().Name, destinationType.Name));
}
Why not do a
map.CanvasLocation = Point(10,10)

Resources