What i am basically looking out for is a combination of controls that work as 1 whole. I have no idea what the best way would be to start solving this problem in WPF, either a custom control, existing control, slider...?
Only thing i do not want are 3th party controls and the such.
When a certain condition is met a button with text will be placed inside the slider. Every time when certain conditions are met this situation will keep on happening and buttons will be placed inside the border field.
So it could be possible i have like 10 buttons after each other inside the border. The 2 navigation buttons to the left and right serve as navigation between all those buttons so all can actually get view and pressed when needed for further actions.
Picture that illustrates what i wish to achieve:
You can start with something simple as a StackPanel (you dont need to put it in a page but i wanted to make it copy paste friendly):
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Button Content="Left"/>
<ListBox>
<ListBoxItem>btnTest 10:00h</ListBoxItem>
<ListBoxItem>btnTest 11:00h</ListBoxItem>
</ListBox>
<Button Content="Right"/>
</StackPanel>
</Page>
Then focus on the appearance and behavior separately.
You need to learn WPF styles, so you can get the colors and layout as in your sample picture. This will also let you make the ListBox horizontal.
Look into the concept of a ViewModel to learn how to populate the ListBox with items. And event handlers for the buttons.
Its a very broad question but I hope this gives you a start.
Related
I'm trying to find the best solution for a TabControl that both support a close button on each TabItem, and always show a "new tab button" as the last tab.
I've found some half working solutions, but i think that was for MVVM, that I'm not using. Enough to try to understand WPF =)
This is the best solution I've found so far:
http://www.codeproject.com/Articles/493538/Add-Remove-Tabs-Dynamically-in-WPF
A solution that i actually understand. But the problem is that it is using the ItemsSource, and i don't want that. I want to bind the ItemsSource to my own collection without having to have special things in that collection to handle the new tab button.
I've been search for days now but cant find a good solution.
And I'm really new to WPF, otherwise i could probably have adapted the half done solutions I've found, or make them complete. But unfortunately that is way out of my league for now.
Any help appreciated.
I have an open source library which supports MVVM and allows extra content, such as a button to be added into the tab strip. It is sports Chrome style tabs which can tear off.
http://dragablz.net
This is bit of a dirty way to achieve the Add (+) button placed next to the last TabItem without much work. You already know how to place a Delete button next to the TabItem caption so I've not included that logic here.
Basically the logic in this solution is
To bind ItemsSource property to your own collection as well as
the Add TabItem using a CompositeCollection.
Disable selection of
the Add(+) TabItem and instead perform an action to load a new tab when it
is clicked/selected.
XAML bit
<TextBlock x:Name="HiddenItemWithDataContext" Visibility="Collapsed" />
<TabControl x:Name="Tab1" SelectionChanged="Tab1_SelectionChanged" >
<TabControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding DataContext.MyList, Source={x:Reference HiddenItemWithDataContext}}" />
<TabItem Height="0" Width="0" />
<TabItem Header="+" x:Name="AddTabButton"/>
</CompositeCollection>
</TabControl.ItemsSource>
</TabControl>
The code behind
private void Tab1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Contains(AddTabButton))
{
//Logic for adding a new item to the bound collection goes here.
string newItem = "Item " + (MyList.Count + 1);
MyList.Add(newItem);
e.Handled = true;
Dispatcher.BeginInvoke(new Action(() => Tab1.SelectedItem = newItem));
}
}
You could make a converter which appends the Add tab. This way the collection of tabs in you viewmodel will only contain the real tabs.
The problem is then how to know when the Add tab is selected. You could make a TabItem behavior which executes a command when the tab is selected. Incidentally I recommended this for another question just recently, so you can take the code from there: TabItem selected behavior
While I don't actually have the coded solution, I can give some insight on what is most likely the appropriate way to handle this in a WPF/MVVM pattern.
Firstly, if we break down the request it is as follows:
You have a sequence of elements that you want to display.
You want the user to be able to remove an individual element from the sequence.
You want the user to be able to add a new element to the sequence.
Additionally, since you are attempting to use a TabControl, you are also looking to get the behavior that a Selector control provides (element selection), as well as an area to display the element (content) which is selected.
So, if we stick to these behaviors you'll be fine, since the user interface controls can be customized in terms of look and feel.
Of course, the best control for this is the TabControl, which are you already trying to use. If we use this control, it satisfies the first item.
<TabControl ItemsSource="{Binding Path=Customers}" />
Afterwards, you can customize each element, in your case you want to add a Button to each element which will execute a command to remove that element from the sequence. This will satisfy the second item.
<TabControl ...>
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=CustomerId}" />
<Button Command="{Binding Path=RemoveItemCommand, Mode=OneTime,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type TabControl}}"
CommandParameter="{Binding}" />
</StackPanel>
</DataTemplate>
<TabControl.ItemTemplate>
</TabControl>
The last part is a bit more difficult, and will require you to actually have to create a custom control that inherits from the TabControl class, add an ICommand DependencyProperty, and customize the control template so that it not only displays the TabPanel, but right next to it also displays a Button which handles the DependencyProperty you just created (the look and feel of the button will have to be customized as well). Doing all of this will allow you to display your own version of a TabControl which has a faux TabItem, which of course is your "Add" button. This is far far far easier said than done, and I wish you luck. Just remember that the TabPanel wraps onto multiple rows and can go both horizontally or vertically. Basically, this last part is not easy at all.
My question seems to be a bit strange. I have a long list selector and I want to add a control like application bar in it so it can be repeated many times the same with the controls in the item template. I thought about a grid with the contents I want, but how can I make this Grid slides up and down ?
Yeah, it is strange but you can certainly try it. There is no definite way to do this but you can create a user control that would be the application bar like element you want and add it to the list selector. But the biggest problem is make it slide up and down. In the user control you can do this easily but there are many ways you can do this. You have to try it out and see. Use animations and story boards to animate the sliding effect. This can be done using Blend for Visual Studio. But you might run in to a problem where even though you did the animation of your application bar sliding in your Application bar like user control, it might not work in the list selector because the layout and the size of a single list item needs to change as the user expands the user control to have the sliding effect. As i said, there are many ways one can do this. You have to try it out and build it.
List item
In App.xaml type in this code
<Application.Resources>
<shell:ApplicationBar x:Key="UserControlAppBar" ForegroundColor="White" BackgroundColor="Black" IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="button1" IconUri="/Assets/Images/appbar/img1.png" Text="News" Click="button1_Click"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem x:Name="MenuItem" Text="Menu1" Click="Menu1_Click"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</Application.Resources>
I want a TextBox with line numbers. So I decided to use one small TextBox for the line numbers on the left and another big one on the right for the text.
My problem now is that I put these two TextBoxes into a Dockpanel and I need a height difference because the TextBox for the line numbers should not have scrollbars. So I need to shorten the left TextBox. My plan is to put an empty StackPanel below the left TextBox. And I'm getting trouble because the DockPanel doesn't sort my controls like I want. The only way I got it was using a fix width but I don't want that!
Or should I go a complete different way?
I don't know why you have to build this control, but you can find something similar for WPF. See this link AvalonEdit. It's a text editor control.
If you don't want a scroll bar on a control, just set the VerticalScrollBarVisibility to disabled.
But I'm not sure that's exactly what you need. If you do this then obviously your line numbers aren't going to scroll with your text box. You best bet might be to put your two textboxes (although if the line numbers aren't supposed to be editable, you might want to use labels instead) in a dockpanel and wrap the dock panel in a scrollviewer.
You may try to use ScrollView. The code below demonstrates the idea. But I haven't come up with a solution to enable horizontal scrolling.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ScrollViewer Height="100">
<DockPanel>
<TextBlock DockPanel.Dock="Left">
<TextBlock.Inlines>
1<LineBreak/>
2<LineBreak/>
3<LineBreak/>
4<LineBreak/>
5<LineBreak/>
6<LineBreak/>
7<LineBreak/>
8<LineBreak/>
9<LineBreak/>
10<LineBreak/>
11<LineBreak/>
12<LineBreak/>
13<LineBreak/>
</TextBlock.Inlines>
</TextBlock>
<TextBox AcceptsReturn="True" TextWrapping="Wrap">
I want a TextBox with line numbers. So I decided to use one small TextBox for the line numbers on the left and another big one on the rigth for the text. My problem now is that I put these two TextBoxes into a Dockpanel and I need a Heigth difference because the TextBox for the line numbers should not have scrollbars. So I need to short the left TextBox. My plan is to put an empty StackPanel below the left TextBox. And I'm getting trouble because the DockPanel doesen't sort my controls like i want. The only way I got it was using a fix width but I don't want that!
</TextBox>
</DockPanel>
</ScrollViewer>
</Grid>
</Window>
It looks like
So I have a Panorama control and the PanoramaItems are programmatically added to the control using the following template.
<UserControl>
<Grid x:Name="LayoutRoot">
<controls:PanoramaItem Name="sitePanoramaItem" Header="{Binding Name}">
<Controls:DockPanel VerticalAlignment="Stretch">
<StackPanel Orientation="Horizontal" Margin="0,10,0,0" Controls:DockPanel.Dock="Top">
<Image Source="../Images/action.png" Width="64" />
<TextBlock Text="{Binding Stats, Mode=TwoWay}" FontSize="45" Margin="15,0,0,0" />
</StackPanel>
<Grid x:Name="graphCanvas" HorizontalAlignment="Stretch" Margin="10,10,10,10"> </Grid>
</Controls:DockPanel>
</controls:PanoramaItem>
</Grid>
</UserControl>
When I click on graphCanvas what I'd like to do is sorta pop the graphCanvas out and display that fullscreen then when I click again restore it to where it was. I've been all over this site and Google and can't find anything similar to what I'm looking for.
I would still like to maintain the Panorama control functionality so that the graphCanvas is still the only one visible but you can cycle through them. Currently I have it sorta working in that I remove the Grid from the DockPanel and put it directly in the LayoutRoot while making the sitePanoramaItem collapsed. However, it's not fullscreen as the Panorama name is still visible (I guess I could hide that as well...) When I put the graphCanvas back int he DockPanel the size of the canvas is all screwed up.
I was hoping there was a simpler way.
Is it even possible?
It is possible to create the UI you describe but it's not going to be simple. You're on the right track with removing it in code and adding it the LayoutRoot and making the Panorama hidden. However you would have to code the scrolling behavior yourself and that is going to be quite tricky - especially making it feel the way to panorama does.
One trick you could try is actually layer a PivotControl on top of your Panorama and have it be collapsed by default. Also edit it's template to remove all default content eg: remove the header control, set margins to 0, etc). Then when you want to go full screen you can remove all the graphCanvases from the Panorama items and and add them to new PivotItems in the PivotControl. Then hide the Panorama and show the Pivot. This will give you scrolling capability for free and the illusion of full screen.
Having said all that I'm not sure I would recommend this. The more common approach would be to simply be to navigate to another page when the user selects an item and handle the full screen aspects there (possibly using the Pivot control again for scrolling). And when you want to leave "fullscreen" mode simply navigate back to the first page. Handling Tombstoning of the fullscreen state will be much easier with this approach for one thing.
You can try making the graphCanvas a Page and putting it in a different XAML. Then add a frame (name it InnerFrame for example) in the same place where you have the graphCanvas right now and navigate to that page with InnerFrame. When the frame is clicked, you navigate with the RootFrame of the app to your graphCanvas page. When you decide to close it, just navigate back with the RootFrame.
Hope it's clear enough :)
Edit:
Navigation in WP7 works very similar as the standard navigation in Silverlight 4, but it's a bit more restrictive. Just throw a PhoneApplicationFrame in your XAML like this:
<phone:PhoneApplicationFrame x:Name="Frame" />
This is basically the same as a Silverlight frame. All the pages you create inherit from PhoneApplicationPage by default, so they can be showed in a frame without any changes.
Your whole application actually runs on a PhoneApplicationFrame. If you take a look at your App class you will see this:
public PhoneApplicationFrame RootFrame { get; private set; }
Here's the MSDN documentation for the navigation system on WP7
This is a tough question, but I'll try to explain anyway...
I have a custom control window that is used all over my applicaton. The reason I did this is because I wanted the various windows and dialog boxes to be fully customizable across my program. I.e., the minimize, maximize, close button and frame are all custom. This window is templated inside my generic.xaml. Now this works and it's all good. The idea I got was from http://www.codeproject.com/KB/WPF/CustomFrames.aspx
Now the users of this custom window are user controls in their xaml they basically use MyWindow as their root element:
<MyWindow>
....
</MyWindow>
But now what I'm trying to do is "inject" certain elements into MyWindow from the User Control's xaml. MyWindow would simply have a container for hosting them. For example, they might want to inject a toolbar button that appears right next to the minimize button. So for example, I might have a user control that does the following (where MyWindow is the root element):
<MyWindow>
<MyWindow.ToolBar>
<Button x:Name="BlaBla"/>
</MyWindow.ToolBar>
</MyWindow>
This would put "blabla" right next to the minimize button for example. But I'm wondering if it's even possible to do this. I.e., the whole MyWindow.ToolBar thing. Is there a construct for this, is this an attached property or something weirder?
It definitely is possible, depends on your choice of types for the DependencyProperty. You could use IEnumerable and bind the MyWindow.ToolBar dp to the ItemsSource on your internal ToolBar.
<ControlTemplate>
<!-- ... snipped down to the ToolBar ... -->
<ToolBarTray>
<ToolBar x:Name="PART_ToolBar" />
</ToolBarTray>
</ControlTemplate>
With the appropriate code in OnApplyTemplate to pull PART_ToolBar and create new Binding for the ItemsSource.
EDIT: rereading your question it appears that I missed that you wanted to add this elsewhere. My suggestion then would be to use this as an object dependency property, with a ContentPresenter bound to the MyWindow.ToolBar with a Visibility set if the binding is not {x:Null}.