MVVM WPF databinding to a Skype-like chat? - wpf

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.

Related

WPF floating listbox

I have a textbox that I would like to combine with a listbox in such a way that when the user types into the textbox, certain items will appear in the listbox, and the user may select them from there. What I am looking for is behaviour similar to that of the AutoCompleteBox. Sadly, I can't use the existing AutocompleBox in my project for several reasons, so I am trying to come up with similar behaviour on my own. Any ideas?
EDIT:
I would like to avoid using the tooltip as this seems like a hack. Also, when the listbox is displayed, no layouts should be changed either in the control or elsewhere. Is there something like the CSS style overflow available?
OK, it looks like "Popup" is what I am looking for. It's got some of its own quirks, but so far it is working just fine. I am pretty much using it like this..
<DockPanel>
<TextBox Text="{Binding Value}"/>
<Popup Name="popOptions" Width="300" Height="100" AllowsTransparency="True" StaysOpen="False">
<ItemsControl ClipToBounds="False" Background="White" MouseLeftButtonUp="ItemsControl_MouseLeftButtonUp">
<sys:String>ITEM ONE</sys:String>
<sys:String>ITEM TWO</sys:String>
<sys:String>ITEM THREE</sys:String>
</ItemsControl>
</Popup>
</DockPanel>
I am capturing other control events to decide when, and when not to display it.
You could put the ListBox in the TextBox's ToolTip
I'm not sure if that's the best way of doing what you're trying to accomplish, but it will work to make a floating listbox

How can I dynamically create a list of label and textboxes in WPF?

I am trying, and failing, to create a list of labels and text boxes in WPF. I am a ASP.NET developer and the XAML experience is slightly overwhelming me at the moment... I have Apress' Pro WPF 3.0 book infront of me and finding it zero use...
At the end of my process I want users to complete some questions that will be dynamic to that user. I have an Array of objects, with properties for a "Question" and "Answer".
I want the "Question" to appear as the label.
I've been looking at ListView controls, but this just seems to give me an Excel style grid which I am not interested in.
In the ASP.NET world I'd use a GridView, with two columns, one with a Label, the other with a TextBox. On submitting the page I'd loop through the items in the grid view to pick out the values of the textboxes, and associate back to the correct object in the Array.
Could someone please direct, or show me what controls I should be using in WPF?
Extra info;
It's a desktop WPF application using .NET 4, Visual Studio 2010.
Cheers
Stu
There's absolutely no need to use a DataGrid for something as simple as this. Using a basic ItemsControl will do what you're looking for without the overhead of such a complex control. This approach is also very easy to customize by just changing the ItemTemplate.
<ItemsControl ItemsSource="{Binding QuestionsToAnswer}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding QuestionText}"/>
<TextBox Text="{Binding AnswerText}" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I agree with Scott that DataGrid is probably the way to go. Here are some decent turotials to get you started:
http://www.c-sharpcorner.com/UploadFile/mahesh/WpfDGP109272009111405AM/WpfDGP1.aspx
http://www.wpftutorial.net/DataGrid.html

Silverlight 4 RichTextBox Bind Data using DataContext

I am working with Silverlight 4 and trying to put my test apps multilingual but I am having some trouble when I arrive to the "RichTextBox" control. I am able to bind it properly by doing back-code (c#), but when trying using the "DataContext" attributes I am not able to load it at all.
I have created a FormatConverter that return a Block (paragraph) for testing and my code where I have my RichTextBox looks like:
<RichTextBox x:Name="rtaTest" BorderThickness="0" IsReadOnly="True" UseLayoutRounding="True"
DataContext="{Binding Source={StaticResource Localization}, Path=Home.MainContent, Converter={StaticResource ParagraphFormatConverter}}">
</RichTextBox>
I am wondering if there is a way of binding a RichTextBox from the XAML.
Run seems to support databinding in SL4, as in:
<RichTextBox>
<Paragraph>
<Run Text="{Binding Path=LineFormatted}" />
</Paragraph>
</RichTextBox>
I think you may be a little confused about the used of the DataContext. You might for example have some Rich text where some children of one or more InlineUIContainer elements may retrieve their text from a property of some object. You would assign the object to the DataContext.
Whilst I'm not quite sure what you were expecting to achieve but I suspect that what you really need is for your converter to actually return a BlocksCollection (even if it just contains the single Block you were originaly returning) and then to bind as:-
<RichTextArea x:Name="rtaTest" BorderThickness="0" IsReadOnly="True"
UseLayoutRounding="True"
Blocks="{Binding Source={StaticResource Localization},
Path=Home.MainContent, Converter={StaticResource ParagraphFormatConverter}}" />
This FillFromXml is a WPF thing? Don't see it in Silverlight.
Blocks cannot be set, they can only be fetched. One way to set the blocks for a RichTextArea is
public static void UpdateRichTextArea(RichTextArea area, string xmlText)
{
if (area == null)
return;
area.Blocks.FillFromXml(xmlText, true);
}

wpf control template

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.

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