Binding to SystemColors in Silverlight XAML - silverlight

I have following code in WPF XAML and want it to be converted to Silverlight 4:
<Setter
Property="Background"
Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter>
Unfortunately, Silverlight does not support x:Static.
Does anybody know how to port it properly without code behind, XAML-only?

Since you cannot access Static properties like that,you've to define your own "wrapper" class that will wrap the static properties, something like this:
public class StaticMemberAccess
{
public ResourceKey WindowBrushKey { return SystemColors.WindowBrushKey; }
//define other wrapper propeties here, to access static member of .Net or your classes
}
Then do this in XAML
<UserControl.Resources>
<local:StaticMemberAccess x:Key="SMA"/>
</UserControl.Resources>
<Setter
Property="Background"
Value="{Binding Source={StaticResource SMA}, Path=WindowBrushKey}" />
<Setter>
Hope, it gives you some idea. :-)
See this also:
Retrieving value from static extension XAML

Related

Is it right to put a viewmodel in a resourcedictionary?

I'm developing a WPF project, and usually I use resourcedictionary to organize the styles and colors. When using Expression Blend it will put the viewmodel object in a resource like this:
<local:VM x:Key="VM" d:IsDataSource="True"/>
and set the datacontext like this
<Window.DataContext><Binding Mode="OneWay" Source="{StaticResource VM}"/></Window.DataContext>
This is very useful to get the command or property in XAML using the source property in binding like this (especially in datatemplate)
{Binding XXCommand,Source={StaticResource VM}}
Can I put the viewmodel object in resourcedictionary or is it better to put this view specific in each view that is related to the viewmodel?
Also, if I put the below style in resourcedictionary I have to include the viewmodel object,
<Style x:Key="MenuItemStyle" TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Desc}"/>
<Setter Property="Icon" Value="{StaticResource IconImage}" />
<Setter Property="Command" Value="{Binding ChangeShowCommand,Source={StaticResource VM}}"/>
<Setter Property="CommandParameter" Value="{Binding}"/>
</Style>
This might be the answer: MVVM Instantiation Approaches. Nicely explained couple of instantiation approaches.

WPF Application using MVVM Toolkit will not compile with StartupEventHandler

I have a WPF application that does not compile when I attempt to add any event handler to the App class.
Below is all the code and the exception I am getting. The application uses the MVVM toolkit - so that may be a factor.
If someone could tell me what I may be missing or doing incorrectly, it would be greatly appreciated.
App.xaml code:
<Application x:Class="MyClient.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Sample.ViewModel"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Startup="Application_Startup">
<Application.Resources>
<!--Global View Model Locator-->
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
<!-- Resources scoped at the Application level should be defined here. -->
<Style x:Key="TextBlockStyleFooter" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="1"/>
</Style>
<Style x:Key="TextBlockStyleClock" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="Foreground" Value="White"/>
<!--<Setter Property="Margin" Value="0, -1,"/>-->
<Setter Property="TextAlignment" Value="Center"/>
</Style>
<Style x:Key="BorderStyle1" TargetType="Border">
</Style>
</Application.Resources>
App.xaml.cs Code:
using System;
using System.Windows;
using System.Windows.Threading;
using GalaSoft.MvvmLight.Threading;
namespace Sample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
static App()
{
DispatcherHelper.Initialize();
}
private void Application_Startup(object sender, StartupEventArgs e)
{
}
}
}
When I try to compile this, I get the following exception:
Error 1 'MyClient.App' does not contain a definition for 'Application_Startup' and no extension method 'Application_Startup' accepting a first argument of type 'EdgePokerClient.App' could be found (are you missing a using directive or an assembly reference?) C:\projects.git\MyClient\src\MyClient\App.xaml 7 73 MyClient
The issue here is that your XAML refers to MyClient.App whereas your code-behind file has the partial class in the Sample namespace. To the compiler, these are two separate classes. So the event handler you've defined in the one class (Sample.App) is not present in the generated class MyClient.App.
You just need to fix either the namespace in your code behind file or the x:Name attribute in the XAML file.
I'd also be careful with the static constructor on App. I'm not sure if the code generator will add a public parameterless constructor or not, but if it doesn't, having only a static constructor will effectively mean that App can't be instantiated.
I'd like to post this comment for other people getting this same error like i did.
I had this same error, however my x:class namespace wasn't different than the code behind namespace. Some tutorials says that after you put the Startup="Application_Startup" on your XAML, your code behind should be updated automatically. it didn't happen leading me to this error.
My Fix - Update code behind with
private void Application_Startup(object sender, StartupEventArgs e){}
before adding
Startup="Application_Startup"
to the xaml.
hope this come to be useful to somebody.

Static Binding to Singleton Mysteriously Fails

I have the following singleton class which contains the following property:
public class Manager : INotifyPropertyChanged
{
public bool IsOnline
...
public static Manager Instance
...
}
In the mark-up I am trying to change the color of a button based on this online property:
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<Binding Source="{x:Static storage:Manager.Instance}" Path="IsOnline"/>
</DataTrigger.Binding>
<Setter Property="Background" Value="#8000FF00"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
This binding <Binding Source="{x:Static storage:Manager.Instance}" Path="IsOnline"/> fails with the exception:
Cannot convert the value in attribute 'Source' to object of type 'System.Windows.Markup.StaticExtension'.
I have quadruple-checked the "storage" namespace; I know it is both referenced and correct. The Instance property is static, so I do not understand why this binding would fail. I have similar bindings to static properties all over that work just fine.
Any ideas?
I've built a sample app that does exactly what you're describing, it works with no issues. You can download it here.
Have you tried using a ValueConverter to inspect the value that the StaticExtension is getting?
(See method 2 on this page)
I just had exactly the same weird problem!
Solution:
You MUST instantiate the class before doing any XAML operations with that class!

Custom panel with alternate background

I'd like to create a simple custom panel to layout children in a business form fashion. Ideally I'd like my markup to look like this:
<Panels:FormPanel>
<TextBlock Text="Name:"/>
<TextBox />
<TextBlock Text="Address"/>
<TextBlock Text="Unknown"/>
<TextBlock Text="City"/>
<TextBox HorizontalAlignment="Stretch"/>
<TextBlock Text="State"/>
<ComboBox/>
<TextBlock Text="Country"/>
<StackPanel>...</StackPanel>
</Panels:FormPanel>
The panel will layout controls in two columns labels on the left side and values on the right.
I have no problem laying out my controls. The problem is that I also need to alternate background for the rows to create stripes for easier reading.
Any ideas how can this be done?
This doesn't directly answer your question, but you could consider this as another solution to the underlying problem.
Take a look at http://wpg.codeplex.com/. I used a similar property-grid-like control in Windows Forms that was modified to understand custom attributes on my business objects.
Now, in WPF, I would think something similar would work really well if you follow the MVVM pattern and you decorate your ViewModel with attributes that such a property grid understands. Then you don't need to explicitly define the fields like you show above.
You could have a ViewModel:
class PersonViewModel
{
[DisplayName("Name")] // The property Grid uses this the Textblock text
[IsRequired] // The property grid could do validation on the field
[Visible]
public string Name { get; set; }
public long InvisibleSystemField { get; set; } // Not shown
}
And then you'd only have Views (Xaml files) like this:
<myCommon:PropertyGrid DataContext={Binding}/>
It could simply use it's DataContext as the starting point for reflection.
OK I'll stop there for now :)
I'm working on a WPF powered LOB application and I'll possibly build something like this in future.
Implementing a custom panel is not actually that difficult. You have to override two methods, Measure and Arrange. Google for "wpf custom panel" to get some articles about that.
What I would suggest you do to get the behavior exactly as you required in the question is extend Windows.Controls.Grid. Your custom grid could then have two columns by default that you initialize in the constructor and you can programmatically set the Grid.Column and Grid.Row properties on the child controls.
Also worth looking at could be the ItemsControl. It does have support for alternatively colored rows. This example (from MSDN) shows how to use it:
<Grid>
<Grid.Resources>
<Style x:Key="alternatingWithTriggers" TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
<Style.Triggers>
<Trigger Property="ListBox.AlternationIndex" Value="1">
<Setter Property="Background" Value="CornflowerBlue"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="ListBox.AlternationIndex" Value="2">
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="Navy"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ListBox AlternationCount="3" ItemsSource="{StaticResource data}"
ItemContainerStyle="{StaticResource alternatingWithTriggers}">
</ListBox>
</Grid>
You could then specify a template for the items that includes a Label and a TextBox, but getting this to work could be fiddly.
Here's one final thing I'll suggest:
XAML Powertoys include features that allow you to generate business forms from ViewModels, ViewModels from Models and much more. You might need to modify the source to get alternating row colors though.
Good luck!

WPF Setting on a Control Template

General question. I have a ControlTemplate that is reasonably complex. Several TextBoxes etc.
I can't use TemplateBinding to bring all the properties to the surface so that I can set all the styles.
Is there a way for a Style to 'delv' into the controls within a control to set values?
Hope my question is clear without an example.
Thanks
The short answer is no. The ControlTemplate is essentially a black box, at least where XAML is concerned (there are ways to dig down the visual tree in code).
When you say you "can't use TemplateBinding", why not? If you just don't have enough available properties that can be fixed by creating some attached properties for the values you want to pass through. This is assuming you're templating a control that you can't change, otherwise you can just add new dependency properties.
Attached property:
public static class CustomProps
{
public static readonly DependencyProperty MyNewBrushProperty = DependencyProperty.RegisterAttached(
"MyNewBrush",
typeof(Brush),
typeof(CustomProps),
new UIPropertyMetadata(Brushes.Green));
public static Brush GetMyNewBrush(DependencyObject target)
{
return (Brush)target.GetValue(MyNewBrushProperty);
}
public static void SetMyNewBrush(DependencyObject target, Brush value)
{
target.SetValue(MyNewBrushProperty, value);
}
}
And usage in Style and Template:
<Style TargetType="{x:Type Button}">
<Setter Property="local:CustomProps.MyNewBrush" Value="Red" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:CustomProps.MyNewBrush)}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Using this method also still allows overriding values on individual instances.

Resources