How to arrange the buttons vertically in RibbonControlGroup (wpf) - c#

I have RibbonControlGroup with a few buttons.
<r:RibbonControlGroup>
<r:RibbonToggleButton Label="button1"/>
<r:RibbonToggleButton Label="button2"/>
</r:RibbonControlGroup>
On Ribbon buttons are arranged horizontally. Like (button1|button2).
How to arrange the buttons vertically?

I know, that I'm late to party, but may be this will help someone.
Since the RibbonControlGroup is an ItemsControl, the right way to go is to replace ItemsPanel like this:
<r:RibbonControlGroup>
<r:RibbonControlGroup.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</r:RibbonControlGroup.ItemsPanel>
<!-- Group items are listed below: -->
<r:RibbonToggleButton Label="button1"/>
<r:RibbonToggleButton Label="button2"/>
</r:RibbonControlGroup>
This approach conceptually differs from #Sajeetharan's answer, because he creates a group with a single child - StackPanel, while my sample still is an equivalent of the code, posted in the question: here's a group with two children of type RibbonToggleButton.
The difference will be meaningful with data binding scenarios, when items of group be populated dynamically through data binding expression.

You can keep these controls in a container and set its Orientation property to "Vertical"
For e.g. using StackPanel as a container
will place the buttons vertically

Use StackPanel and change the orientation to Vertical ,
<r:RibbonControlGroup>
<StackPanel Orientation="Vertical">
<r:RibbonToggleButton Label="button1"/>
<r:RibbonToggleButton Label="button2"/>
</StackPanel>
</r:RibbonControlGroup>

Related

WPF ListView virtualization in a ScrollViewer

I have a requirement which is to display a user information at top of the page and a ListView of images will follow it, and I've wrote following code (it's a pseudocode but I think it's enough to explain what I've done):
<ScrollViewer>
<StackPanel>
<Grid>
<!-- User Information Part -->
</Grid>
<ListView>
<!-- Images Part, This is a custom virtualized ListView, it's ItemsPanel is a custom VirtualizingWrapPanel -->
</ListView>
</StackPanel>
</ScrollViewer>
But in this scenario, the VirtualizingWrapPanel (by which has been tested on another individual ListView without an explicit ScrollViewer declaration and it works correctly) and the virtualization of ListView won't work because the desired height of ScrollViewer is positive infinity and all the items in the ListView will be expanded and rendered, I wonder whether there is a way that can make the ListView in ScrollViewer being virtualizable? Thanks
You can't virtualize a list that has all elements being rendered (because of the StackPanel),
A workaround that will work for you: you need a single ListView. With the first row customized to display the User Information Part, and all other rows displaying images.

Wrap the same control in a WrapPanel

in my WPF project I have a selfmade timeline visualization. Each row of a Grid is an hour (e. g. 9 am, 10 am, and so on) and from left to right, the minutes increase from 0 to 60.
Assume an event ranges from 9:50 pm to 10:30 pm. It is visualized by some custom control, that fits its Width and position to the corresponding time in the "timeline". Can I break the same control to continue in the next row? I know a Wrap panel does this, but only between two separate controls.
Thanks in advance.
Your custom control probably consists of other controls, right? And GridView is probably not the best choice if you need wrapping, you cannot move some columns to the new "line". Instead you could visualize each event as e.g. StackPanel with some custom stuff etc. So you should basically include the break-line logic into your control, so that when your control doesn't get enough width it would move its internal elemnets to a new line. How about including a WrapPanel into your control?
You could also use a normal ListView if you want to bind to a collection of elements and redefine the internal collection control of the ListView, so that it positions items horizontally. So all your events would stack to each other horizontally and wrap when needed:
<MyCustomControl>
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding ... my events ...}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
...
</ListView>
</MyCustomControl>

WPF: How to dynamically create a grid with x rows and y columns with consecutive numbers

I am completely new to wpf and c#, so excuse if this is super trivial question. I am trying to create a fairly simple control.
This grid will always have consecutive numbers, with a color rectangle in front of it. Clicking on the gray rectangle will change its color, and set the text to bold (I will deal with these triggers later).
For now, I just need to figure out how to create this control dynamically. When the program starts, it needs to one time create this control, and then the size won't change. I need to tell it the number of columns and rows (each column will probably always have 8 elements), and have it populate with consecutive numbers with specific font style/rectangle color.
I was experimented with creating a stackpanel UserControl for rectangle/label combo, passing the style to it, and then adding 32 of these UserControls in specific row/column in a grid. But I would need the size of that grid to be dynamic, so I need some for loop in the code I think.
Thanks!
I would start with an ItemsControl
You can give it a collection of items, and it will render each item however you want, displayed in any panel you want.
For example, you might have something like this
<ItemsControl ItemsSource="{Binding MyCollection}">
<!-- This panel will be used to hold the items -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="8" Columns="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- Each item will be drawn using this template -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Text="{Binding }" Style="{StaticResource MyButtonStyle}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The Rows and Columns property of the UniformGrid are DependencyProperties, so you could bind them to properties on the DataContext to make them dynamic.
The only problem with a UniformGrid is it only arranges items Horizontally. If you want to display them Vertically, you can either create a custom UniformGrid, or switch to a different panel such as a WrapPanel. If you are new to WPF Panels, I would recommend reading through WPF Layouts - A Quick Visual Start.
The ItemTemplate can be anything. Personally I would use a Button so you have the Click or Command behavior to handle that event, and just overwrite the Button's Template to look however you want. It is an easy task to include your Triggers in there too.
And if you wanted selection behavior, I would recommend switching from an ItemsControl to a ListBox, and overwriting that Template the same way, however it doesn't sound like you need it though, so I think an ItemsControl is better :)
I would try using a listview and change the template to the style you want to use for your elements.
To limit the number of items in a row you can use
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
That way you would always get 3 elements in a row, like
123
456
To make the 3 dynamic you can databind it to some value in your codebehind / viewmodel
to dynamically create the elements within the listview you can add objects to a list/observable collection and then add those to the listview via
listviewname.ItemSource=ListName;
Or however you like. They will get arranged according to how many columns you tell the grid to have. Adding 32 items (with uniform grid of 4) leads to
1 2 3 4
5 6 7 8
9 10 11 12
...
On your page you must create a "main" element, for example a Grid.
Give it a name, so that we can access it by code. Here I gave it the name of root
So you will have something like
<Page
... >
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
x:Name="root">
</Grid>
</Page>
Then, on the .cs file of this page you must create a function with the code below. You can call this function on the MainPage() function.
This loop will create one Grid column with dynamic Grid rows
// Create a Grid and add it to a component of your page
Grid mainGrid = new Grid();
root.Children.Add(mainGrid);
for (int i = 0; i < 8; i++)
{
// I am creating a Grid with a TextBlock inside,
// it will have the same apperance as a Rectangle,
// but this way you can have a Text inside
Grid g = new Grid();
TextBlock tb = new TextBlock();
tb.Text = i.ToString();
g.Children.Add(tb);
// Here you set the Grid properties, such as border and alignment
// You can add other properties and events you need
g.BorderThickness = new Thickness(1);
g.BorderBrush = new SolidColorBrush(Colors.Black);
g.HorizontalAlignment = HorizontalAlignment.Stretch;
g.VerticalAlignment = VerticalAlignment.Stretch;
// Add the newly created Grid to the outer Grid
mainGrid.RowDefinitions.Add(new RowDefinition());
mainGrid.Children.Add(g);
// Set the row of the Grid.
Grid.SetRow(g, i);
}
I used a Grid instead of a Rectangle since Rectangles can't have Children.
It must be easy to create the other columns as well, using the same logic that I used to create the Rows.
The solution to me was pretty like the ones above, but I had to bind the ItemsSource in the back code.
<!-- This panel will be used to hold the items -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- Each item will be drawn using this template -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--Here is the big deal I think. Desing your template according to what you need. In this case, a grid with 1 default row and column will work-->
<Grid>
<!--Reading object property called "Exchange" and setting its value into a text block-->
<TextBlock
Margin="10, 10, 10, 40" FontSize="16"
HorizontalAlignment="Center"
VerticalAlignment="Center" Foreground="GreenYellow" Text="{Binding Exchange}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
Then in the page.cs I did the binding right in the constructor. But you can bind anytime suits you
List<Bot> Bots = new()
{
new Bot
{
Exchange = "Binance"
},
new Bot
{
Exchange = "Kukoin"
}
};
ItemsControlName.ItemsSource = Bots; // I HAD to bind here. Could not make it work another way.
In my example, I have used a list of a simple class called Bot, with one single property called Exchange. Like this
public class Bot
{
public string Exchange { get; set; }
}
Then I got it:

xaml / c# stackpanel with background rectangle

I have a list (ListBox) of items in XAML using a StackPanel- based element template. The layout is fine, but I would now like to have a rectangle as a background for each item - creating a box around each one.
I was thinking of using a Canvas somehow, but as each item's height varies (as well as the height of the items inside the StackPanel), I'm not sure how to do it (I'm new to C#/XAML). What would be the best composition for the template in this situation?
You can just specify it in an ItemTemplate and it will do what you want, something like;
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderBrush="Red" BorderThickness="2" Background="Blue"/>
<!-- Insert the rest of your Item template stuff here -->
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
ListBox is a type of ItemsControl, which exposes several properties to control the appearance of the items. In this case, have a look at ItemContainerStyle (in the case of ListBox, the item containers are instances of ListBoxItem). You could, for instance, set the Background property in an ItemsContainerStyle to some color.

Storing and displaying a grid of buttons / multiple layouts

I am building a point of sale application using WPF with MVVM.
One of the features is that there will be a grid/panel on the screen with say for example 10 x 10 buttons, 1 button per stock item for example.
What I need to do is to allow the user to create a new layout or edit an existing layout where they can add a new button or remove a button etc..
So in theory the user can have a number of different layouts where they can select from to show on the screen.
Each of the buttons will be linked to a stock product in the database and will have properties like colour, text, image etc..
So I am thinking if I have a user control set to 10 x 10 buttons or use a Uniform Grid, I could bind to a collection of buttons. I was also thinking of storing each layout button for each layout as XML and reading this to create some kind of collection and binding that to the grid.
For example the user could at point have the choice of choosing between 10 different screen/ grid layouts, each layout having its own set of buttons which could be in different positions, or have different text etc..
My question is, is this the best approach to store the buttons and layouts as XML?
And how could i directly bind a grid/uniform grid to a collection of buttons?
Many thanks
Overall approach looks fine to me. As for binding button collection to grid, you can use ItemsControl with custom ItemsPanel template for this:
<ItemsControl ItemsSource="{Binding Buttons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="10" Columns="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button>
<!-- bind button color, content, etc -->
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Categories