How to make a custom UserList control in C#? - c#

I'm making a chat program and I need a UserList control that supports icons, names, banners, status icons.
Here is a picture of the UserList I wish to clone:
As you can see the user name appears on top of the background image.
The status at the far shows red for admins, yellow for members and so on.
There are 2 more status icons that appear BEFORE the admin/member status and they show if a user is accepting private chats/messages here is a picture of that:
As you can see the UserList can contain normal (non banner like) icons as well as chat/pm status.
The UserList must scroll like any normal listview type control.
So can somebody tell me how to produce this control in C# winforms or wpf?
Any help would be greatly appreciated!

If you are using WPF, start with a ListView and set the view to a GridView.
Then set up the columns and cell templates.
Bind to properties.
<ListView Margin="10" Name="lvUsers" ItemsSource="{Binding Users}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding UserIcon}"/>
<TextBlock Text="{Binding Name}" Margin="20,0,0,0" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Status">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{StaticResource PrivateChatImage}" Visibility="{Binding IsPrivateChat, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<Image Source="{StaticResource PrivateMessImage}" Visibility="{Binding IsPrivateMess, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<Image Source="{Binding StatusIcon}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>

Well thanks for trying to help out you lot.
I did however manage to solve the problem by custom drawing everything.
Here is the end result
http://q67.imgup.net/Untitledeb8d.png
Bascially what I did was make a WinForms UserControl then added a userList class so it hooked into OnPaint() then looped through and drew the users.
It worked fairly well so then I made a header for it with Name and Status then I made the seperator grabbable to move it around (since its drawn on it has to be all manual stuff). It properly sets the cursor to the splitter.
After that was finished I needed a way to know what user a person clicked on but that was just a simple rect search.
After that was complete I needed a scroll that worked so I moved the user paintings into a new class that inherits SplitterControl I believe and then I made it set it's scroll size based on how many users in the list * how big the elements are etc.
All in all this userlist seems to work just as good as the one I was trying to clone.
So all is well!.

Related

Build UserControl to display both text and image dynamically

I am building a quiz redistributable desktop application. Questions can be text or image or both.
Someone suggested i build a text and image dynamic user control to display the questions. I have searched all round but cant find any tutorial that shows how to build such user control.
i was reffered to http://www.akadia.com/services/dotnet_user_controls.html,
http://en.csharp-online.net/Create_List_Controls,https://msdn.microsoft.com/en-us/library/aa302342.aspx
but it dosent help
As I can understand you need some control that can display a dynamic content (text/image). I can suggest you to use the content control that selects its content DataTemplate according to it's current data context.
I'will put a whole solution in several minutes.
<ContentControl Content="{Binding CurrentControlContent.Content}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type soSandBoxListView:SingleTextModel}">
<TextBlock Text="{Binding SingleModelContent}" Background="Tan"></TextBlock>
</DataTemplate>
<DataTemplate DataType="{x:Type soSandBoxListView:MultipleTextModel}">
<StackPanel>
<TextBlock Text="{Binding FirstName}" Background="Yellow"></TextBlock>
<TextBlock Text="{Binding LastName}" Background="Red"></TextBlock>
<!--use the binding to your picture presentation in model-->
<Image Source="Resources/yotveta.jpg" Stretch="None"></Image>
</StackPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
Regards

Why does ListView Item Template show buttons but with no text?

I have an WPF application with this XAML...
<ListView
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ItemsSource="{Binding HTMLControlNames}">
<ListView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"></Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The bindings are correct and there is data in the ObservableCollection property that implements INPC.
I added the Expression Dark Theme which is also working but this is the output from the markup above:
The buttons are there, they just aren't showing the text... BTW the number of buttons is equal to the count of items in the collection.
Here's the property in the ViewModel, single stepping shows me there are items (the proper ones) in the collection.
public ObservableCollection<ControlName> HTMLControlNames
{
get { return _HTMLControlNames; }
set
{
_HTMLControlNames = value;
PropChanged("HTMLControlNames");
}
}
Lastly the ControlName Class:
public class ControlName
{
public string Name { get; set; }
}
If I don't use ExpressionDark.xaml the content shows up!
Here's more information: Top part of the control shows up ok...
If I don't use DataTemplate as in the top half of this control the buttons are fine.
Here's the default Control Template (just a grid with a content presenter)..
What you are seeing that you think is a button in the ListView control is actually the header area. You can see this more clearly by adding columns to the header:
<ListView.View>
<GridView>
<GridViewColumn Header="Test" />
</GridView>
</ListView.View>
The list view items are actually the thin lighter-grey strips below this header.
I've not had much experience in templating list views (I usually use list boxes), but in the theme you are using, the list view seems to be templated in such a way that it basically ignores the item template. You can see that it does by using a daft template like this:
<ListView.ItemTemplate>
<DataTemplate>
<Rectangle Fill="Orange" Width="20" Height="20" />
</DataTemplate>
</ListView.ItemTemplate>
You will see that no orange rectangles appear in the list view, even when the collection that you bind to has elements in it.
I'm not quite sure how you can get around this problem. Maybe someone with more experience of templating list view controls can chime in.
Thanks to Stephen this is the solution so far:
<ListView.View>
<GridView>
<GridViewColumn x:Name="xHtmlControlcol"
Header="Filter For:"
Width="{Binding ActualWidth,
ElementName=XListView,
Mode=OneWay}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Width="{Binding ActualWidth,
ElementName =XListView,
Mode=OneWay}" BorderThickness="1,0" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
It produces this: Note that there's still one small issue with the left margin which I don't know how to fix right now.
The Trick to this is that when using Data Binding:
Use the ItemsSource to bind to collection of ListView
Use the ListView.View as shown above to set up a GridViewColumn.
Use the GridViewColumn.CellTemplate to inject the control type you want.
Make sure the injected control is bound to the proper Content path name.

Display data from two levels down

I have the following classes, which contain ObservableCollections of the next level down:
Draw
ObservableCollection<Round>();
Round
ObservableCollection<Formation>();
Formation
So a Draw is made up of Rounds, Rounds are made up of Formations.
I have a page which has a button to create a random draw, I currently have it calling another class which returns a draw:
this.defaultViewModel[DrawName] = RandomDraw.generate();
I am having no problem binding a ListView to Rounds and displaying round information, but how do I display the individual formations? This is what I am currently doing, I was not expecting to be able to just display things by binding to Formations but how do I access it?
<ListView
ItemsSource="{Binding Rounds}"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,9.5">
<TextBlock
Text="{Binding RoundNumber}"
TextWrapping="Wrap"
Pivot.SlideInAnimationGroup="1"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemTextBlockStyle}"
Margin="0,0,19,0"/>
<TextBlock
Text="{Binding Formations}"
TextWrapping="WrapWholeWords"
Pivot.SlideInAnimationGroup="2"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemContentTextBlockStyle}"
Margin="0,0,19,0"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You should take a look at Hierarchical Data Templates, which are used by the WPF TreeView control rather than ListViews. They are a natural fit to show hierarchical data. Of course, like any WPF control, you can completely customize their appearance using styling and templates. Here are some good references:
MSDN How to: Use a TreeView to Display Hierarchical Data
Hierarchical Databinding in WPF
However, if you would like to keep using ListViews, then one way to do this is to nest another container control inside the parent ListVIew. ObservableCollections are processed automatically by specific WPF elements, such as Panels. In your example, you can replace the second TextBlock with another ListView, with an ItemTemplate similar to the first. It can also be any Collection-like Panel element, such as StackPanel.
<ListView
ItemsSource="{Binding Rounds}"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,9.5">
<TextBlock
Text="{Binding RoundNumber}"
TextWrapping="Wrap"
Pivot.SlideInAnimationGroup="1"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemTextBlockStyle}"
Margin="0,0,19,0"/>
<!-- CHANGED CODE HERE -->
<ListView
ItemsSource="{Binding Formations}"
...>
<ListView.ItemTemplate>...</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

ListView SelectItem Binding not working as expected

I have a fairly straight forward listview control for my Windows 8 XAML/C# application. I am binding the listview to a PersonList and that works correctly. However, what I'd like to do and haven't been able to find the answer for is I want the to click an item in the listview and be able to display the PersonSingle object to the other textboxes on the screen.
I've read some posts that indicate that the listview may not be the right control for this operation. Am I missing something in my listview that would allow me to do this operation or should I use a different control?
<ListView
x:Name="itemListView"
Visibility="Visible"
Width="auto"
Height="auto"
ItemsSource="{Binding PersonList, Mode=TwoWay}"
SelectedItem = "{Binding PersonSingle, Mode=OneWay}"
ItemTemplate="{StaticResource person80Template}"
SelectionMode="Single"
Grid.Row="1"
Grid.Column="1"
VerticalAlignment="Stretch">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="7,7,0,0">
<Button
AutomationProperties.Name="PersonValue"
Content="{Binding PersonName}"
Style="{StaticResource TextButtonStyle}"/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
UPDATE:
So I figured out how to do it in a non-MVVM way (or at least not in a true MVVM way)
I added an ItemClick event to my ListView:
ItemClick="itemListView_ItemClick"
And then in the code behind I added the following:
private void itemListView_ItemClick(object sender, ItemClickEventArgs e)
{
VM.PersonSingle = ((Person)e.ClickedItem);
}
That works, but like I said, it doesn't feel very MVVM'ish. If you have any suggestions on how to make it work without having to manually set the PersonSingle object please answer below.
Your ItemClick solution is the right solution. You could create an attached behavior if you are opposed to handling events, but that's your choice.

Making clickable URLs in RichTextBox using bindings

My XAML has a DataTemplate defined which has ItemsSource set to some data class, which holds properties that will be presented in UI. One property is "Files", which has to display one or more files in the form of <Hyperlink NavigateUri="URLtoFILE">Filename</Hyperlink> (optional filesize).
The property is currently of type string where I'm concatenating different files' URLs and text together. But the stuff I put into that property display on screen verbatim.
I've seen this: WP8: RichTextBox has no Document property, but I have the problem of using data templates and bindings, which makes referencing the RichTextBox object in code impossible (is it?).
How can I mix text and clickable URLs within a WP8 control that is using data templates and bindings?
EDIT: If it helps, the ItemsSource always holds only one object.
EDIT: Part of XAML
<Grid>
<phone:LongListSelector x:Name="List">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<RichTextBox IsReadOnly="True">
</RichTextBox>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
You want to show a list of urls?
If you want this :
<lisbox itemSource={Binding YourItemSource} selectedItem="{Binding ItemProperty}">
<listbox.ItemTemplate>
<dataTemplate>
<textblock>
<Hyperlink Command="{Binding HyperLinkTapped}" NavigateUri="URLtoFILE"></Hyperlink>
</textblock><
</datatemplate>
</listbox.itemtemplate>
</listbox>

Categories