I'm new to the world of WP7 and .net programming for that matter and i need help. I have a custom component that has a property that uses template binding.
<TextBlock Text="{TemplateBinding Info}" FontSize="20" Grid.Row="1" TextWrapping="{TemplateBinding TextWrap}"/>
I defined the dependency properties in the .cs file.
Now in my page.xaml i placed the custom component like so,
<rounded:RoundedImageView x:Name="pivotItem1" Info="Test bind" BorderBrush="White" ImageSrc="Images/default_service.png" TextWrap="Wrap"/>
Which works ok, now I want the Info and TextWrap properties to be changed dynamically based on some external variables so I did this
<rounded:RoundedImageView x:Name="pivotItem1" Info="{Binding sopInfo}" BorderBrush="White" ImageSrc="Images/default_service.png" TextWrap="{Binding wrap}"/>
where sopInfo and wrap are the external variables defined in the backing cs file of the page. But this doesn't work, the Info and TextWrap values do not change. How can i achieve it?
Thanks
Try to set the DataContext of your Page like this:
<phone:PhoneApplicationPage
DataContext="{Binding RelativeSource={RelativeSource Self}}" />
Then make sure that sopInfo and wrap are public DependancyProperties of your Page class.
public static readonly DependencyProperty sopInfoProperty =
DependencyProperty.Register(
"sopInfo", typeof(String),
);
public string sopInfo
{
get { return (string)GetValue(sopInfoProperty); }
set { SetValue(sopInfoProperty, value); }
}
Related
My problem is that I'm referencing a static resource, primary (as a color) in my MainPage, but when I have MainPage in the constructor of App() for Dependency Injection, primary isn't defined yet because its reference is loaded from App.xaml.
public partial class App : Application
{
//MainPage gets loaded first with a reference to
//StaticResource Primary which doesn't exist yet.
//An exception is thrown in mp.InitializeComponent()
//complaining about StaticResource Primary not existing
public App(MainPage mp, MainPageViewModel vm)
{
//StaticResource Primary is defined in here
InitializeComponent();
MainPage = mp;
MainPage.BindingContext= vm;
}
}
I can work around this by doing the following:
Adding Colors (and Styles) to the ResourceDictionary of MainPage:
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ContentPage.Resources>
But then I also have to add a ResourceDictionary in Styles.xaml referencing Colors.xaml:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Colors.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
This approach is fine for a small app, but I have many view pages utilizing Colors.xaml in the app I'm developing. Is there any way I can globally reference Colors.xaml and Styles.xaml in MauiProgram.cs? (So they're registered before DI takes place with MainPage)
You don't need to reference colors. What you actually ask is:
"How to resolve services with dependency injection".
You can add to any class IServiceProvider, and "ask" for a service to be provided to you. When you "ask" for your View, it will cascade (or to use your term: dominos down the line) and call the required constructors for ViewModel. And if your ViewModel uses something like ISettings, It will call the constructor of your MySettings class that implements the interface and so on.
The whole idea of using DI is to let it do this work for you.
You should not pass pages, in the constructor of you Application class. Why? Because when you construct it, LoadFromXaml is not called yet. But nothing is stopping you from having IServiceProvider in your constructor. And request services after Initialization is done.
This is good theory: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0
This is good example: https://stackoverflow.com/a/32461714/6643940
Lets say I have a main component that I want to initialize in a specific way and I have it's constructor take an Interface for this purpose. Is there a way to define the implementation I want for this interface in my xml and in turn inject that into the main component as a parameter? Like this:
public interface IComponent2 {
void DoStuff();
}
public class ConcreteCompImpl2 : IComponent2 {
IComponent1 _comp;
public ConcreteCompImpl2(IComponent1 comp) {
_comp = comp;
}
public void DoStuff(){
//do stuff
}
}
<component id="component1" service="ABC.IComponent1, ABC" type="ABC.ConcreteCompImpl1, ABC" />
<component id="component2" service="ABC.IComponent2, ABC" type="ABC.ConcreteCompImpl2, ABC" >
<parameters>
<component1>???</component1>
</parameters>
</component>
Or am I thinking about this all wrong and there is a much simpler way to accomplish this? The main thing I want to be able to do is configure what 'kind' of IComponent1 will get injected whenever an IComponent2 is created. Thanks
If you have only one concrete class implementing IComponent1, then it will automatically be injected when you resolve IComponent2.
If you have several classes implementing IComponent1 and want a specific one every time IComponent2 is resolved, you need to specific an inline dependency:
container.Register(
Component.For<IComponent2>()
.ImplementedBy<Component2>()
.DependsOn(Dependency.OnComponent<IComponent1, YourSpecialComponent1>())
);
I'm not completely sure you can specify this in the XML configuration, but honestly you should use the Fluent API instead of the XML configuration unless you have a really compelling reason to use it. As mentioned in the above link:
Ability to register components in XML is mostly a leftover from early days of Windsor before Fluent Registration API was created. It is much less powerful than registration in code and many tasks can be only accomplished from code.
I'm translating a web application and things are generally going smoothly with wicket:message and properties files. But Wicket always wants to have a component for looking up strings.
How can I translate converters and renderers (i.e. implementations of IConverter and IChoiceRenderer) which don't have access to any Wicket component in their methods?
So far I found one way - Application.get().getResourceSettings().getLocalizer().getString(key, null) - but I have to make the strings "global", i.e. associated with the application class. That's not nice for separation and reuse. How can I do it better?
I think you should invent you own way how to achieve this. Here in my current project we registered our own IStringResourceLoader like this:
IStringResourceLoader stringResourceLoader = new OurOwnResourceLoaderImpl();
Application.get().getResourceSettings().getStringResourceLoaders().add(stringResourceLoader);
Then for example in IChoiceRenderer we just call Application.get().getLocalizer().getString("key", null).
Inside our IStringResourceLoader we are looking for bundles (property files) with some string pattern according our own conventions.
Or you can just register localization bundle (ie. properties file) distributed inside your library's jar in Application#init through org.apache.wicket.resource.loader.BundleStringResourceLoader.
Afaik there is no standard way to do that so it's up to you what path you choose.
Updated:
I found another solution how your library/extension can register it's own localization by itself so you needn't to touch Application#init or create your own IStringResourceLoaders.
There is preregistered string resource loader org.apache.wicket.resource.loader.InitializerStringResourceLoader (see wickets default IResourceSetting implementation ie. ResourceSetting and it's constructor) which uses wicket's Initializer mechanism - see IInitializer javadoc - basically you add wicket.properties file in your jar class root (ie. it is in default/none package) and inside file there is:
initializer=i.am.robot.MyInitilizer
then i.am.robot.MyInitilizer:
public class MyInitializer implements IInitializer {
/**
* #param application
* The application loading the component
*/
void init(Application application) {
// do whatever want
}
/**
* #param application
* The application loading the component
*/
void destroy(Application application) {
}
}
and now you create your localization bundles in same package and same name as IInitializer implementation (in our example MyInitializer)
I think I found another way...
I noticed that IStringResourceLoader also has a method String loadStringResource(Class<?> clazz, String key, Locale locale, String style); (and one more parameter for variation in newer Wicket versions) which does not require a component. clazz is supposed to be a component class, but... it doesn't actually have to be :)
I was able to implement my own class MyLocalizer extends Localizer with a new method
getString(String key, Class<?> cl, IModel<?> model, Locale locale, String defaultValue)
which works in a similar way to
getString(String key, Component component, IModel<?> model, String defaultValue)
but uses the class directly instead of a component. It still uses the same properties cache and resource loaders.
Then I wrote an abstract class MyConverter implements IConverter which has a MyLocalizer getLocalizer() and a few getString methods like the Component class. Basically it does getLocalizer().getString(key, getClass(), model, locale, defaultValue), so the properties can now be attached to the converter class.
Seems to work :)
If I understand your question...
You can use package based properties that means if you put your keys/values into a property file 'package.properties' in a package. Each localized resource of any subpackage under that package returns the value associated to the requested key until you override it in another property file.
The file name is 'package.properties' in Wicket prior to 1.6.x and 'wicket-package.properties' in Wicket 1.6+
See
https://cwiki.apache.org/confluence/display/WICKET/Migration+to+Wicket+6.0#MigrationtoWicket6.0-package.propertiesrenamedtowicket-package.properties
However it works just for componet, outside the componet (when component argument is null), it is possible to use:
WicketApplication.properties (the WebApplication class is WicketApplication.class, this property file is in the same package).
applicationGlobalProperty=My Global Localized Property
wicket-package.properties (package based, place it in the same package as the page)
localText=Localized text: A local component text based on wicket-package.properties
LocalizedPage.html (markup template)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Localized Page</title>
</head>
<body xmlns:wicket="http://wicket.apache.org">
<div>
<div>
<h2>Texts</h2>
<div>
<wicket:message key="localText"/> <br/>
<span wicket:id="localizedLabel"></span>
</div>
</div>
</div>
</body>
</html>
LocalizePage.java (code)
public class LocalizedPage extends WebPage {
private static final long serialVersionUID = 1L;
public LocalizedPage() {
super();
}
#Override
protected void onInitialize() {
super.onInitialize();
add(new Label("localizedLabel", new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
#Override
public String getObject() {
return WicketApplication.get().getResourceSettings().getLocalizer().getString("applicationGlobalProperty", null);
}
}));
}
}
See the full example on https://repo.twinstone.org/projects/WISTF/repos/wicket-examples-6.x/browse
I have custom classes that I currently instantiate within App.xaml as resources. I want to move these custom objects into a Merged ResourceDictionary, where they are used within styles, and keep them close to where they are used.
Here's an example of what I want, arbitrarily using fake converter objects, but they could be any custom object...
App.xaml (namespace declarations ommitted):
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Merged.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="SomeStyle" TargetType="SomeControl">
...
</Style>
...
</ResourceDictionary>
And then in Merged.xaml (namespace declarations omitted):
<ResourceDictionary>
<cvt:VisibilityToBoolConverter x:Key="BoolToVisibility" Inverted="True"/>
<cvt:VisibilityToBoolConverter x:Key="NotBoolToVisibility" Inverted="True" Not="True"/>
<Style x:Key="SomethingThatUsesVisibilityToBoolConvertersStyle" TargetType="SomeOtherControl">
....
</Style>
</ResourceDictionary>
The issue I'm seeing is this: when I create the BoolToVisibility and NotBoolToVisibility objects (as well instantiating other objects that are instances of custom classes I have created) just as part Application.Resources, they are created and all the references work as expected; however, when I move these into a Merged Resource Dictionary (as I have in the sample above), I get a malformed Application exception when the Silverlight application loads.
I belive this to be an issue with how objects are instantiated differently in Merged Resource Dictionaries (I belive it is more of a lazy-load approach), but I would expect it to work nonetheless.
I am very much able to add Style objects, DataTemplates, ControlTemplates, and the like. But when I want to create instances of custom classes that are named or keyed using Xaml, it works great inside of App.xaml's Application.Resources directly and Application.Resources/ResourceDictionary as well. As soon as they are moved into a merged dictionary, it throws the exception. Is this by design? Any other ideas that work? Thanks in advance...
I have FINALLY worked around this. I took a page out of how the App class gets instantiated and did the same with the Merged.xaml file. I created a class with "code-behind" for Merged.xaml, called Merged that inherits from ResourceDictionary. I then (borrowing from App.g.cs), I initialize the component by loading from the Merged.xaml file during construction.
Merged.xaml.cs:
public partial class Merged : ResourceDictionary
{
private bool _contentLoaded;
public Merged()
{
InitializeComponent();
}
public void InitializeComponent()
{
if (_contentLoaded)
{
return;
}
_contentLoaded = true;
System.Windows.Application.LoadComponent(this, new System.Uri("/MySilverlightApp;component/Merged.xaml", System.UriKind.Relative));
}
}
The Merged.xaml file looks exactly the same as in my original question, using ResourceDictionary as it's root element.
The App.xaml is SLIGHTLY different. Instead of referencing the Merged ResourceDictionary by using the ResourceDictionary element and the Source attribute, I simply referenced the Merged class:
<Application.Resources
xmlns:msa="clr-namespace:MySilverlightApplication">
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<msa:Merged />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="SomeStyle" TargetType="SomeControl">
...
</Style>
...
</ResourceDictionary>
</Application.Resources>
Viola! It works.
You can avoid the extra codebehind by setting the build action for your shared xaml to "Resource" and reference it as /AssemblyName;component/Shared.xaml. For a reason that mostly escapes me, referencing it in this way allows custom object instantiation to work properly.
I am attempting to create an AttachedProperty for a DataGridColumn within Silverlight 3.0 and I am having some issues.
Here is the AttachedProperty:
public class DataGridColumnHelper
{
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.RegisterAttached("Header", typeof(string), typeof(DataGridColumnHelper),
new PropertyMetadata(OnHeaderPropertyChanged));
private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
string header = GetHeader(d);
var dataGridColumn = d as DataGridColumn;
if (dataGridColumn == null)
{
return;
}
dataGridColumn.Header = GetHeader(dataGridColumn);
}
public static string GetHeader(DependencyObject obj)
{
return (string)obj.GetValue(HeaderProperty);
}
public static void SetHeader(DependencyObject obj, string value)
{
obj.SetValue(HeaderProperty, value);
}
}
As you can see it is really simple, I am trying to overcome the limitation that the Header Property in the DataGridColumn class cannot be bound.
This XAML works as expected...
<Controls:DataGridTextColumn Binding="{Binding OwnerName}"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
Behaviors:DataGridColumnHelper.Header="User Name"/>
However this XAML throws an error...(Specifically: {System.Windows.Markup.XamlParseException: AG_E_PARSER_PROPERTY_NOT_FOUND [Line: 224 Position: 112]
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
....})
<Controls:DataGridTextColumn Binding="{Binding OwnerName}"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
Behaviors:DataGridColumnHelper.Header="{Binding Resources.UserNameListViewHeading, Source={StaticResource Labels}}"/>
Just for experimentation I attached this property (with the binding syntax above) to a DataGrid and checked the DataGridColumnHelper.Header property in the OnHeaderPropertyChanged method and the value was correct (and an exception wasn't thrown)
It is my understanding that the object that the AttachedProperty is attached to must be a DependencyProperty. Looking through Reflector, DataGridColumn (from which DataGridTextColumn derives) derives from DependencyProperty.
Can somebody please shed some light on this? I am trying to Localize our application, and I am having trouble with the DataGrid. I am sure I can do this in code-behind, but I am trying to avoid that.
Chris, the problem is very simple, this won't work because the DataGridTextColumn is "detached" from the Visual Tree. Your DataGridTextColumn object is rooted in the Columns collection of the DataGrid - see the indirection. So even attached properties will not work as you expect. Now there is a way to make all this work using something I'm calling Attached Bindings, see:
http://www.orktane.com/Blog/post/2009/09/29/Introducing-nRouteToolkit-for-Silverlight-(Part-I).aspx
Just remember to attach the binding properties using something that is in the VisualTree (so the Grid holding the column would do just fine.)
Hope this helps.
Try using this, im assuming UserName is a property in your viewmodel
<Controls:DataGridTextColumn Binding="{Binding OwnerName}"
HeaderStyle="{StaticResource DataGridColumnHeaderStyle}"
Behaviors:DataGridColumnHelper.Header="{Binding UserName}"/>
I cant test your scenario so my post is just an idea. Might work, might not.