XAML GridLength resource with value bound to another resource - c#

Is it possible to define a GridLength as XAML resources in a ResourceDictionary setting the length value using another StaticResource?
What I'm trying to achieve is something like this:
<System:Double x:Key="MyValue">8</System:Double>
<Thickness x:Key="MyThickness"
Bottom="{StaticResource MyValue}"
Left="{StaticResource MyValue}"
Right="{StaticResource MyValue}"
Top="{StaticResource MyValue}" />
<GridLength x:Key="MyGridLength">{StaticResource MyValue}</GridLength>
Is there a way to do it?
Thank you very much!

I think there is no way to do that exactly like you want to. If you pass any string inside - it will be passed to GridLengthConverter directly and not parsed (so StaticResource etc are ignored). If you will pass xml inside it will be interpreted as content, and GridLength does not support direct content.
So most reasonable option is just duplicate "8" and put MyGridLength near MyValue. Otherwise - move both to static properties (but there you will have only one field with value of 8, so no duplication) and reference via {x:Static}

Related

UWP- How would I go about referencing a variable string within a datatemplate?

To give a bit of context: In our application, we have a series of terms stored in a database. We internally reference our terms using some key, whereas our clients decide what text should show up in place of that. This has worked well for our web applications.
However for our UWP application, we have run into trouble in our DataTemplates. The way I understand it, data templates work like this:
<DataTemplate x:DataType="ObjectWithAllInformation">
<Element Property={x:Bind PropertyOnAboveObject} />
</DataTemplate>
The problem is that we're wanting to bind something that exists outside of the context of this specific object. We want to do something like this:
<DataTemplate x:DataType="ObjectWithAllInformation">
<Textblock Text="{Some sort of binding to a global terms object?}" />
<Element Property={x:Bind PropertyOnAboveObject} />
</DataTemplate>
Is there a way to instantiate such a global resource that we can reference within the data template this way? Something that just popped in my head that I haven't tried yet, is that a custom user control might work, but it seems overkill for accessing a string. Is there a simple way to achieve this?
You could use the localization mechanism as presented in this quick-start
In summary, you would create a resources file (.resw) in a known folders inside your solution "Strings/culture-code" - where culture-code is the language of your resources. You define the strings there and then reference them via the x:Uid property on your textblock
<DataTemplate x:DataType="ObjectWithAllInformation">
<Textblock x:Uid="resource1" />
<Element Property={x:Bind PropertyOnAboveObject} />
</DataTemplate>
and the corresponding resource file would have
resource1.Text: "whatever static text you need to define"
Notice that when you define the resource you are using the same value you used in the x:Uid field, and prefix it with the property that you need to set with that value, in your case "Text". You can use this mechanism to set values to other properties if needed, like Headers, PlaceholderText, etc...

How to bind resources properties in a DataTemplate

Hello all I have the following data template:
<DataTemplate DataType="Integer">
<StackPanel>
<xctk:IntegerUpDown Minimum="{Binding XPath=Min}"
Maximum="{Binding XPath=Max}"
Increment="{Binding XPath=Inc}"
ClipValueToMinMax="True"
AllowSpin="True">
<xctk:IntegerUpDown.Resources>
<converters:Parameter x:Key="IntegerParameter"
CurrentDevice="{Binding ElementName=Dock, Path=DataContext.CurrentDevice}"
ParameterName="{Binding RelativeSource={RelativeSource TemplatedParent}, XPath=#RegisterName}"
ParameterType="Integer">
</converters:Parameter>
</xctk:IntegerUpDown.Resources>
<xctk:IntegerUpDown.Value>
<Binding XPath="#Name"
Converter="{StaticResource IntegerDataConverter}"
ConverterParameter="{StaticResource IntegerParameter}"
Mode="TwoWay"/>
</xctk:IntegerUpDown.Value>
</xctk:IntegerUpDown>
</StackPanel>
</DataTemplate>
Aim of this data template is to call the converter to set the value of the IntegerUpDown control reading it from an external device.
Details on how to contact the device are stored in the converters:Parameter class (derived from dependency object). Two way means that the same mechanism should be used with ConvertBack to write the value to the device.
MultiBinding is not an option since the ConvertBack method could not be used to "create" all the parameters from a single integer value.
This template works almost as intended: I get an instance of the Parameter class for each item the data template is applied to.
Unfortunately the values for CurrentDevice (that should bind to the DataContext property CurrentDevice of the window named "Dock") and ParameterName (that should bind to an Xml attribute of the Xml Node the DataTemplate is applied to) are always null.
I'm sure the issue is in the way I try to bind the Parameter properties, but I'm not able to figure out the correct syntax. Any idea on how to get the result (I can't believe this can't be done... ).
Thanks for any help you can provide
As you may guess my idea was trying to find a workaround for the "you can't bind ConverterParameter" issue.
After further research on internet I found this post:
Bindable Converter Parameter
from this ntg123 guy. It actually solves my problem allowing to somehow bind the ConverterParameter to multiple sources using a syntax almost identical to the standard one.
It is based on a custom MarkupExtension and works really well in situations where Multibinding is not possible.

Josh Smith MVVM Demo app

In MainWindow we have:
<HeaderedContentControl
Content="{Binding Path=Workspaces}"
ContentTemplate="{StaticResource WorkspacesTemplate}"
Header="Workspaces"
Style="{StaticResource MainHCCStyle}"
/>
In the resources:
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource ClosableTabItemTemplate}"
Margin="4"
/>
</DataTemplate>
And in the article says:
A typed DataTemplate does not have an x:Key value assigned to it, but
it does have its DataType property set to an instance of the Type
class. If WPF tries to render one of your ViewModel objects, it will
check to see if the resource system has a typed DataTemplate in scope
whose DataType is the same as (or a base class of) the type of your
ViewModel object. If it finds one, it uses that template to render the
ViewModel object referenced by the tab item's Content property.
My question is:
How does the template know that the type is a collection of workspaces (WorkspaceViewModel)?
It doesn't need to, in the code you've posted. In your sample, you have given a strict value to your content template: you've explicitly used {StaticResource WorkspacesTemplate}, and so a resource with the key of "WorkspacesTemplate is looked up.
Because you've explicitly set the template, it doesn't matter what the intended type is: it'll try to display any object in your Content using the template you've set - with varying degrees of success if you use a type that doesn't match!
In the alternate method you mention - with a "typed DataTemplate", you would declare your datatemplate with <DataTemplate DataType="{x:Type l:WorkSpace}" />. Note that there is no x:Key (and also that I've assumed you have a namespace l mapped to your local code). What happens here is that WPF automatically sets the key of your resource to the DataType (important to note: a resource key doesn't have to be a string!).
Then, when you declare your HeaderedContentControl, you can leave out setting the ContentTemplate. At runtime, when the control is rendered, WPF will check the type of the Content object and find that it is WorkSpace, and it'll then look up a resource with x:Key="{x:Type l:WorkSpace}" - which will match your typed template.
This is a useful way of making consistent representations of data throughout your application, since a typed DataTemplate will be used automatically by any content-presenting control throughout your application.
WPF doesn't really care about the concrete type, it's just need to be some IEnumerable of something, WPF uses the type descriptor to know what the ui binding with.

XAML globalization using resources in combobox

I am globalizing my WinRT app and I can't use language resources in my comboboxs. I can use it in my TextBlocks using Text property but not using x:string. What am I doing wrong?
TextBlock x:Uid="Priority" Text="Default"></TextBlock>
<ComboBox>
<x:String x:Uid="Color">Default1</x:String>
<x:String x:Uid="Color.Text">Default2</x:String>
</ComboBox>
EDIT
Why can't I populate ComboBox elements with resource strings in XAML code? I know that I can add TextBlock elements inside ComboBox to use dictionaries or, as I am doing now, load them through code but this is not the response to my question.
As far as I know when you use in xaml that is a compile time constant which will not be able to change at runtime and bind to a resource. That is why you probably see Default1 or Default2 as items in your combobox.
I was able to find a solution to your problem.
The idea is that in the combobox you should use ComboBoxItem and set the x:Uid to the value of the resource. But in the resource file, the actual name should be Name.Content, because ComboBoxItem has a ContentPresenter in it as default and not a TextBlock.
So this is the code that worked for me:
In the resource file I have:
Combo.Content ComboBox1
And in the Xaml I used:
<ComboBox>
<ComboBoxItem x:Uid="Combo" />
</ComboBox>
This will populate the ComboBox with an item "ComboBox1" (from the resource file).
I have not tested this to see if it works with resource files for different languages, but I see no reason why it should not work.
I would suspect (but haven't found specific statement in documentation), that the entries in resource.resw would need to be (dependency?) properties of the objects for the automatic resource binding to work. Strings don't have such properties; Default1 isn't a value for String.Content, for example.
Path of least resistance would be using TextBlock for you ComboBox elements. Alternatively, you could load the resource in code and assign it to the string that way.
Is there anything preventing you from using a binding for the ComboBox's ItemsSource? That way you could use a custom object that contains the information you need, as well as a DisplayName property, which can then get the correct resource string from the .resx file.
If that's not an option at all, I'm not sure right now what the solution would be to do the whole thing entirely in XAML.

Accessing inner controls of UserControl

I am building a custom UserControl which would allow me to place text inside a ProgressBar. The problem is, none of the ProgressBar's DependencyProperties get transferred over. Here is the XAML for my custom UserControl.
<UserControl
x:Class = "MyProgram.MyCustomProgressBar"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid>
<ProgressBar Name="uiProgressBar" />
<Label Name="uiLabel" />
</Grid>
</UserControl>
How can I access and set the Minimum, Maximum, Value, etc. from XAML when I start using this UseControl.
<local:MyCustomProgressBar x:Name="uiLoadTime" ??.uiProgressBar.Maximum="50" />
I am hoping I don't need to redefine a bunch of DependencyProperties in order to get this functionality.
The usual way is to use a DependencyProperty... it's not so bad once you got used to it really.
Use the "propdp" built in snippet in the code-behind of your usercontrol.
Let's take the ProgressBar.Maximum example:
Make an integer dependencyproperty with a default value of 100 (or whatever you like), name it InnerProgressBarMax.
In your UserControl's XAML, you bind it this way:
<ProgressBar Maximum="{Binding InnerProgressBarMax, ElementName=myUsrCtrl}" />
When you use the control in another part of your application, simply enter a value like this:
<local:MyCustomProgressBar x:Name="uiLoadTime" InnerProgressBarMax="50" />
Rinse & repeat for each property you want to expose.
Edit:
If you really need to have 50+ DP exposed, you could bring down the hastle by specifying smart default values for your DPs.
To do that, when you create a DP, set the parameter of new PropertyMetadata(YOUR_DEFAULT_VALUE)
Once that is done, your control may expose many DPs, but you'll only have to set a few manually in the XAML code that uses the control.
The alternative to wrapping everything in DependencyProperties is to let the UserControl's consumer provide the ProgressBar. It could look like this:
<local:MyCustomProgressBar x:Name="uiLoadTime">
<local:MyCustomProgressBar.ProgressBar>
<ProgressBar Maximum="50" />
</local:MyCustomProgressBar.ProgressBar>
</local:MyCustomProgressBar>
Then in MyCustomProgressBar.xaml.cs, you would expose a public property for a ProgressBar. In its setter, modify the properties however you see fit, then add it to the UserControl's root Grid.

Categories

Resources