wpf control template - wpf

I have a very simple case that I think would benefit from using templates (but I'm not sure, which is why I'm asking). All the templating examples I've seen either assume more knowledge than I have, are too specific to be of much use to a total newb like myself, or contain lots of ancillary stuff that makes it hard to identify what's part of the template.
Here's the setup:
I have two labels side-by-side, with the first label populated with the name of a field, and the second label populated with the value of the field.
Here is the XAML I currently have in my app (many, many times):
<StackPanel Style="{StaticResource horizontalStackerStyle}">
<Label Style="{StaticResource labelStyle}">Field One:</Label>
<Label Style="{StaticResource valueStyle}" Name="field1"
Content="{Binding dataObject.field1}" />
</StackPanel>
I would like to create a template such that I could write XAML like this:
<CustomControlOrWhatever
FieldName="Field One:"
FieldValue="{Binding dataObject.field1}"/>
I have a feeling I can do this with some kind of template. One benefit of which would be that I don't need to keep specifying the styles over and over. Am I correct? How would I do this?
Thanks in advance!
UPDATE:
Still haven't found an answer to this. I chose a possible solution using Dependency Properties, and tried to ask a clarifying question here. Well, the first responder said that I don't actually need to clutter up my code behind with DP nonsense, so I changed it again--and it still doesn't work. Can anyone come up with a working solution? This seems like it should be so simple.
Just to be clear: this only needs to be one-way binding with values updated every few seconds.

What you're asking for is basically a user control.
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SomeNameSpace.SomeControlName">
<Grid x:Name="LayoutRoot">
<StackPanel Style="{StaticResource horizontalStackerStyle}">
<Label Style="{StaticResource labelStyle}" x:Name="FieldNameLbl"></Label>
<Label Style="{StaticResource valueStyle}" x:Name="ValueLbl">
</StackPanel>
</Grid>
</UserControl>
In the code behind, you'd need to expose two properties that would set the value of the controls.
public string FieldName
{
get { return FieldNameLbl.Text; }
set { FieldNameLbl.Text = value; }
}
public string FieldValue
{
get { return ValueLbl.Text; }
set { ValueLbl.Text = value; }
}
And then to call that you can put this at the top of your window/page with the rest of your declarations:
xmlns:Controls="clr-namespace:SomeNameSpace"
and then you can insert the control into your window/page like this:
<Controls:NameOfYourControl FieldName="Field One:" FieldValue="{Binding dataObject.field1}"/>

You could create a UserControl called FieldControl and define backing (automatic) properties for FieldName and FieldValue. (Normal properties would be fine, so long as you only need to bind once, which is probably the case.)
The XAML code might look like:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="foo.bar">
<StackPanel Style="{StaticResource horizontalStackerStyle}">
<Label Style="{StaticResource labelStyle}" Content="{Binding Path=FieldName, Mode=OneTime, StringFormat='{0}: '}"/>
<Label Style="{StaticResource valueStyle}" Content="{Binding Path=FieldValue, Mode=OneTime}" />
</StackPanel>
</UserControl>
Hope that helps.

What you want to do is similar to the discussion about putting images on a button with a simple way of specifying the path, like <Button MyImage="foo.jpg" />. Follow this article for the actual details.
To summarize:
One obvious way would be to create an UserControl containing your two labels and exposing the two properties. Not much templating here.
The most WPFish solution seems to be to use two Attached Properties on one of the labels (say the value), and provide a control template for it that includes the other label (the description). In the template, you bind each label text to the corresponding attached property value.

Related

DataBinding to a List in silverlight

I've got a Grid which contains a TextBlock. The Grid's DataContext is of type List<MyClass>, and I'd like to bind the TextBlock.Text property to the MyClass.MyProperty property of first element in the List. I tried something like:
<Grid x:Name="RootLayout">
<TextBlock Text="{Binding [0].MyProperty}" />
</Grid>
But of course, that did not work. What's the right way of doing this?
Edit:
I'm going to try and make my explanation more clear. I've got multiple elements in the grid, each of which binds to a different item in the list. The items are laid out in a customized manner which cannot be accomplished by a GridView or ListBox. One of the items in the Grid is the TextBlock, and I'd like to bind its Text property to a property of the first element in the list. Once I know how to do that, I can extend that knowledge to add bindings to the rest of the elements in the grid.
Edit 2:
Turns out, my code works just fine in Silverlight. My project is actually a WinRT project, but I figured I'd get quicker answers if I tagged it as Silverlight, since databinding is supposed to work the same. I'm assuming this is a bug in WinRT, so I'll just have to find a workaround for it :(
I'm not sure I get why you want to do this, but you could create a property that returns what you want from the item in the list like so:
public string MyBindingProperty
{
get { return MyList != null && MyList.Count > 0 ? MyList[0].MyProperty : "Error Text"; }
}
Then you'd bind to MyBindingProperty:
<TextBlock Text="{Binding MyBindingProperty}" />
EDIT
I was wrong in saying you can't get at the items in the List - my bad. Your binding should look like this:
<TextBlock Text="{Binding [0].MyProperty}" />
If you need me I'll be in the corner enjoying my humble pie.
I am not an expert of SL but I think your are using the wrong Grid object; try with DataGrid in this way:
<data:DataGrid x:Name="targetDataGrid">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="MyProperty"
Binding="{Binding MyProperty}" />
</data:DataGrid.Columns>
</data:DataGrid>
also see here for more details: Defining Silverlight DataGrid Columns at Runtime
Edit: then go this way:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding MyProperty}" />
</Grid>
found here: http://msdn.microsoft.com/en-us/library/cc278072%28v=VS.95%29.aspx scroll donw the article...

WPF show small number beside all Controls

I have many FrameworkElements (TextBlock, CheckBox, ListBox..) and I would like to make something allowing me to show a small number besides every one control.
Some text ³
I came with the idea to write a MarkupExtension, where I could write that number like this:
..
<TextBlock Text="Some Text" SomeExtension="3" />
..
and then to add it somehow to the template of the Control.
But I'm sure, you guys have better solution for this problem ;)
One way to go with it would be create a Attached Property. Upon setting it on a control, a custom Adorner would be added for that control showing specified number.
Use the tag property to provide the number you want and inside the custom template databind to the property
<TextBlock Text="Some Text" Tag="3" />
and inside the controltemplate
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"/>

WPF - What to do when a Dependency Property is another Control in the XAML

I'm hoping this will be my last question today. I'm in a hurry and google is not helping much (that or I'm searching the wrong places).
I created some custom properties and behaviors so my RadioButtons can alter my labels Content and the mask of my TextBoxes.
I could pass a String as a property, but how do I pass another control as a property? (AdjustedLabel is of type Label)
<RadioButton i:CPF_CNPJAdjustBehavior.LabelContent="Apple" i:CPF_CNPJAdjustBehavior.AdjustedLabel="??????????" Content="CPF" Height="16" HorizontalAlignment="Left" Margin="30,216,0,0" Name="radioButton1" VerticalAlignment="Top" GroupName="a" IsChecked="True">
<int:Interaction.Behaviors>
<i:CPF_CNPJAdjustBehavior/>
</int:Interaction.Behaviors>
</RadioButton>
<Label Content="Label" Height="28" HorizontalAlignment="Left" Margin="20,81,0,0" Name="MyLabel" VerticalAlignment="Top" />
What do I have do write in "?????????" to set AdjustedLabel to the label named "MyLabel" ?
Thanks in Advance
Clark
AdjustedLabel="{Binding ElementName=MyLabel}" will do what you're searching for.
Consider reading some documentation for getting started with WPF, Bindings, Dependency Properties and XAML syntax. You could start with XAML Syntax In Detail, Dependency Properties Overview and Data Binding Overview.

MVVM WPF databinding to a Skype-like chat?

Hey guys, I've got what I think is an interesting question:
You all know and love the Skype chat interface: each message is enclosed in a bubble, with emoticons and link capabilities, as well as an avatar at the left.
What is the most ideal WPF component to house each message in, if I were creating a Skype-like interface?
I am using MVVM, so all my messages are stored in the ViewModel as an ObservableCollection.
I have had problems binding to a RichTextBox, and so I have investigated binding to a Listbox, where each list item is a message and each item is styled to have a Skypey border and avatar etc.
Any ideas?
The only suitable solution that I have found is using the flowdocumentreader and an ivalueconverter to convert an array of strings to a flowdocument. It actually works great once I made my own scripting language similar to bbcode.
This was the sample I learned from. http://michaelsync.net/2009/06/09/bindable-wpf-richtext-editor-with-xamlhtml-convertor
It was a little overkill for me so I ended up just making the ivalueconverter and a simple script language.
The solution i see is that you should use DataTemplate and Style. The idea is following: each text message represented by class object. Now when you bind your message inside template, you explicit tell how do you want your messages will look like.
It will better for you to create a usercontrol that will know how represent your messages.
Example that represent similar idea, but idea is the same:
<Window.Resources>
<DataTemplate DataType="{x:Type model:MessageModel}">
<ed:Callout AnchorPoint="0,1.5" Margin="10" CalloutStyle="RoundedRectangle" Content="{Binding Path=Text}" Fill="#FFF4F4F5" FontSize="14.667" HorizontalAlignment="Left" Height="100" Stroke="Black" VerticalAlignment="Top" Width="200" />
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Path=MsgList}" />
</Grid>
For that example you need attach Microsoft.Expression.Drawing.sll which come aside with Blend 4.

How to Clone a whole grid of Controls?

I have the following code and basically what i am not able to figure out is how to clone the whole grid and make a blank copy of them side by side.... for a clear understanding this is something to do with hospital application and the grid is related to a pregnancy so when said 'ADD CHILD' button a whole new grid should be created during run time, thanks for the help below is a link that might help people cause i tried it but not sure how to display it
How can you clone a WPF object?
You should put the object you are want to "clone" in a DataTemplate and reference this template from an ItemsControl, then when you need another grid add another item to the items control (or even better to the list the control is bound to) and the ItemsControl will create a new grid and bind it the new object.
For an example take a look at this post on my blog.
Here is an example for this application (I left only the relevant parts and I didn't test it, so there are probably some typos there):
<Window ... >
<Window.Resources>
<DataTemplate x:Key="ChildTemplate">
<Grid>
...
<TextBlock Text="Delivery Date:" Grid.Column="0" Grid.Row="0"/>
<TextBox Text="{Binding DeliveryDate}" Grid.Column="1" Grid.Row="0"/>
<TextBlock Text="Delivery Time:" Grid.Column="0" Grid.Row="1"/>
<TextBox Text="{Binding DeliveryTime}" Grid.Column="1" Grid.Row="1"/>
...
</Grid>
</DataTemplate>
</Window.Resources>
...
<Button Content="AddChild" Click="AddChildClick"/>
...
<ScrollViewer>
<ItemsControl ItemsSource="{Binding AllChildren}" ItemsTemplate="{StaticResource ChildTemplate}">
<ItemsControl.PanelTemplate>
<ItemsPanelTemplate><StackPanel Orientation="Horizontal"/></ItemPanelTemplate>
<ItemsControl.PanelTemplate>
</ScrollViewer>
...
</Window>
And in cs:
Set an object with all the form data as the Window's DataContext. I'll call this class PostDelveryData.
Create another class with the repeating data. I'll call it ChildDeliveryData.
Add a property of type ObservableCollection<ChildDeliveryData> called AllChildren to PostDeliveryData; it's important it'll be ObservableCollection and not any other type of collection.
Now, for the magic:
private void AddChildClick(object sender, RoutedEvetnArgs e)
{
((PostDeliveryData)DataContext).AllChildren.Add(new ChildDeliveryData());
}
And when you add the new item to the list another copy of the entire data template will be added.
I'm not sure that you're using the correct approach here. I would approach the problem by creating a "ChildGridControl" with a Child property, and let the Child property handle the databinding. Adding a new child to the GUI would involve creating a new instance of the ChildGridControl.
If I am understanding correctly, you should create a UserControl, which wraps your Grid and subsequent controls inside. And use this User control anywhere you wanted to replicate that UI.

Resources