WPF - Get text from static Dictionary Singleton - c#

I got the localization for my project in an external class library, because I want only one Lang.csv file for my translations.
For this I got a static instance Translator.TI with an indexer in the namespace TimeTracking.Lang and my WPF Application is in the namespace TimeTracking.View in the main project (so different projects, but same basic namespace).
namespace TimeTracking.Lang
{
public class Translator
{
public static readonly Translator TI = new Translator();
private readonly Dictionary<string, Translation> _translations;
public string this[string key]
{
get { ... }
}
...
}
}
Now I want to load my translations from this static singleton instance into the view.
<Window
...
xmlns:p="clr-namespace:TimeTracking.Lang;assembly=TimeTrackingShared"
Title="{x:Static p.Translator.TI[TimeTracking]}"
>
...
</Window>
Question: Is this possible and how? And if not: Could I do this by using a class property targeting the static singleton?

It is not possible to use indexer with {x:Static} extension. You could achieve this with Binding, for example:
Title="{Binding Source={x:Static p:Translator.TI}, Path='[TimeTracking]'}"
It is also a good idea to implement INotifyPropertyChanged interface in your Translator class to avoid binding memory leaks and to enable property change notifications.

Related

Custom class implementing interface IDictionary<type, type> that could be static?

This is a bit Software Engineering and C# question. It seems to me this question will end up all about what c# CAN do so I'll post it here first.
I have a project that has multiple classes that need to access the same dataset. I have created a custom class for that dataset that has a private Dictionary<byte[], MyCustomInterface> instance. The class implements IDictionary<byte[], MyCustomInterface>. For the methods and properties I just wrap the private dictionary methods and properties. I have then added some methods and properties of my own dedicated to my specific needs.
As I said I need access to the custom dictionary and it's data in many classes. I tried making my custom class static but can't because it implements interfaces.
I could make a database in the background but that would be a way heavyweight solution. I have done this before but it ends up being a lot of maintenance.
What other ways would be available to have access to the same set of data/same class from all my classes? I need to be able to serialize/deserialize this custom data set and save the data in a file for retrieval later. I'd prefer to not give up on using Interfaces, they're really handy.
public class EntityDictionary : IDictionary<byte[], IDispenseEntity>
{
private Dictionary<byte[], IDispenseEntity> _backing = new(new ByteArrayComparer());
public IDispenseEntity this[byte[] key]
{
get => _backing[key];
set => _backing[key] = value;
}
public ICollection<byte[]> Keys => _backing.Keys;
public ICollection<IDispenseEntity> Values => _backing.Values;
...
//My custom properties and methods
}
Singleton pattern?
public class EntityDictionary : IDictionary<byte[], IDispenseEntity>
{
private EntityDictionary() {}
static EntityDictionary() {}
private static _instance = new EntityDictionary();
public static Instance { get { return _instance; }}
...
}
So there is only one dictionary that's shared by all uses, you can;t create your own instance, and are forced to use the single instance.

How to define an constructor argument accessible from Xaml

Xamarin's ListView defines a 1-argument constructor as follows:
public ListView([Parameter("CachingStrategy")] ListViewCachingStrategy cachingStrategy)
As a result, CachingStrategy can be used in Xaml:
<ListView CachingStrategy="RecycleElement" .../>
I'm wondering how I can do the same thing. The following code, as is, does not compile because ParameterAttribute is internal to Xamarin.Forms:
public ItemListControl([Parameter("IsReadOnly")] bool isReadOnly)
I copied class ParameterAttribute from Xamarin.Forms, and the above compiled, but had no effect on Xaml processing. Here is the class, for reference:
[AttributeUsage(AttributeTargets.Parameter)]
internal sealed class ParameterAttribute : Attribute
{
public ParameterAttribute(string name)
{
Name = name;
}
public string Name { get; }
}
Is there anything I'm missing?
To make things simpler, I would recommend creating a BindableProperty for IsReadOnly. But you can always use x:Arguments to pass in parameters to constructor:
<local:ItemListControl ...>
<x:Arguments>
<x:Boolean>true</x:Boolean>
</x:Arguments>
</local:ItemListControl>
EDIT - 1
There is one hack that you can use - (I wouldn't recommend as this could change anytime with an update in XAMLC compilation) - but you can make sure to keep the namespace same as the one used internally while defining the parameter attribute.
namespace Xamarin.Forms
{
[AttributeUsage(AttributeTargets.Parameter)]
internal sealed class ParameterAttribute : Attribute
{
public ParameterAttribute(string name)
{
Name = name;
}
public string Name { get; }
}
}
And XAML usage would look like:
<local:ItemListControl IsReadOnly="true" .. />
EDIT - 2
This hack only seems to work if XAMLCompilation is applied to host control/page.

Static binding doesn't update when resource changes

I'd first like to say I'm very new to Binding.. I've done some things in WPF already but I never used binding because concept is a bit too hard to understand for me right of the bat. Even this what I'm doing now is something i managed to salvage from a tutorial that I didn't fully understand.
In my application I have a static class with static properties and there's a static method that changes those static properties.
Example:
public static class AppStyle
{
public static SolidColorBrush property = Brushes.Red;
public static void ChangeTheme()
{
property = Brushes.Blue;
}
}
Inside the XAML I have a control that has it's background binded to this value. I even declared the namespace properly.
...
xmlns:style="clr-namespace:CorrectNamespace;assembly=RightAssembly"
...
<TextBox x:Name="TXT_PN"
Background="{Binding Source={x:Static style:AppStyle.property}}"
TextChanged="TXT_PN_TextChanged"
Text="Text"/>
When the application loads it will load the correct setting (Red color) however when things change and ChangeTheme() is called, the static class will get the new value, however the textbox's Background will not change.
What am I doing wrong here? As I said, I'm very new to this and I would appreciate the solution in laymen's terms.
Thank you!
First of all, your property is actually not a property, but a field. A minimal property declaration would look like this:
public static SolidColorBrush Property { get; set; }
Please note the name is starting with an uppercase letter, which is a widely accepted coding convention in C#.
Because you also want to have a change notification fired whenever the value of the property changes, you need to declare a property-changed event (which for non-static properties is usually done by implementing the INotifyPropertyChanged interface).
For static properties there is a new mechanism in WPF 4.5 (or 4.0?), where you can write a static property changed event and property declaration like this:
public static class AppStyle
{
public static event PropertyChangedEventHandler StaticPropertyChanged;
private static void OnStaticPropertyChanged(string propertyName)
{
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
}
private static SolidColorBrush property = Brushes.Red; // backing field
public static SolidColorBrush Property
{
get { return property; }
set
{
property = value;
OnStaticPropertyChanged("Property");
}
}
public static void ChangeTheme()
{
Property = Brushes.Blue;
}
}
The binding to a static property would be written with the property path in parentheses:
Background="{Binding Path=(style:AppStyle.Property)}"
To implement reaction on a change, you need to notify about the change. See INotifyPropertyChanged interface. However, you can't use it with a static class. What about a singleton (ideally using some dependency injection container) instead of a static class?

Design Time Support with Event Aggregator AND WIndowManager

I have to create a WPF application with Caliburn.Micro 2.0.2 for my Bachelor exam.
In this application three different Views will be shown in a single Shell (Window) and they have to communicate with each other. So I need the Event Aggregator.
I also need the Window Manager to show additional dialogs.
My actual problem is that I have to bring all this together with full Design Time Support.
Unfortunately there is no example for that case.
The documentation of Caliburn.Micro says that a default constructor is needed in the view model, to provide design time support. However the Event Aggregator and the Window Manager are used as constructor parameters in the view model, so there is no default constructor at first.
The documentation also says that in such a case the ViewModelLocator should be used to get Design Time Support.
Unfortunately the section about the ViewModelLocator doesn't give me enough information about how to do that.
Another idea might be to chaining constructors like this:
public class ExampleViewModel : PropertyChangedBase
{
private readonly IEventAggregator eventAggregator;
private readonly IWindowManager windowManager;
public ExampleViewModel() : this(null)
{
}
public ExampleViewModel(IEventAggregator eventAggregator) : this(eventAggregator, null)
{
}
public ExampleViewModel(IEventAggregator eventAggregator, IWindowManager windowManager)
{
this.eventAggregator = eventAggregator;
this.windowManager = windowManager;
// doing everything needed for the Design Time Support
}
}
But I have no idea if that will work at last.
I hope somebody here can help me with this issue.
You can use a separate DataContext (ViewModel) for design time. You need to add in your XAML where the view model is used:
<UserControl
...
xmlns:dt="clr-namespace:YourProject.DesignTimeHelpers;assembly=YouAssembly"
d:DataContext="{Binding Source={x:Static dt:DesignTimeModels.ExampleViewModelForDesignTime}}">
There is the DesignTimeModels static class with the view model:
public static class DesignTimeModels
{
public static ExampleViewModel ExampleViewModelForDesignTime { get; set; }
// static constructor
static DesignTimeModels()
{
ExampleViewModelForDesignTime =
new ExampleViewModel(new EventAggregator(), new WindowManager());
}
}
The main idea is creating an instance of the view model by a static initializer with arguments what you need.
If you would like to use a IoC container (Caliburn for example) for instantination of the EventAggregator or the WindowManager, you can use a ServiceLocator pattern. For example:
// static constructor
static DesignTimeModels()
{
var eventAggregator = ServiceLocator.Get<IEventAggregator>();
var windowManager = ServiceLocator.Get<IWindowManager>();
ExampleViewModelForDesignTime =
new ExampleViewModel(eventAggregator , windowManager);
}

Adding static class into Application.Resources error

I am trying to add static class as a resources in Application.Resources
namespace MultiResImageChooser
{
public static class MultiResObjectInstance
{
private static MultiResPropertyChanged multiResObject = new MultiResPropertyChanged();
public static MultiResPropertyChanged current
{
get
{
return multiResObject;
}
}
}
}
Then in App.xaml I have
xmlns:static="clr-namespace:MultiResImageChooser"
....
<Application.Resources>
<static:MultiResObjectInstance x:Key="MultiResObjectInstance"/>
</Application.Resources>`
But in design view, VS2012 complains that The type MultiResObjectInstance is an abstract and must include an explicit value
How do I properly include static class in App.xaml as a resource?
Note sure giving a key for it because it is static.
You can't get an instance of a static class.
I think the problem is being static already. XAML tries to get an instance of the type and can't do it so thinks it is an abstract...

Categories