Concatenate two string in XAML [duplicate] - xaml

I want to concatenate in my window title a property from my viewmodel and a value that cames from a resources file.
This is what I have working without the string from resources:
Title="Binding Path=Description, StringFormat=Building: {0}}"
Now I want to remove the "Building" string and put a value from a resource like I use on other places:
xmlns:res="clr-namespace:Project.View.Resources"
{res:Strings.TitleDescription}
How can I define both? Can I define like a {1} parameter?

I've seen the MultiBinding answer in several places now, and it is almost never necessary to use it. You can define your resource as the string format instead, and as long as there is only one string format argument, no MultiBinding is required. Makes the code a lot more succinct:
<TextBlock Text="{Binding Description, StringFormat={x:Static res:Strings.TitleDesc}}" />
And the TitleDesc resource is obviously "Building: {0}".

Yes, you can. Simply use a MultiBinding.
The MSDN article on StringFormat has an example.
In your case, the code would look something like this:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Source="{x:Static res:Strings.TitleDescription}"/>
<Binding Path="Description"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>

Related

.bind vs string interpolation in aurelia

In our code base we have a mixture of the following:
attribute="${something}", attribute="${something | converter}", etc.
attribute.bind="something", attribute.bind="something | converter"
I find the latter easier to read.
The examples I'm referring to are exactly like the above; i.e., they do not add any additional string content.
I think that it's easier on Aurelia too. Am I correct?
Also, for these specific cases where no actual interpolation is
involved, is there any benefit to the first form? (other than it is
two characters less to type.)
Given the examples you have shown, I would recommend using option 2. It really isn't "easier on Aurelia," but it is more explicit that you are binding the value of that attribute to the property listed.
Original Answer Below
The benefit of the first option is when you have, for example, an attribute that accepts many values but as a single string. The most common example of this is the class attribute. The class attribute accepts multiple classes in a space-separated list:
<div class="foo bar baz"></div>
Imagine we only want to add or remove the class baz from this list based on a prop on our VM someProp while leaving the other classes. To do this using the .bind syntax, we would have to create a property on our VM that has the full list but adds or removes baz as determined by the value of someProp. But using the string interpolated binding, this becomes much simpler:
<div class="foo bar ${someProp ? 'baz' : ''}"></div>
You can imagine how this could be extended with multiple classes being added or removed. You could maybe create a value converter to do this using the .bind syntax, but it might end up with something that wasn't as readable.
I could imagine a value converter being created that might look something like this in use:
<div class.bind="someProp | toggleClass:'baz':'foo':bar'"></div>
I really think this is much less readable than using the string interpolation syntax.
By the way, the value converter I imagined above would look like this:
export class ToggleClassValueConverter {
toView(value, toggledClass, ...otherProps) {
return `${otherProps.join(' ')} ${value ? toggledClass : ''}`;
}
}
The best part is that I'm still using string interpolation in the value converter :-)
After wading through the tabs I'd already opened I found this. Although it's not quite the same thing, and it's a bit old, there's a similar thing talked about on https://github.com/aurelia/templating-binding/issues/24#issuecomment-168112829 by Mr Danyow (emphasis mine)
yep, the symbol for binding behaviors is & (as opposed to | for value converters).
<input type="text" data-original="${name & oneTime}" value.bind="name" />
Here's the standard way to write a one-time binding. This will be a bit more light-weight in terms of parsing and binding:
<input type="text" data-original.one-time="name" value.bind="name" />
I don't know if it applies to the .bind/${name} case as well as the oneTime one in the example, but perhaps if it comes to his attention he can say either way.
Given this isn't a cut and dry answer, I'll be marking Ashley's as the answer as it confirms the legibility question and provides useful information on other use cases should anyone else search on similar terms.

Applying OGNL expression to a context variable

I'm currently working with Struts2 (inexperienced developer) and I've been searching but I couldn't find how to apply an OGNL expression to a variable stored in context.
The thing is that I need to retrieve a parameter from Context and uppercase it. By now, I've tried to do it this way but sadly with no luck:
<s:property value="#myVar.toUpperCase()" />
As this works with variables stored in the ValueStack (notation without #), I don't really understand why this won't work with anything stored in Context..
I'm able to print the #myVarcontent just fine if I don't append the .toUpperCase() to it.
Also tried this workaround but didn't help:
<s:property value="<s:property value="#myVar"/>.toUpperCase()"/>
So what's the thing I'm missing? How can I apply an OGNL expression to a variable stored in Context?
Your variable most probably isn't a String so there isn't toUpperCase() method in it. The solution is to call toString() before calling toUpperCase().
<s:property value="#myVar.toString().toUpperCase()" />
Update
Actually your problem is here <s:set var="myVar" value="%{#parameters.myVar}"/> since there could be more then one myVar in parameters it will return an array of Strings, so if you want just a single parameter change your expression to #parameters.myVar[0] and then toUpperCase() will work.
<s:set var="myVar" value="%{#parameters.myVar[0]}"/>
<s:property value="#myVar.toUpperCase()" />
OR
<s:set var="myVars" value="%{#parameters.myVar}"/>
<s:property value="#myVars[0].toUpperCase()" />

Is there any way to reference (in XAML) an assembly with spaces in its name?

Is it not possible to reference an assembly that has spaces in its name? Do I really have to rename my assemblies to not contain spaces? Is there no way to escape the spaces? I can't find very many instances of people who have this problem, let alone any solutions...
Example XAML:
<UserControl x:Class="SomeClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Some.Namespace;assembly=Some Assembly With Spaces In The Name"
>
And this is the error that the compiler gives you when you try to do this:
Unknown build error, ''clr-namespace:Some.Namespace;assembly=Some Assembly With Spaces In The Name' mapping URI is not valid. Line 4 Position 2.'
Putting ' or " around the assembly name doesn't help.
This solution seems to have fixed the issue for me with spaces in the assembly name.
This looks like the bug you're referring to, which is 'fixed'...
I've just had a similar problem with a ValueConverter in a separate assembly, and the way to get it to build was to include a default constructor in my ValueConverter class. Without that, VS won't build it if it's contained in an assembly with spaces in the name.
Unfortunately, it builds but then falls over with a XamlParseException when I actually run it up.
If I do the same referencing an assembly without spaces, everything is fine.
As an aside, you're defining the xmlns:local namespace but referencing a different assembly - if your namespace is indeed local you can just do:
<xmlns:local="clr-namespace:Some.Namespace"/>

MSBuild tasks can accept primitive arrays, but how do you write one to pass into the task?

I would guess it has to be an ITaskItem since it's a vector instead of scalar, I've got the only 2 MsBuild books here on my desk, and I can't find examples of how to pass in an array to a task. I want to do a string array, but I'd like to know the proper way that would work with any primitive type.
How do you pass in an array of string (or int) to a MsBuild task?
MSBuild tasks can accept ITaskItem, primitives, string or an array of any of those for parameters. You just declare the type in your task and then the values will be converted before passed to the task. If the value cannot convert to the type then an exception will be raised and the build will be stopped.
For example if you have a task which accepts an int[] named Values then you could do.
<Target Name="MyTarget">
<MyTask Values="1;45;657" />
<!-- or you can do -->
<ItemGroup>
<SomeValues Include="7;54;568;432;79" />
</ItemGroup>
<MyTask Values="#(SomeValues) />
</Target>
Both approaches are essentially the same. The other answers stating that all parameters are strings or that you have to use ITaskItem are incorrect.
You said you have two books on MSBuild, then I presume one is my Inside the Microsoft Build Engine book, you should read the chapter on Custom Tasks so that you get a full grasp on these topics. There is a section explaining parameter types specifically.
IIRC, msbuild items are always string arrays - that is the only option. So an array of integers would be stored as an array numeric strings.

web.config explanation of profile properties

I have a List<> as part of a users profile stroed in the web.config like so
<properties>
<clear/>
<add name="EditorUploads"
type="System.Collections.Generic.List`1[[System.String]]"/>
</properties>
Although this code works, I don't know why. I can't find any documentation on what the `1 means anywhere. Can anyone shed some light on this please? Thanks.
The ``1` is a different notation used for generic types.
The 1 indicates the number of generic type parameters.
I have seen this notation when writing stacktraces as strings as well. It seems to indicate the generic characters <> and the following type is the generic type, eg:
List<string>
To denote the number of Type parameters that follow.