Why doesn't x:Static work in my WPF example? - wpf

[This is .Net 3.5.] I have seen a lot of examples that say, do it this way, so I must just be missing something:
I have a project with a Resources.resx file. In the Resources file are Strings that are Public. One of them is "Cancel", shown in this snippet from Resources.Designer.cs:
namespace WFT.PumpSvc.Bench.Properties {
public class Resources {
public static string Cancel {
get {
return ResourceManager.GetString("Cancel", resourceCulture);
}
}
...
Next, I have some xaml that has
xmlns:strings="clr-namespace:WFT.PumpSvc.Bench.Properties"
and
<wft:TouchButton Name="closeButton">"{x:Static strings:Resources.Cancel}"</wft:TouchButton>
(TouchButton inherits from Button.)
Instead of "Cancel" showing on my button, I see {x:Static strings:Resources.Cancel}. Is it obvious what I have missed that isn't finding the string?

You can't write a markup extension directly in an element (at least not in this form), it must be in an attribute:
<wft:TouchButton Name="closeButton" Content="{x:Static strings:Resources.Cancel}"></wft:TouchButton>
You can also write it like this:
<wft:TouchButton Name="closeButton">
<x:Static Member="strings:Resources.Cancel" />
</wft:TouchButton>

You made it a string, it won't be parsed like this, use element-syntax:
<wft:TouchButton Name="closeButton">
<x:Static Member="strings:Resources.Cancel"/>
</wft:TouchButton>

Related

Why Can't I Use My DbContext Type?

I'd like to access some static properties of my DbContext type in a WPF Window. I thought I could use the same XAML that I use to refer to individual entities:
<Window.Resources>
<entity:Account x:Key="account"/> //Works fine
<entity:MyEntities x:Key="myEntities"/> //Throws an error!
</Window.Resources>
I get this error:
No connection string named 'MyEntities' could be found in the application config file.
Why is it treating the DbContext type (MyEntities) differently than the Account entity? Is there an easy way I can access the static properties of my MyEntities type?
The syntax you used is for creating instances, not static properties. If you want to access a static property you need to use the x:Static markup extension
<Window.Resources>
<entity:Account x:Key="account" SomeProperty={x:Static entity:MyEntities.MyProperty}/>
</Window.Resources>
The above xaml would be similar to the C# code
var account = new Account()
{
SomeProperty = MyEntities.MyProperty
};
this.Resources["account"] = account;
See that you are calling new Account(), if you called new MyEntites() (like your original example did) you get the error you where getting.
It appears that particular error results due to the static constructor that I placed in my DbContext. When I remove the static constructor the error changes to:
Object reference not set to an instance of an object.
As it turns out, the original error doesn't prevent me from compiling or running my application. I changed my code to use Scott Chamberlain's suggestion (which produces a similar ignorable error) because it is much cleaner and I can access the static properties on the DbContext just fine in spite of Visual Studio's complaints. Thanks, everyone, for the help and suggestions.

Design Time - Dynamic

can i create a view at design time, using dynamic objects? (with visual studio 2010)
for example, or something, is that possible?
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dyn="clr-namespace:System.Dynamic;assembly=System.Core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
and
<d:DesignProperties.DataContext>
<dyn:ExpandoObject>
<dyn:ExpandoObject.Name>MyName</dyn:ExpandoObject.Name>
</dyn:ExpandoObject>
</d:DesignProperties.DataContext>
The above example does not work.
Sometimes I have class complicated to manage. And I can not use them at design time, the idea of using a dynamic type would be not to change the bindings (properties that I will use) and get a vision.
I do not know if I was clear, but if you have something that can help me would be great.
That should not work in any case, be it design or run-time.
You can use ExpandoObjects, but only via dictionary syntax:
<dyn:ExpandoObject>
<sys:String x:Key="Name">MyName</sys:String>
</dyn:ExpandoObject>
Though i do not know if that junk of a GUI designer is able to handle that, nor do i know if this works with compiled XAML.
Edit: As i thought you cannot compile this because some component fails:
Error 1 The Key attribute can only be used on a tag contained in a Dictionary (such as a ResourceDictionary).
Well, it is a bloody dictionary alright...
You can use a markup extension though, you can get the DictionaryFactoryExtension from this answer and modify it like this:
public override object ProvideValue(IServiceProvider serviceProvider)
{
var expando = (IDictionary<string,object>)new ExpandoObject();
foreach (DictionaryEntry kvp in Dictionary)
expando[(string)kvp.Key] = kvp.Value;
return expando;
}
//The designer uses this for whatever reason...
public object this[object key]
{
get { return this.Dictionary[key]; }
set { this.Dictionary[key] = value; }
}
Then you can use that just like an ExpandoObject:
<!-- Of course you can also hard-code the key-type in the class,
it should be a string in all cases when using an ExpandoObject anyway -->
<local:DictionaryFactory KeyType="sys:String" ValueType="sys:Object">
<sys:String x:Key="Name">MyName</sys:String>
</local:DictionaryFactory>
The designer should be able to handle this.

How to display application title in XAML text field

I have a Windows Phone page code that is shared by multiple applications.
At the top of the page, I show the title of the application, like so:
Is it possible to make the text be bound to the application title as defined in the application's assembly?
I realise that I could do this by code by reading the title in the assembly and then doing something like:
this.ApplicationTitle.Text = title;
I was hoping that the title as defined in the assembly could be accessed with some magic like:
Text={assembly title}" directly from within the xaml.
Thanks
Create a property called ApplicationTitle that returns that name of the application like the following, and then bind to it in XAML:
public string ApplicationTitle
{
get { return System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; }
}
(You can use a relative binding source if you can't or don't want to use the data context.)
edit:
I just realized that my method involved security considerations since GetName is a method that is [Security Critical]. And I got a MethodAccessException stating: Attempt to access the method failed: System.Reflection.Assembly.GetName()
So here's another way to get the assembly name and return it in a property by using the AssemblyTitle attribute.
public string ApplicationTitle
{
get
{
System.Reflection.AssemblyTitleAttribute ata =
System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(
typeof(System.Reflection.AssemblyTitleAttribute), false)[0] as System.Reflection.AssemblyTitleAttribute;
return ata.Title;
}
}
To bind in XAML, you can use this:
Text="{Binding ElementName=LayoutRoot, Path=Parent.ApplicationTitle}"

How to use Windows' Customized Region and Language settings in WPF

I am working in Namibia. Namibia is not an option on the Windows Region and Language settings, but share most cultural specifics with South Africa, so we select English South Africa and then customize the currency symbol to be "N$" (Namibian Dollars) and not "R" (South African Rand).
However, I can't convince WPF to use the customized currency. Using string.format("{0:c}", foo) in code works fine, but using {Binding Path=SomeCurrencyValue, StringFormat=c}` in XAML still uses the "R" symbol and not the custom "N$" symbol.
In App.xaml.cs I set the Application Culture with the following code:
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(System.Globalization.CultureInfo.CurrentCulture.LCID, true);
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement),
new FrameworkPropertyMetadata(
System.Windows.Markup.XmlLanguage.GetLanguage(
System.Globalization.CultureInfo.CurrentUICulture.IetfLanguageTag)));
As demonstration, here is some XAML code that shows the problem:
<StackPanel>
<TextBlock>
Formatted in XAML with: <LineBreak/>
Text="{Binding Path=SomeCurrencyValue, StringFormat=c}" <LineBreak/>
Result:
</TextBlock>
<TextBox Text="{Binding Path=SomeCurrencyValue, StringFormat=c, Mode=OneWay}"
Margin="5"/>
<TextBlock>
Formatted in code with: <LineBreak/>
return string.Format("{0:c}", SomeCurrencyValue); <LineBreak/>
Result:
</TextBlock>
<TextBox Text="{Binding Path=SomeCurrencyString, Mode=OneWay}"
Margin="5"/>
</StackPanel>
The DataContext for the above View contains the following:
public double SomeCurrencyValue
{
get { return 34.95; }
}
public string SomeCurrencyString
{
get
{
return string.Format("{0:c}", SomeCurrencyValue);
}
}
And the result looks like this:
I know there is a similiar question here, but I was hoping to get better answers with a more complete question. I am mostly working on financial applications for Namibian clients, so this is quite a serious issue for me - if there is no way to do this with .NET 4.0, I would consider filing a bug report, but I just wanted to check here first.
EDIT:
Just opened up the bounty on this question. I'm hoping for either a solution that isn't a rediculous workaround, or confirmation that this is a bug and should be filed as such.
One solution to this is to create this Namibian CultureInfo, so its fully recognized by all .NET layers. Here is a code that does it:
public static void RegisterNamibianCulture()
{
// reference the sysglobl.dll assembly for this
CultureAndRegionInfoBuilder namibianCulture = new CultureAndRegionInfoBuilder("en-NA", CultureAndRegionModifiers.None);
// inherit from an existing culture
namibianCulture.LoadDataFromCultureInfo(new CultureInfo("en-za"));
namibianCulture.CultureEnglishName = "Namibia";
namibianCulture.RegionEnglishName = "Namibia";
namibianCulture.CultureNativeName = "Namibia"; // you may want to change this
namibianCulture.RegionNativeName = "Namibia"; // you may want to change this
// see http://en.wikipedia.org/wiki/ISO_3166-1, use user-defined codes
namibianCulture.ThreeLetterISORegionName = "xna"; // I use x as 'extended' and 'na' as namibia
namibianCulture.TwoLetterISORegionName = "xn";
namibianCulture.ThreeLetterWindowsRegionName = namibianCulture.ThreeLetterISORegionName;
// see http://www.currency-iso.org/dl_iso_table_a1.xml
namibianCulture.ISOCurrencySymbol = "nad";
namibianCulture.CurrencyEnglishName = "Namibia Dollar";
namibianCulture.CurrencyNativeName = "Namibia Dollar"; // you may want to change this
// this is were you build something specific, like this symbol you need
namibianCulture.NumberFormat.CurrencySymbol = "N$";
// you'll need admin rights for this
namibianCulture.Register();
}
public static void UnregisterNamibianCulture()
{
CultureAndRegionInfoBuilder.Unregister("en-NA");
}
Once you have called the Register function once on a given machine (you will need to install this culture on end user machines), you can now use your initial WPF startup code, just change it like this:
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-NA");
And everything should work as expected. You can also use standard language tags and all that jazz, since en-NA is now recognized.
I had the same problem and I started from Simon's answer (thank you, Simon) making some modifications in order to get the user configuration (Region and Language in Control Panel) every time the application is launched, not the culture default.
My code look like this one
public MainWindow()
{
CreateAndRegisterLocalizedCulture();
this.Language = XmlLanguage.GetLanguage(customCultureName);
InitializeComponent();
DataContext = new ViewModel();
}
private void CreateAndRegisterLocalizedCulture()
{
CultureAndRegionInfoBuilder customCulture = new CultureAndRegionInfoBuilder(customCultureName, CultureAndRegionModifiers.None);
// Inherits from the current culture and region, may be configured by the user
customCulture.LoadDataFromCultureInfo(CultureInfo.CurrentCulture);
customCulture.LoadDataFromRegionInfo(RegionInfo.CurrentRegion);
// Not needed for the culture sake but...
customCulture.CultureEnglishName = CultureInfo.CurrentCulture.EnglishName + "-Customized";
customCulture.CultureNativeName = CultureInfo.CurrentCulture.NativeName + "-Customized";
// If the custom culture is already registered an unregistration is needed
// otherwise the following Register() call will generate an exception
if (CultureInfo.GetCultures(CultureTypes.UserCustomCulture).Where(ci => (ci.Name == customCulture)).Count() != 0)
{
// Admin rights are needed here
CultureAndRegionInfoBuilder.Unregister(customCulture);
}
// Admin rights are needed here
customCulture.Register();
}
It works fine to me but there are two problems in this approach:
In windows 7+ you need to start the application with Administrator rights as it will create a new culture file in C:\Windows\Globalization with the name you give to your custom culture
The Unregister method does not delete the above create file but it renames it as xyz.tmp0 and, with a logic I didn't get, time to time it creates more tmp file copies (xyz.tmp1, xyz.tmp2, ...). At least it is how it works in my pc.
Something that is not really a problem but a bit weird is that, once I change my regional settings in the control panel, I have to start my application twice before I see the modification. I can survive :)

cannot create an instance in xaml in silverlight 4.0

In the xaml code i get an error telling cannot create an instance of
this AllEmployeeViewModel class file, actually this class file exists in the solution folder when i type scr: the intellsene shows me the class file
<UserControl.Resources>
<scr:AllEmployeeViewModel x:Key="empName"></scr:AllEmployeeViewModel>
</UserControl.Resources>
<Grid x:Name="MainGrid" Background="White" Width="400"
Height="407" DataContext="{Binding Source={StaticResource empName}}" >
<Grid x:Name="grdAllEmp" DataContext="{Binding Path=EmployeeClass}">
<sdk:DataGrid AutoGenerateColumns="True" Height="274"
HorizontalAlignment="Left" Margin="8,8,0,0"
Name="dgEmployee" VerticalAlignment="Top" Width="385"
ItemsSource="{Binding}"/>
<Button Content="Get All Employees" Height="23"
HorizontalAlignment="Left" Margin="12,288,0,0"
Name="btnAllEmplloyees" VerticalAlignment="Top" Width="381"
Command="{Binding Path=DataContext.GetEmployees,ElementName=MainGrid}"/>
</Grid>
i am trying to bind the data to grid, if i ignore the compile time error and run its gives an error key not found.
please let me know the solutionif you know,working on this issue from past 2days
any help would be great
thanks.
I too had the same issue.
cannot create instance of viewmodel
Just copy this code and place it in ViewModel
public bool IsDesignTime
{
get
{
return (Application.Current == null) ||
(Application.Current.GetType() == typeof(Application));
}
}
//Constructor
public ViewModelClass()
{
if(IsDesignTime == false)
{
//Your Code
}
}
Just add this line in MainPage.xaml.cs page
InitializeComponent();
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
//Code that throws the exception
}
it works fine.
Does your class AllEmployeeViewModel have a zero-argument constructor? WIthout that, Silverlight cannot create an instance of your class.
You have a binding to EmployeeClass. That has to be a collection of some type for this to work, but the name EmployeeClass sounds like a single object and not a collection.
You really needed to post your View Model code as we had to guess this.
I put together a quick example and if the ViewModel contains:
public ObservableCollection<EmployeeClass> Employees { get; set; }
and I populate them with a few sample EmployeeClass objects,
public AllEmployeeViewModel()
{
this.Employees = new ObservableCollection<EmployeeClass>();
this.Employees.Add(new EmployeeClass() { Name = "One" });
this.Employees.Add(new EmployeeClass() { Name = "Two" });
and I change the binding to:
<Grid x:Name="grdAllEmp" DataContext="{Binding Path=Employees}">
It looks like this (no other changes):
I was getting the same error, i will explain it to you hopefully it will help you.
In my ViewModel's constructor i was executing some code, all code was withing below if condition except,
If(!IsInDesignMode)
{
// my code
}
// Problamatic method execution point
Except a method that i wanted to execute every time, but it turns out that you can only execute code if above condition is satisfied else your view model instance will not be created.
So to avoid this you have to do like that:
If(!IsInDesignMode)
{
// my code
// Problamatic method execution point
}
Put all your code inside that condition and everything will be fine.
Note: I was using MVVMLight library along with Model-View-ViweModel pattern.

Resources