Custom panel with alternate background - silverlight

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!

Related

wpf custom button best approach

I want to create a custom Button inside WPF. Of course, the button will be an UserControl and it will contain many visual elements (like stroke, highlight, shadow, glow, images etc.).
The problem is that if I use DependencyProperties and bind them in XAML I won't be able to see the result at DesignTime (I've tried to implement IsInDesignMode method but for a certain reason that I can't understand my VS just crashes when I use this method on UserControls, otherwise it works just fine) and this is definitely not good.
So I am thinking about not using XAML at all and do all my work in the code behind.
What do you guys think?
Like you, when I was getting started and wanted to understand how / what was going on and working with templates, it took a lot of trial and error. Hopefully my research and some step-by-step components can help you customize to your liking and KNOWING where things are coming from.
First, when trying to understand how a new "template style" will work, I created a simple stand-alone WPF app ("AMS") for my Any Manipulating Styles. This way, I don't have to wait forever to see what something will look like during trial / error with the rest of my primary project and themes.
From that, I created a new WPF Window called "TestingStyles". Save/Compile, run, no problem.
Now, in the "VIEW CODE" of the TestingStyles window, I have put whatever I am playing with for a custom class... To help show the step-by-step, I've created the following:
namespace AMS
{
/// <summary>
/// Interaction logic for TestingStyles.xaml
/// </summary>
public partial class TestingStyles : Window
{
public TestingStyles()
{
InitializeComponent();
}
}
// Enumerator for a custom property sample...
public enum HowToShowStatus
{
ShowNothing,
ShowImage1
}
public class YourCustomButtonClass : Button
{
public YourCustomButtonClass()
{
// auto-register any "click" will call our own custom "click" handler
// which will change the status... This could also be done to simplify
// by only changing visibility, but shows how you could apply via other
// custom properties too.
Click += MyCustomClick;
}
protected void MyCustomClick(object sender, RoutedEventArgs e)
{
if( this.ShowStatus == HowToShowStatus.ShowImage1 )
this.ShowStatus = HowToShowStatus.ShowNothing;
else
this.ShowStatus = HowToShowStatus.ShowImage1;
}
public static readonly DependencyProperty ShowStatusProperty =
DependencyProperty.Register("ShowStatus", typeof(HowToShowStatus),
typeof(YourCustomButtonClass), new UIPropertyMetadata(HowToShowStatus.ShowNothing));
public HowToShowStatus ShowStatus
{
get { return (HowToShowStatus)GetValue(ShowStatusProperty); }
set { SetValue(ShowStatusProperty, value); }
}
}
}
As you can see, the custom "Button" class, I have at the bottom outside the default TestingStyles : Window declaration... so its all in the same "Project".
In this XAML sample, I make reference to a "TaskComplete.png" graphic file (which should just for sample purposes, add directly to the project... Even if a simple smiley face for sample purposes).
So, create such a simple .png file... even by using Microsoft Paint and drawing a circle with eyes and smile. Save into the project at the root (get into pathing stuff later, get it working first).
Save and recompile the project, so the project knows publicly what the new "class" (button) is when you start to define the XAML template.
Now, back to the TestingStyles designer and get it into split screen so you can see both the designer and the XAML markup... and Just replace with the following...
<Window x:Class="AMS.TestingStyles"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:AMS"
Title="TestingStyles" Height="300" Width="300" >
<Window.Resources>
<!-- Build a "Style" based on an anticpated target control type of YourCustomButtonClass.
per the "my:" reference, the "my" is an "alias" to the xmlsn:my in the declaration above,
so the XAML knows which library to find such control. In this case, I've included within
the actual forms's 'View Code' as a class at the bottom.
As soon as you assign an "x:Key" reference, its like its telling XAML to make this a PRIVATE
style so you don't reference it explicitly (yet)
-->
<Style TargetType="my:YourCustomButtonClass" x:Key="keyYourCustomButtonClass">
<!-- put whatever normal "settings" you want for your common look / feel, color -->
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,0,1,1"/>
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="30" />
<!-- Now, for the template of the button. Things can get really crazy here
as you are now defining what you want the "button" to look like, borders,
content, etc. In this case, I have two borders to give the raise/sunken effect
of a button and it has its own colors -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button" >
<!-- The x:Name references used during triggers to know what it is "applying" changes to -->
<Border x:Name="BorderTopLeft"
BorderBrush="Gainsboro"
BorderThickness="0,0,1.5,1.5">
<Border x:Name="BorderBottomRight"
BorderBrush="Gray"
BorderThickness="1.5,1.5,0,0">
<!-- Now, what control type do you want the button to have...
Ex: You could use a grid (as I have here), stack panels, etc -->
<Grid Background="LightBlue" >
<!-- I'm defining as two columns wide, one row tall.
First column fixed width 20 pixels example for an image -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20px" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<!-- Now, create the controls I want available within my "template".
when assigned with "x:Name", thats like a property withing the template
that triggers can associate and update to. -->
<Image x:Name="btnImage"
Grid.Row="0" Grid.Column="0"
Stretch="None"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Source="TaskComplete.png"
Visibility="Visible" />
<!-- and also have the text for the button to show the user -->
<TextBlock x:Name="txtNewBtn"
Grid.Row="0" Grid.Column="1"
Padding="5"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{TemplateBinding Content}" />
<!-- The "{TemplateBinding Content}" means to set the text based on
the "CONTENT" property of the original button and not use a fixed value -->
</Grid>
</Border>
</Border>
<!-- Now, some triggers for the button itself... some can be property based, others data-based -->
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<!-- What properties do we want to change when user CLICKS
on the button, give the "EFFECT" of click down/up by
changing the "Margin" and border thicknesses... -->
<Setter Property="Margin" Value="1,1,0,0"/>
<!-- Notice the "TargetName" below referring to the x:Name I've applied in template above
so when the user clicks on the button, it changes the border thickness properties of
each to give the effect of a normal button clicking. I'm widening one border, shrinking other -->
<Setter TargetName="BorderTopLeft" Property="BorderThickness" Value="2.5,2.5,0,0"/>
<Setter TargetName="BorderBottomRight" Property="BorderThickness" Value="0,0,.5,.5"/>
</Trigger>
<!-- Here, I have a custome property on the class for "ShowStatus". The binding is to itself
regardless of how many instances of this type of "button" are on a given form
First trigger happens when the value is changed to "ShowNothing", but can also change
when set to "ShowImage1" or other as you may need applicable
-->
<DataTrigger Binding="{Binding Path=ShowStatus, RelativeSource={RelativeSource Self}}" Value="ShowNothing">
<Setter TargetName="btnImage" Property="Visibility" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=ShowStatus, RelativeSource={RelativeSource Self}}" Value="ShowImage1">
<Setter TargetName="btnImage" Property="Visibility" Value="Visible"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- NOW, we can expose any instance of "YourCustomButtonClass" button to use the style based on definition above
any instance of such YourCustomButtonClass will automatically reflect this style / look -->
<Style TargetType="my:YourCustomButtonClass" BasedOn="{StaticResource keyYourCustomButtonClass}" />
</Window.Resources>
<Grid>
<my:YourCustomButtonClass Content="Button" VerticalAlignment="Top" ShowStatus="ShowImage1" />
</Grid>
</Window>
This should give you a great jump-start to defining your own templates and how the elements start to tie together. Once this sample is running, as you change any colors, margins, padding, etc to the template, you'll immediately see the visual impact that component has on the control.
Have fun and don't bang your head too much against the wall...
BTW, once this is working, then you can take the style element stuff within the
<Window.Resources>
</Window.Resources>
and put it into a Windows Resource Dictionary to make it global to your project instead of just this test form.

WPF shared property

I have a question which I guess it's some basic knowledge which I missing in WPF.
I set default width (generix.XML) to Textbox with some Minim width for the textbox
<Style TargetType="{x:Type TextBox}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="MinWidth" Value="50"/>
</Style>
I have two deferent controls which holds text box. Both Textboxes has same width..
I which to add some property to one of the controls which will declare the width of the textbox, and will override its width declaration, in a way that the textbox will 'find' to this property.
here is some drawing describes my requirement:
Update:
I just figure out that I didn't described one more importing thing.
I Have some DataTemplate which uses the textbox. As I wrote above, I have two controls which have the same DataType (MyData) I also created DateTemplate to display MyData. I would like that each control will display the textbox (from the datatemple) with different width.
update 2:
here is some more code
1- The dataTemplate to my data where is using textbox
<DataTemplate DataType="{x:Type ml:MyData}">
<Border BorderBrush="Transparent" ClipToBounds="True" Style="{StaticResource errorBorder}">
<TextBox Text="{Binding MyText}"/>
</Border>
</DataTemplate>
2- the way I used the datatemplate which uses the Textbox.
<ContentPresenter Grid.Column="1" Margin="10,1,10,1" HorizontalAlignment="Left" Content="{Binding}" />
This contentPresentor is been displayed in two diffrent controls. and as I wrote before, I would like that each control will display the textbox in diferent width
It's look like I miss some basic knloage (attached proerty? logic/visual tree?).
Thanks, Leon
Good question, the main idea in DataTemplate is that you have specific graphical representation for some data. You can read more about it in MSDN.
If you want to customize your TextBox, and have it different properties inside different UserControls, you might want to use ControlTemplate.
The thing is that if you want to control properties of specific control (in this case TextBox with some border) you should use ControlTemplate.
Your XAML should look something like:
<ControlTemplate TargetType="{x:Type TextBox}">
<--! define the ControlTemplate here with some Width property-->
<ControlTemplate>
and the Control which use it will have TextBox (as you defined it, with Border):
<TextBox Grid.Column="1" Margin="10,1,10,1" HorizontalAlignment="Left" Content="{Binding}" Width="50"/>

Binding a simple object of bools to ListBox and highlighting "true" items

I have a very simple class
public class SimpleClass // abreviated for this example
{
public bool HighAlert {get;set;}
public bool LowAlert {get;set;}
// about 10 other bools
}
They are all boolean prorties. I could also use a struct or possibly an array if that makes things easier.
I'd like to databind to a listbox AND have the items that are "true" highlighted in blue or red. And of course have the listbox updated when my object instantiated from SimpleClass changes. My only other requirement is to have something in the list box other than the member names. For example, it might be nice to have "Low Bank Account Alert" rather than "LowAlert".
And of course, the more this is automated (listbox actually using the SimpleClass) the better, for that inevitable day when someone adds a property to SimpleClass.
Any examples or tutorials? I would think this is a fairly common scenario.
Thanks,
Dave
you question seems to be twofold.
1) Conditional Formatting. you can use Triggers on the your list box, like this:
<Style x:Key="ColoringStyle" TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=HighAlert}" Value="True">
<Setter Property="Background" Value="#33FF0000"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=LowAlert}" Value="True">
<Setter Property="Background" Value="#33FFDD00"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
2) Displaying ListBox items differently. in WPF, you can use ItemTemplate:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
--- Have your custom display in here ----
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
both are widely used, pls google for any detailed examples, hope you got the gist

WPF ListView image depending on status column

I'd like to show an icon instead of a value in a listview. Basically, the ListView is bind to ModelView-Class (Observable-Collection as a property in that) and has a column called "status". Depending on status value, I'd like to show a different image. What would be the best way to do it. I read about DataTemplate, but I don't know where to hook in the code to switch the image.
MV-Class constructor looks like:
public TaskViewModel()
{
this.TaskCollection = ac.GetAllTasks();
}
Many thanks in advance,
Adam
I'd use a DataTrigger. Here's an example:
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template" Value="{StaticResource DisabledImageTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="Active">
<Setter Property="Template" Value="{StaticResource ActiveImageTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
If your images path/name dictated by code behind (this is bad but sometimes happens), you could implement IValueConverter and name it like StatusToIconConverter. See here on MSDN with a simple example.
Regarding Data Templates See at the DataTemplateSelector class. Here is also a very simple example.
The key point is to define simple class which just analizes a passed in value and returns an appropriate data template, obviously you have to declare one data template per image.

How to change WPF Listbox/ListBoxItem DataTemplate for selected item WITHOUT affecting style & theming?

This question is very similar to Change WPF DataTemplate..., which I have read and implemented. It worked beautifully at first, but I ran into a problem with it.
That problem is that, when using themes in your application such as those in the WPF Futures project (e.g. Expression Dark), the ListBoxItems all revert back to the default WPF styling. This breaks the theme for those elements and, for example, produces black text on black background where the text would otherwise be white. This also affected my TreeView, and presumably would affect other similar controls.
I think this is because conflicting styles are being set for ListBox.ItemContainerStyle--one from the theme and one for switching data templates.
I've looked around for other solutions, but haven't found anything yet. Here are the leads or ideas I've had so far:
Subclassing DataTemplateSelector and setting it to ListBox.ItemTemplateSelector. (The current best bet).
Somehow, somewhere use a Trigger, DataTrigger, or EventTrigger.
Give up on themes.
Somehow hack the functionality I want into the theme.
Somehow make my custom ItemContainerStyle somehow inherit it's colors and eye candy from the theme's style. (I tried it briefly, and it didn't work.)
Here is my ListBox and related pieces:
<Window.Resources>
<DataTemplate x:Key="NormalTemplate">
...
</DataTemplate>
<DataTemplate x:Key="SelectedTemplate">
...
</DataTemplate>
</Window.Resources>
<ListBox x:Name="RegisterListBox" Grid.Row="0"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding Adjustments}">
<!-- this is from the post referenced above -->
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContentTemplate" Value="{StaticResource NormalTemplate}"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource SelectedTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
The Listbox.DataContext is set in code to enable the ItemsSource binding.
Any ideas how I can achieve the kind of functionality described above while maintaining seamless support for themes?
Have you tried doing something like this?
<ListBox.ItemContainerStyle>
<Style
TargetType="{x:Type ListBoxItem}"
BasedOn="{StaticResource {x:Type ListBoxItem}}"> <=====
...
The idea is that the framework will first go look for a style with a key equal to typeof(ListBoxItem), it will find it in the themes, and then your style will just extend the themed one with your specific details.

Resources