WPF controls, saving real estate - c#

I'm pretty new to WPF and C# and am trying to help out on some GUI stuff for work. We basically have 3 sections, a LHS (left hand side) [section 1], a RHS that has a top and bottom section [section 2 and section 3]. Looks like this
1 | 2
1 | -
1 | 3
They want a way to shrink each section with a button click. Currently the | and - are spacer items and can be dragged (Edit: this is done using a gridsplitter which they don't like). I did a little research and saw there are expander items and accordion items. I didn't know if either could be used for this scenario, and what would be the least hassle. In trying each just a bit, some additional questions for the controls come to mind since I'm not familiar with them.
Expander:
By shrinking section 1, would it make section 2 and 3 then take up the whole screen? Or can this only be done with an Accordion?
Is it hard/easy to change the <> icons to +- icons? If so, any tutorial out there?
Accordion:
Can the <> be changed to +-? If so, any tutorial out there?
Can the default color of blue be changed?
TIA

An Expander sounds like a suitable option for your situation. Fortunately it's included with WPF out of the box, unlike the Accordion control. But I found this question related to the Accordion control and thought it'd be useful for you to check out.
To change the appearance of the Expander toggle button you'll want to modify its control template. Changing the template to display plus or minus instead of arrows isn't too tough. If you visit the link you'll see you're going to want to change ExpanderToggleButton portion of the template.
Since you just want to change from using the arrows to using plus/minus signs you can simply change the Path data for collasped/expanded arrow. You can look here for more infortmation on drawing simple shapes with path.
Here is an example of someone modifying the control template of the Expander. It's for a different tweek in appearance, but it should be useful should you decide to go this route.
EDIT:
Really simple example (without the change in ToggleButton appearance) to get an idea of how to collaspe and save real estate:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColunmDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Expander Name="Section1" Grid.RowSpan="2" Grid.Colunm="0" ExpandDirection="Left">
<!-- Stuff goes here -->
</Expander>
<Expander Name="Section2" Grid.RowSpan="0" Grid.Colunm="1"
<!-- Stuff goes here -->
</Expander>
<Expander Name="Section3" Grid.RowSpan="1" Grid.Colunm="0"
<!-- Stuff goes here -->
</Expander>
</Grid>

You could use GridSplitter. The user can drag them to change the size. Not a click - a drag.
<GridSplitter Grid.Row="1" Grid.Column="1"
Width="3" Background="Purple" VerticalAlignment="Stretch" HorizontalAlignment="Center" ShowsPreview="False" >

Related

GridSplitter with a fixed panel (grid column) when grid (usercontrol/window) size changes

Basically, I want to emulate the GridSplitter.FixedPanel feature available in WinForms.
XAML :
<UserControl ...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" />
<GridSplitter
Grid.Column="1" Width="3" VerticalAlignment="Stretch"
Background="Transparent"
ResizeDirection="Columns" ResizeBehavior="PreviousAndNext" />
<ListBox Grid.Column="2" />
</Grid>
</UserControl>
This works great and resizes each side accordingly. But suppose we resize the (not maximized) window containing this UserControl, now both grid columns on each side of the splitter (auto) resizes. The 4/5 and 1/5 column width ratios are required for space distribution upon start, but practical space allocation depends on the displayed data, hence the grid splitter.
How to make one column retain its width (the one on the right for instance as it hosts properties, tools, etc.) while the window gets resized around, hence only making the left column resize.
I have some ideas :
Just code behind to emulate FixedPanel like in WinForms : DragStarted, DragCompleted and some private fields for eg.
Use a Behavior like suggested in this SO topic (I have not used Behaviors for years, have some refreshing to do - To be honest, I really hope there is an XAML-only way, but if there isn't, I prefer the code behind way where I expose new dependency propertie(s) rather than a behavior)
I believe I'm missing one feature of WPF to achieve this the WPF way. Almost all times I thought "well I guess I have to code behind this...", there were the WPF way, usually simplier, safer, easy to design and better, performance wise. That's why I'm asking directly, and maybe would help someone else looking for the feature.
Programming language (for that matter) : C#
Edit : after Léo Savador's answer :
See : there were a WPF way (toying with XAML ColumnDefinition Width properties) and little code :
bool p_layoutInitialized = false;
void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) {
if (e.NewSize.Width > 1) { // optional : && e.NewSize.Height > 1
if (!p_layoutInitialized) {
RightColumn.Width = new GridLength(MainGrid.ActualWidth / 5);
p_layoutInitialized = true;
}
}
}
where RightColumn is the name of the ColumnDefinition on the right, and MainGrid the name of the Grid.
Thanks you so much, was in the process of writing heavy code behind. You saved me so much time :D
PS : Please do not assume I'm a WinForm fanboy. I'm only mentionning WinForms to give a comparative example of the desired feature, could have used CSS and JS, but much harder to describe.
Here is a simple solution that I can recommend to you for your need:
For your right column, instead of using a dynamic width (1*), use a fixed width:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="160" />
</Grid.ColumnDefinitions>
If you set a fixed width of 160:
You will get the same initial result (1/5 of the initial width of your window)
You will be still able to resize your grid
On resize, your right column will keep it's width
And you have also the possibility to use code behind to calculate the desired fixed width at startup, according to the window initial width, to be more "dynamic".

Multiple list views - auto height for all of them

I'm trying to resolve some layout problems in my Xamarin.Forms application. For example, when height of content is higher than body content height, then lists will collapse.
I have undefined amount of lists with custom item templates. I want to remain all height of each list and have possibility of scrolling them.
I tried use StackLayout but it doesn't support scrolling. When I use ScrollView, the Auto property doesn't work correctly (there is ambigous space between each of lists).
My code looks like this:
<Grid>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0"> //Header
...
</Grid>
<StackLayout Grid.Row="1"> //Group of lists
<ListView x:Name="firstList" ItemTemplate="..." ItemsSource="...">
</ListView>
<ListView x:Name="secondList" ItemTemplate="..." ItemsSource="...">
</ListView>
...
</StackLayout>
</Grid>
How can I position these lists on full height?
What you try to achieve is very ambiguous from the mobile app perspective. Think the other way around: While your screen is full of stacked ListViews, how would the system know it has to scroll down the page or scroll down the current ListView?
Also nesting ListView into ScrollView is a very bad practice because:
ListView implements its own scrolling.
ListView will not receive any gestures -> they will be handled by the parent ScrollView.
also ListView can have customized header and footer that scrolls with the elements of the list, potentially offering the functionality that the ScrollView was used for.
If you want to stick to this layout, your option here would be to design your own implementation of your control using custom renderers and manage the gesture.
Hope it helps and happy coding!

How do I add a color film to entire application

this might be a very typical requirement, but has anyone ever tried to have a coloured film/cover on application. So I want when user performs an action the entire application get a red film on it. its not simply changing colour of controls, its like placing a coloured film so that everything that was white appears red, green appears yellow black remains black and so on..
I know I haven't added any attempts to this question because everything that I tried made no sense at all, only thing I can think of is to adjust RGB of every colour so that a particular value is added to it.
but here I just want to ask is there a simpler way of placing a red translucent pane on my application ?
Thanks
Like #HighCore suggested, you can simply put a control on top of everything else by putting it at the bottom of your XAML:
<Window>
<Grid>
<!-- Your Content Here -->
<Grid Background="Red" Opacity="0.3" />
</Grid>
</Window>
On that last grid you can also bind some things to it as your application needs, such as
<Window>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</Window.Resources>
<Grid>
<!-- Your Content Here -->
<Grid Background="{Binding MyColorCover}" Visbility="{Binding CoverIsVisible, Converter={StaticResource BoolToVis}}" Opacity="{Binding CoverOpacity}" />
</Grid>
</Window>
This would allow you to change the film cover's color/opacity/visibility at runtime. This assumes you got your bindings/MVVM stuff set up appropriately, which is another topic altogether.

Winrt Xaml Grid ROw not filling Space with *

I have the problem, that my Grid is not filling the space as I want it.
Here some code:
<HubSection>
<Grid Width="850">
<Grid.RowDefinitions>
<RowDefinition Height="35"/>
<RowDefinition Height="*"/>
<RowDefinition Height="310"/>
</Grid.RowDefinitions>
<Input:RadDatePicker Grid.Row="0" Value="{Binding CurrentDate, Mode=TwoWay}" />
<ListView
Grid.Row="1">...
</ListView>
<Grid Height="310"
Grid.Row="2">...
</Grid>
...
I want that the middle row is filling the space up of the hubsection. Instead it now just fills up when the listview contains enough items.
Any idea?
Now the filled ListView:
I would try setting the VerticalContentAlignment of the HubSection to Stretch as well as setting the VCA of the outer grid to that option. I'm suspecting the default might be Center or Top and so the minimizing vertical alignment control from the parent control and the expanding star-sized row setting of the inner grid come in a little bit of a conflict that some layout prioritizing rules probably resolve in getting the VCA rule to win.
For similar layout issues it is usually best to analyze with a visual tree debugger such as the XAML Spy or WinRT XAML Toolkit. You can also try tracing these various properties by walking the visual tree with the VisualTreeHelper class yourself.

How to Prevent auto-resizing in a custom activity designer?

I hope you can help me with my problem. It's about a custom designer for a WF 4.0 activity, but the problem is essentially in the WPF of the designer.
Some background
I've created a custom WorkFlow activity to send e-mails. For the custom designer for the activity, I've previously been using regular Textboxes for the "Subject" and "Body" of the e-mail, but I'd like to use the ExpressionTextBox to easily bind it to the InArguments of the activity. The ExpressionTextBoxes are in a grid, and this grid is on a StackPanel.
I've set the the MinWidth, MaxWidth and Margin of the ExpressionTextBoxes to fit with the other controls, and in the Visual Studio Designer (viewing the custom activity designer, not the actual WorkFlow) everything looks as it should.
<sapv:ExpressionTextBox Grid.Column="1" Grid.Row="2" Height="Auto" HorizontalAlignment="Right" Margin="4, 4, 4, 4"
Expression="{Binding Path=ModelItem.Subject, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
ExpressionType="{x:Type TypeName=sys:String}" OwnerActivity="{Binding Path=ModelItem}" VerticalAlignment="Center" MaxWidth="176" MinWidth="175" />
The problem
When used, initially it also looks as it should, but when the ExpressionTextBoxes are edited, they shrink into being really small. When text is entered, the control expands to fit the text, until it reaches its MaxWidth. When the editing ends, it goes back to it's MaxWidth. I'd prefer if it stayed the same size, regardless of being in edit-mode or not.
If you can't see it, open the image here
What I've tried
I've mostly been doing WinForms, and I'm pretty inexperienced with WPF, so I don't know if there are some funky properties or other settings that I've missed. I've tried setting width-properties of the parent controls (StackPanel and Grid), I've tried setting just the width (no min/max), but it seems to shrink regardless of what I set.
If you would like more information or code, please don't hesitate to ask.
Update
As you can see in the comments to Maurices answer, I figured out how to avoid the problem by removing the horizontalAlignment property, and then using margins to align it to the right. But I'm not going to mark an answer, until there's an explanation of why this behaviour happened in the first place. My XAML was almost identical to what Maurice posted, so there must be something wrong elsewhere.
The XAML for the ExpressionTextBox looks fine to me and when I try the following designer it works just fine.
<sap:ActivityDesigner x:Class="WorkflowConsoleApplication2.MyActivityDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation">
<sap:ActivityDesigner.Resources>
<sapc:ArgumentToExpressionConverter x:Key="ArgumentToExpressionConverter" />
</sap:ActivityDesigner.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Label Content="Subject"
Grid.Row="2"
Grid.Column="0"/>
<sapv:ExpressionTextBox Grid.Column="1"
Grid.Row="2"
Height="Auto"
HorizontalAlignment="Right"
Margin="4, 4, 4, 4"
Expression="{Binding Path=ModelItem.Subject, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
ExpressionType="{x:Type TypeName=sys:String}"
OwnerActivity="{Binding Path=ModelItem}"
VerticalAlignment="Center"
MaxWidth="176"
MinWidth="175" />
</Grid>
</sap:ActivityDesigner>
So I suspect the problem is possibly in your grid definition.

Categories

Resources