I have a scroll viewer that I want to display all of my user controls. I have two types of user controls which are education and work. They are just text boxes and a button. I dynamically create various numbers of each and add them to a list of type usercontrol. However I cannot get all of the user controls to display!
Scroll Viewer xaml
<ScrollViewer x:Name="myScrollViewer" HorizontalAlignment="Left" Height="518" Margin="128,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="1123" FontSize="22"/>
Code behind
List<UserControl> info = new List<UserControl>();
EducationControl educationControl = new EducationControl(school._school, school._degree, school._fieldOfStudy, school._educationStartDate, school._educationEndDate);
info.Add(educationControl);
WorkControl workControl = new WorkControl(work._employer, work._jobTitle, work._jobStartDate, work._jobEndDate);
info.Add(workControl);
myScrollViewer.Content = info;
When I set the content of the scrollviewer to info, it just displays a string like:
System.Collections.Generic.list'1[Windows.UI.Xaml.Controls.UserControl]
However the I can get an individual usercontrol to display properly when I do:
myScrollViewer.Content = info.ElementAt(0);
How can I display all of the user controls in the scroll viewer?
The ScrollViewer's content must be a list-style control, such as a ListBox. By itself, the ScrollViewer doesn't know how to render a List<UserControl>, so it just prints the type name.
It looks like you probably want items to become the ItemsSource of a ListBox or similar control.
Related
I need to modify my XAML elements by code. I need to replace original content with new content inside ScrollViewer "XAML_ScrollViewer". Simple example of XAML code.
<ScrollViewer x:Name="XAML_ScrollViewer">
<ListView x:Name="XAML_ListView">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:SomeInformation">
<Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
To do this I use following code. Everything is so far well. New content appears as it should to do.
C#
//SourceElementParent = XAML_ScrollViewer
//GET PRESENT CONTENT
FrameworkElement ControlOldContent = (SourceElementParent as ContentPresenter).Content as FrameworkElement;
//CREATE NEW GRID
Grid NewParentGrid = new Grid();
//USE NEW GRID AS CONTENT
(SourceElementParent as ContentPresenter).Content = NewParentGrid;
//ADD SOME ELEMENT 01
NewParentGrid.Children.Add(XAMLElement_01);
//ADD SOME ELEMENT 02
NewParentGrid.Children.Add(XAMLElement_02);
//ADD OLD CONTENTS INTO A NEW GRID
NewParentGrid.Children.Add(ControlOldContent );
But when I need to restore the original content I cannot do it. The following code works BUT created Grid inside ScrollViewer must remain.
C#
//CLEAR ALL CHILDREN OF THE GRID
((SourceElementParent as ContentPresenter).Content as Grid).Children.Clear();
//ADD OLD CONTENT TO THE GRID
((SourceElementParent as ContentPresenter).Content as Grid).Children.Add(ControlOldContent);
Because I want to restore the control ScrollViewer to the old state (content as it was before any modify) I also need to rid of the Grid I created earlier. But if I do so I get exception if I resize window size by mouse. If I don't resize all looks good.
I get the following exception:
e = {Windows.UI.Xaml.UnhandledExceptionEventArgs}
Exception = {"Invalid pointer\r\n\r\nInvalid pointer\r\n"}
I tried to use following code to restore contents but it fails.
C#
//CLEAR ALL CHILDREN OF GRID
((SourceElementParent as ContentPresenter).Content as Grid).Children.Clear();
//ADD ORIGINAL CONTENT
(SourceElementParent as ContentPresenter).Content = ControlOldContent;
So, any good hints how to solve this problem?
Found a working solution finally. Content must restore as new ScrollContentPresenter. So the ContentPresenter type must be exactly correct and I didn't realize this before.
//CLEAR ALL CHILDREN OF GRID
((SourceElementParent as ContentPresenter).Content as Grid).Children.Clear();
//RESTORE SCROLLVIEWER CONTENT.
(SourceElementParent as ScrollContentPresenter).Content = new ScrollContentPresenter() { Content = ControlOldContent };
I've got a ListView defined in XML:
<ListView
x:Name="lvFuellmengenDetails"
HorizontalAlignment="Center"
Height="570"
FontSize="30"
Margin="10,85,10,0"
VerticalAlignment="Top"
HorizontalContentAlignment="Center"
Width="572">
In the code behind I set the GridView as a view to the ListView to be able to add some columns
var gridView = new GridView();
this.lvFuellmengenDetails.View = gridView;
gridView.Columns.Add(new GridViewColumn
{
Header = "Nummer",
Width = 200,
DisplayMemberBinding = new Binding("Nummer")
});
gridView.Columns.Add(new GridViewColumn
{
Header = "Wert",
Width = 200,
DisplayMemberBinding = new Binding("Wert")
});
I need another Column that should be editable in every line (e.g. Textboxes) - defined not in XML, but in C# code)
If that is not possible: is there a way to detect a certain line is clicked?
I looked for an Event like "ItemClicked" but couldnt find any.
Then I could open a DialogBox and change the label instead of using textboxes. Thanks for your help.
To archive what you want, you have to either build the DataTemplate or get the resource and assign that onto the columns ItemTemplate
it is more or less the same as if you would use normal XAML
as the DataTemplate probably wont change, you probably want to create the DataTemplate in XAML and then just load it from the resources
I have an xaml datagrid template in my WPF application that binds/pulls data from a sharepoint site. Each row has a button with a tooltip and the text is dynamically loaded from this connection. When a user clicked on the button, it would copy the tooltip text to the Windows ClipBoard. Just recently, my existing code behind stopped working, and can't seem to get that dynamically loaded tooltip text anymore to work with in code. I've ruled out the clipboard as I can manually set the text and it copies to the clipboard and I can still see the dynamically loaded text in the UI so it can't be the connection. Below is how I use to get the text in the click event:
var buttonTemplate = ((Button)sender).ToolTip;
var buttonTTtext = ((TextBlock)buttonTemplate).Text;
System.Windows.Clipboard.SetText(buttonTTtext.ToString());
Here is the xaml I'm using in the datagrid template:
<mui:ModernButton Click="someButton_Click" Tag="{Binding Path=MyTemplate}" >
<mui:ModernButton.ToolTip>
<TextBlock Text="{Binding Path=template}" TextWrapping="Wrap" />
</mui:ModernButton.ToolTip>
</mui:ModernButton>
Thanks for the help...the tooltip text was in the DataContext of the button. I solved my issue with this code:
Button btn = (Button)sender;
var dc = btn.DataContext.GetType().GetProperty("template").GetValue(btn.DataContext, null);
I have a treeview at the left side of the screen, and when I click on any of the TreeViewItem, I want the right side of the screen to change accordingly.
For example, clicking on 'Project' would display on the right half of the screen, a label for project name along with the project name in a text box, and a similar label-textbox pair for some other fields. Clicking on a sub-option of 'Project' such as 'Task 1' should change the right half of the screen such that instead of labels and textboxes for project name and details, it should now be for task name/details. Atm, I only care about label-textbox pairs but in the future I'll need some more sophisticated options, maybe buttons and tables.
What I thought of was to have a grid premade for each option, when I clicked on 'Project' there would be a grid which displays all the info for a Project. And when I then clicked on 'Task 1', the Project grid should be hidden and the Task grid should be displayed with the fields filled out.
Is this possible? What should I be using to create templates that I can then choose from?
Firoz already mentioned the important bit. A rough guess is that you're not using MVVM pattern, so to minimize the adaption effort, you could add a Content Control to your window and set the content of this control whenever a selection is made. You can put any User Control in there.
Using MVVM would mean you bind that Content Control to a property on your ViewModel (of type UIElement or UserControl) and set an instance whenever a bound selected values changes. Speaking of selected Value, I think the default TreeView is not really Binding-friendly, so you might end up with behaviours that do the binding for you.
What you are asking to do is quite easy and possible, but I don't think you are thinking quite big enough.
As your project grows and the number of different things that you want to show expands, then you are going to need to show and hide more and more controls. This is quite quickly going to get unmanageable. Instead think about some other controls deal with this, in some ways you are doing something very like a tabbed dialog, just with a hierarchical set of tabs.
A tabbed dialog has a panel and a set of tabs, when you click on each tab, the content of the panel changes. In fact you can create UserControls one for each specialised set of UI that you want to display, e.g. you could have a ProjectControl that displays all of your project textboxes, labels, buttons etc.
In addition WPF has this neat feature called DataTemplates, these define how a type of data should look when it is displayed. So if you where to have a
public class MyProject
{
public string Name {get;set;}
}
Then you could define
<DataTemplate DataType="{x:Type MyProject}>
<TextBox Text="{Binding Name}"/>
</DataTemplate>
And WPF will automatically convert the data into to its visual form if you set it as the content of the tab panel.
However this type of displaying content in a panel is not the only WPF control that does this. There is also something called a NavigationFrame, which also can be used wrapped into a Window as a NavigationWindow. This control provides you ways to navigate to the next Page to display. Pages can be just like the UserControls in a tabbed dialog, but can also be URIs, enabling you to link in content from the web if you wish. In addition you can call NavigateTo from other controls enabling you build much more usable interfaces.
I worked through the process of building a full windows control panel style interface in
http://alski.net/post/2012/01/11/WPF-Wizards.aspx
and http://alski.net/post/2012/01/13/WPF-Wizards-part-2-Glass.aspx
I've added later VS2012 style glows in
http://alski.net/post/2013/09/14/WPF-Re-creating-VS2012Office-2013-window-glow.aspx
And then released the entire source code as open source at
http://winchrome.codeplex.com/
This comes with support for embedding Navigation panels with
<WinChrome:SearchableNavigationWindow
x:Class="WinChrome.Win7Demo.MainWindow"
...
xmlns:WinChrome="clr-namespace:WinChrome;assembly=WinChrome"
Style="{StaticResource Win7NavigationWindow}">
<WinChrome:SearchableNavigationWindow.Navigation>
<view:Navigation x:Name="navigationTree"/>
</WinChrome:SearchableNavigationWindow.Navigation>
(Full source code)
Where the navigation window is embedded as, but can also be a TreeView.
<UserControl x:Class="WinChrome.View.Navigation" ...>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" Padding="12,0"
VerticalScrollBarVisibility="Auto" >
<StackPanel>
<Button
Margin="0,12,0,0" Style="{StaticResource LinkNavigatorButtonStyle}"
Content="Home"
Command="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Win7Demo:MainWindow}, AncestorLevel=1},
Path=GoHomeCommand}" />
</StackPanel>
</ScrollViewer>
(Full source code)
I currently have a window with a ListBox within in. The ListBox shows the results from a search.
The problem I currently have is that when a search is performed and enough items are added to the ListBox, the ListBox expands vertically and forces the form to expand vertically as well.
I know I can fix this with a maxheight, but I don't want to limit the size of the form to the user, only to the program at runtime.
Is there a way I can tell the ListBox to not automatically expand or only expand when the user resizes the form?
My apologies... I've sorted out the problem. I'd mistakenly set Window.SizeToContent = "Height".
Problem solved.
Just put it in a Grid. Unless the window is set to automatically size (SizeToContent="..."), then this should work.
<Grid>
<ListBox x:Name="lstSomeData"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
</Grid>