I need to represent updatable list ObservableCollection<RegisterBean> listOfRegisters of objects RegisterBean as matrix with row and column headers Object contain 3 properties:
byte deviceAddress;
byte register;
byte[] data;
And only one property data should be displayed.
The expected result is like on image:
I reached this structure with usual datagrid but the problem was to update it because I used a converter with new DataTable() as a returned value. This is not correct because it flickers and rerenders all objects.
I asked for a help yesterday here. And this solution is working:
<ItemsControl ItemsSource="{Binding listOfRegisters}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="16"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Data, Converter={StaticResource ByteToStringValueConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But I didn't understand how to change the structure of usercontrol and to add headers. The result of the solution with itemscontrol:
Thanks!
UPD:
The headers should be static without any sorting and stuff like that
I start saying that probably, checking what's wrong with DataGrid would be better and that is not necessary to re-write Controls, but if you still want to use the ItemsControl ...
Supposing that there are two collections (ColHeaders & RowHeaders) in your ViewModel that contains your Headers you can add two other panels that hold headers..
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<!-- Column Headers -->
<ItemsControl Grid.Column="1" Grid.Row="0" ItemsSource="{Binding ColHeaders}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding}" Width="30" Height="30"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Grid.Row="1" Grid.Column="1" ItemsSource="{Binding listOfRegisters}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="16"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Data, Converter={StaticResource ByteToStringValueConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- RowHeaders -->
<ItemsControl Grid.Column="0" Grid.Row="1" ItemsSource="{Binding RowHeaders}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding}" Width="30" Height="30"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
I also sized the TextBlocks and the TextBoxes in order to align everything.
Just add a Grid around it, like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="Col 0"/>
<Label Grid.Column="1" Content="Col 1"/>
<Label Grid.Column="2" Content="Col 2"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Row 0"/>
<Label Grid.Row="1" Content="Row 1"/>
<Label Grid.Row="2" Content="Row 2"/>
</Grid>
<UniformGrid Rows="3" Columns="3" Grid.Column="1" Grid.Row="1">
<Button Content="00"/>
<Button Content="01"/>
<Button Content="02"/>
<Button Content="10"/>
<Button Content="11"/>
<Button Content="12"/>
<Button Content="20"/>
<Button Content="21"/>
<Button Content="22"/>
</UniformGrid>
</Grid>
Related
I am creating UWP application. There is a listview, with groups.
XAML code goes like this:
<Page.Resources>
<CollectionViewSource x:Name="ContactsCVS" IsSourceGrouped="True" />
<!-- When using x:Bind, you need to set x:DataType -->
<DataTemplate x:Name="ContactListViewTemplate" x:DataType="data:Contact">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Ellipse x:Name="Ellipse"
Grid.RowSpan="2"
Width ="32"
Height="32"
Margin="6"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Fill="LightGray"/>
<TextBlock Grid.Column="1"
Text="{x:Bind Name}"
x:Phase="1"
Style="{ThemeResource BaseTextBlockStyle}"
Margin="12,6,0,0"/>
<TextBlock Grid.Column="1"
Grid.Row="1"
Text="{x:Bind Position}"
x:Phase="2"
Style="{ThemeResource BodyTextBlockStyle}"
Margin="12,0,0,6"/>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{x:Bind ContactsCVS.View}"
ItemTemplate="{StaticResource ContactListViewTemplate}"
SelectionMode="Single"
ShowsScrollingPlaceholders="True"
Grid.Row="1"
Grid.ColumnSpan="2" x:Name="listViewMain">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate x:DataType="data:GroupInfoList">
<TextBlock Text="{x:Bind Key}"
/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</Grid>
And everything is ok, except that I want to make each group to have some kind of border. Like this:
How to achieve this?
As #Ken Tucker said, you can edit the GroupStyle and use GroupStyle.Panel property to add a border for each group. For example, using a GroupStyle like the following:
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate x:DataType="data:GroupInfoList">
<TextBlock Text="{x:Bind Key}"
Style="{ThemeResource TitleTextBlockStyle}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<StackPanel BorderBrush="Red" BorderThickness="1" Margin="8,0,18,0" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
However, you may find there is no effect with using this GroupStyle in your code. This is because GroupStyle.Panel can't work with UI virtualization. If the ListView uses a virtualizing panel such as ItemsWrapGrid or ItemsStackPanel, then GroupStyle.Panel won't have effect. And for ListView its default ItemsPanel is a ItemsStackPanel. So you will also need to change ListView's ItemsPanel like:
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
Then you should be able to see the border for each group. For more info, please refer to this case. And also please note that using GroupStyle.Panel might influence the performance as the lack of UI virtualization. You may consider whether to use this according to your real scenario.
My View displays the image as a first layer, than I display the bunch of the shapes (rectangles, lines, circles) over the image as a second layer.
The image has a scroller because it can't be fully displayed on my View.
The strange issue is enclosed in the fact, that the shapes are displayed over the scroller.
How can I fix it?
Here's my View:
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="500" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="500" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
<Image Source="{Binding VM.ManipulatedImage}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Stretch="None"
Width="Auto" Height="Auto"/>
</ScrollViewer>
<ItemsControl
ItemsSource="{Binding VM.Shapes, Mode=TwoWay}"
Grid.Row="0" Grid.Column="0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Path Data="{Binding Geometry}"
Fill="{Binding Fill}"
Stroke="{Binding Stroke}"
StrokeThickness="{Binding StrokeThickness}"
Opacity="{Binding Opacity}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Place the ScrollViewer around the Grid. The Grid is happy to have multiple children.
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="500" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="500" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Source="{Binding VM.ManipulatedImage}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Stretch="None"
Width="Auto" Height="Auto"/>
<ItemsControl
ItemsSource="{Binding VM.Shapes, Mode=TwoWay}"
Grid.Row="0" Grid.Column="0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Path Data="{Binding Geometry}"
Fill="{Binding Fill}"
Stroke="{Binding Stroke}"
StrokeThickness="{Binding StrokeThickness}"
Opacity="{Binding Opacity}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</ScrollViewer>
My StackPanel and ScrollViewer seem to just not end at the Grid.Row position. I am making a Metro app so it is mandatory for the grid to be dynamic, as well as all the elements.
The code:
<Grid Background="#FFE4E4E4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="0.5*"/>
</Grid.RowDefinitions>
<!--News/Leaderboard Feed-->
<StackPanel Grid.Column="0" Grid.Row="0">
</StackPanel>
<!--Marketplace Feed-->
<StackPanel Grid.Column="0" Grid.Row="1">
</StackPanel>
<!--Detailed Marketplace Account-->
<StackPanel Grid.Column="1" Grid.Row="1">
</StackPanel>
<!--Marketplace View-->
<StackPanel Grid.Column="1" Grid.Row="0" VerticalAlignment="Top">
<ScrollViewer VerticalAlignment="Top">
<!--Allows scrolling-->
<GridView x:Name="MarketplaceFeed" ItemsSource="{Binding StockList}" ItemTemplate="{StaticResource MarketplaceFeedTemplate}" VerticalAlignment="Top">
<!--Displays the stock markets the user is interested in.-->
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</ScrollViewer>
</StackPanel>
</Grid>
You should put the ScrollViewer on the outside. This will auto-fit to the grid, and anything inside it will get the scrolling treatment.
<!--Marketplace View-->
<ScrollViewer VerticalAlignment="Top" Grid.Column="1" Grid.Row="0">
<StackPanel VerticalAlignment="Top">
<!-- other content -->
</StackPanel>
</ScrollViewer>
I have a scenario where i have one control, which is using another control thru ListBox.ItemTemplate. I need to share Height and width between these 2 controls. How can we achieve that?
Main Conrol Xaml looks like as followings:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Text="{Binding Path=Caption,
Mode=OneWay}" />
<TextBlock Grid.Row="1"
Text="{Binding Path=Caption2,
Mode=OneWay}" />
</Grid>
<ListBox Grid.Row="0"
Grid.Column="1"
ItemsSource="{Binding Path=ViewModels}">
<ListBox.ItemTemplate>
<DataTemplate>
<Views:View2 />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
View2 xaml looks like as following:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0"
Grid.Column="0"
Text="{Binding Path=Value,
Mode=OneWay}"/>
<TextBlock Text="{Binding Path=Value2,
Mode=OneWay}"
Grid.Row="1"
Grid.Column="0"
/>
</Grid>
You can synchronize row height and column width using Grid.IsSharedSizeScope and the SharedSizeGroup attribute on ColumnDefinition and RowDefinition.
I'm not sure which elements you need to synchronize in your Xaml, but an example might be as follows:
Ia a parent element you use Grid.IsSharedSizeScope="True"
<Grid IsSharedSizeScope="true">
..
</Grid>
This synchronizes any columns (or rows) that have the same SharedSizeGroup within that scope (you can have multiple nested scopes).
So if your view.xaml looks like this
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="column1"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Path=Value, Mode=OneWay}"/>
<TextBlock Text="{Binding Path=Value2, Mode=OneWay}" Grid.Row="1" Grid.Column="0"/>
</Grid>
Then all the textblocks will have the same width.
I'm trying to make a WPF DataGrid show scrollbars when necessary.
You can see the basic XAML code of my user control below:
<Grid x:Name="Data" Grid.Column="0" VerticalAlignment="Stretch" Height="Auto" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Expander Header="Route Setup" Grid.Row="0" VerticalAlignment="Top" Background="White">
</Expander>
<Expander Header="Select Locations" Grid.Row="1" VerticalAlignment="Top" Background="White">
</Expander>
<DataGrid Grid.Row="2" ItemsSource="{Binding Locations, Mode=TwoWay}" Height="Auto" AutoGenerateColumns="False" ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
</DataGrid>
This isn't working, I don't see any scroolbars when the DataGrid grows beyond the available space. I've already tried to use a scrollview around my DataGrid but that doesn't change anything.
Update
It might be important to know that the usercontrol is loaded into the LeftRegion of a shell that has the following markup:
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions >
<ColumnDefinition Width="*" MinWidth="400" MaxWidth="600"/>
<ColumnDefinition Width="9" />
<ColumnDefinition Width="*" MinWidth="300" />
</Grid.ColumnDefinitions>
<GridSplitter x:Name="MainSplitter" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Grid.Column="1"
Margin="0" Width="9" Style="{DynamicResource gridSplitterVerticalStyle}"/>
<ItemsControl Name="LeftRegion" Grid.Column="0" Background="Azure" Height="Auto" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" cal:RegionManager.RegionName="LeftRegion">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl Name="RightRegion" Height="Auto" Background="DarkGreen" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" Grid.Column="2" cal:RegionManager.RegionName="RightRegion">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
Best Regards
Jay
In your grid named "Data", remove the Height="Auto" from the third RowDefinition. At least one row must have the "*" height (which is the default) to take the remaining available space.
Solved it. I needed to remove Height="Auto" from the thrird RowDefinition.