ScrollViewer not showing all content when canvas is scaled using ScaleTransform - c#

I have two Canvas panels in ScrollViewer. One is the main canvas which is having a grid shape drawn on its back ground. Then I have two ItemsControl. The first ItemsControl is having Stackpanel as its ItemsPanel with Horizontal Orientation. The second ItemsControl is having Canvas as its Panel. On this canvas I am drawing Line objects in DataTemplate of Itemscontrol.There is PreviewMouseWheel event on this canvas. In the event handler I am zooming this canvas which is zooming the Line objects. The width of this canvas is binded to ViewModel property CanvasWidth. Also this will change the width of Outer Canvas as its width is also binded to ViewModel Property CanvasWidth. When the PreviewMouseWheel is fired, I am adding more grid lines on main Canvas. I have TextBlock over them as DataTemplate of ItemsSource. Before zooing, the content of last TextBlock was 14260. After zoomin it should remain 14260. but the step value of two consecutive TextBlock should be reduced. Right now I am not able to see the whole content through ScrollViewer. The step size is reduced which was desired but the new grid lines which are drawn cannot be seen throught Scrollviewer. i know there is content. but I am unable to acces it. The scrollviewer is not showing it.
<Grid x:Name="grid1" >
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<ScrollViewer Name="scrollViewer" HorizontalScrollBarVisibility="Auto" Grid.Row="1" Grid.Column="3" Margin="10,10,0,10" >
<Canvas Name="back_canvas" Height="12000" Width="{Binding CanvasWidth}" Margin="0,0,10,0" >
<Canvas.Background>
<DrawingBrush TileMode="Tile" Viewport="0,0,40,40" ViewportUnits="Absolute">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,50,50"/>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Brush="Gray" Thickness="1"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Canvas.Background>
<ItemsControl ItemsSource="{Binding TimeAxis}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Margin="0,0,3,0" Width="37" Background="GreenYellow" >
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl ItemsSource="{Binding Lines}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Height="12000" Background="Transparent" Name="front_canvas"
PreviewMouseWheel="OnPreviewMouseWheel"
Width="{Binding CanvasWidth, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
</Line>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</ScrollViewer>
</Grid>
private void UpdateGraph(Canvas canvas, double deltaValue)
{
List<MarkerView> markers = new List<MarkerView>();
scaleFactor += deltaValue;
double tempScale = scaleFactor;
if (scaleFactor < 1.0)
{
scaleFactor = 1.0;
}
if (scaleFactor > maximumScale)
{
scaleFactor = maximumScale;
}
if (tempScale > 0)
{
totalSamples = graphVM.maxSignalLength;
maximumCanvasWidth = totalSamples * maximumDeltaDistance;
if(scaleFactor<=maximumDeltaDistance)
{
ScaleTransform scaleTransform = new ScaleTransform(scaleFactor, 1);
canvas.RenderTransform = scaleTransform;
verticalLines.ForEach(x =>
{
x.RenderTransformOrigin = new Point(1, 1);
x.RenderTransform = new ScaleTransform(1 / scaleTransform.ScaleX, 1 / scaleTransform.ScaleY);
});
if (deltaValue < 0)
{
graphVM.CanvasWidth = graphVM.InitialCanvasWidth * tempScale;
}
else
{
if (graphVM.InitialCanvasWidth * scaleFactor > maximumCanvasWidth)
graphVM.CanvasWidth = maximumCanvasWidth;
else
graphVM.CanvasWidth = graphVM.InitialCanvasWidth * scaleFactor;
}
graphVM.ResetLabels();
DeltaDistance = canvas.Width / totalSamples;
MarkerView markerRed =
UIHelperView.FindChild<MarkerView>(Application.Current.MainWindow, "splitterRed");
MarkerView markerGreen =
UIHelperView.FindChild<MarkerView>(Application.Current.MainWindow, "splitterGreen");
markers.Add(markerRed);
markers.Add(markerGreen);
// Move Markers with zooming
foreach (MarkerView marker in markers)
{
marker.Delta = DeltaDistance; // after zooming if you move the marker then this value will be used to get correct position
Canvas.SetLeft(marker, marker.XPosition * DeltaDistance);
}
markers.Clear();
}
}
}
here is the output picture https://imgur.com/a/7WTrBoc
this is zoomed output https://imgur.com/C7SCOSJ

RenderTransform doesn't affect ActualWidth/Height of the control. Try using LayoutTransform instead.

Related

How to curve listbox and its scrollbar in WPF .NET 5.0

fellow programmers!
I just started to learn WPF and as part of my first projects I am trying to create 2 curved carousel listboxes near a center circle on both sides. Using custom panel in listbox I managed to get this result:
<Grid Margin="7" Height="450">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="300"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Viewbox Grid.Column="1" Margin="20 0 20 0" PreviewMouseDown="Viewbox_PreviewMouseDown" Style="{StaticResource MainOption}">
<Grid Width="230" Height="230" >
<Ellipse Width="230" Height="230" Stroke="{StaticResource PrimaryDarkColor}" StrokeThickness="2" Fill="Transparent" />
<!--<Ellipse Width="200" Height="200">
<Ellipse.Fill>
<ImageBrush ImageSource="/Assets/Profile.ico" />
</Ellipse.Fill>
</Ellipse>-->
<md:PackIcon Kind="Map" Foreground="White" Width="180" Height="180" Margin="25 10 0 0" />
<TextBlock Text="Map" HorizontalAlignment="Center" VerticalAlignment="Bottom" Foreground="White" Margin="0 0 0 30" Style="{StaticResource MenuItem}"/>
</Grid>
</Viewbox>
<ListView Grid.Column="0" ItemsSource="{Binding LeftMenuItems}" Height="360" FlowDirection="RightToLeft" ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<cc:CurvedPanel RadiusX="70"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<!--<Button Content="{Binding Text}" Width="100" Command="{Binding OpenCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" CommandParameter="{Binding Window}"/>-->
<TextBlock Text="{Binding Text}" Style="{StaticResource MenuItem}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView Grid.Column="2" ItemsSource="{Binding RightMenuItems}" Height="360" ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<cc:CurvedPanel RadiusX="90" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<!--<Button Content="{Binding Text}" Width="100" Command="{Binding OpenCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" CommandParameter="{Binding Window}"/>-->
<TextBlock Text="{Binding Text}" Style="{StaticResource MenuItem}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
public class CurvedPanel : StackPanel
{
public double RadiusX { get; set; }
protected override Size MeasureOverride(Size availableSize)
{
return base.MeasureOverride(availableSize);
}
protected override Size ArrangeOverride(Size finalSize)
{
double angle = 80, centerX = 0, centerY = finalSize.Height / 2, decrement = 20, radiusY = centerY * 0.8, radiusX = 70;
Point prevPoint = new Point(0, 0);
if (Children.Count > 0)
{
foreach (UIElement child in Children)
{
var angleInRadians = AngleToRadian(angle);
Point childPosition = new Point(radiusX * Math.Cos(angleInRadians), radiusY * -Math.Sin(angleInRadians) + radiusY);
child.Arrange(new Rect(new Point(childPosition.X, childPosition.Y), new Size(finalSize.Width, child.DesiredSize.Height)));
angle -= decrement;
}
}
return finalSize;
}
private double AngleToRadian(double angle)
{
return angle * (Math.PI / 180);
}
}
But this is far from ideal, because (as image shows) items overlap. Probably because it doesn't account for item's size itself. I want to prevent this overlapping, but can't figure out changes that need to be implemented.
Plus I want to make curved scrollbar, which when scrolling will scroll along curved path. But I have no idea how to do this.
I heard there was once PahtListBox, which could accomplish what I need, but I don't think this is available in core.
Any help will be greatly appreciated!

How to dynamically change grid rows and columns according to window size in WPF

I'm making an image gallery of sorts, and I'm currently loading the images into a grid dynamically via C#. If I shouldn't be using a grid to display the images, I'm more than willing to change it to a better-suited control, but it needs to be window-resizing-friendly.
When I resize the window, I want the following things to happen:
The images all stay the exact same size. They already fit into the grid slots while maintaining their aspect ratio
The grid spaces themselves are also not resized at all
The grid contains more or less rows/columns depending on how many can fit into the window.
This would mean that, if the window was resized to be very thin and very high, the grid would contain one column (or two, or however many are needed) and many rows to display the images in.
If it was very wide, but not high, then it would only have one (or two, or however many are needed) row(s) and many columns. Etc.
Not sure if it's needed but my code to display the images is:
for (int i = 0; i < ImageGrid.RowDefinitions.Count; i++)
{
for (int j = 0; j < ImageGrid.ColumnDefinitions.Count; j++)
{
Image img = new Image();
BitmapImage bitmap = new BitmapImage();
using (var fs = new FileStream(path, FileMode.Open)) // open the image
{
bitmap.BeginInit();
bitmap.StreamSource = fs;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
}
bitmap.Freeze(); // bitmap isn't properly cleaned up and memory leaks can occur if this isn't here
img.Source = bitmap;
img.Margin = new Thickness(10);
img.Stretch = Stretch.Uniform;
Grid.SetRow(img, i);
Grid.SetColumn(img, j);
ImageGrid.Children.Add(img);
}
}
And my XAML for the grid is:
<Grid ShowGridLines="True" Background="DimGray">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="175" Width="0"/>
<ColumnDefinition MinWidth="755" Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Name="lblWinSize" Content="Width, Height"
HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
<TextBox Name="txtnbox" Style="{StaticResource CustomTxtBox}"
TextWrapping="NoWrap" Width="Auto" Height="25" VerticalAlignment="Top"
Margin="10, 20, 10, 0"/>
<Separator Style="{StaticResource VerticalSeparator}"
HorizontalAlignment="Right" Height="Auto" Width="2" Margin="0,10,0,10"/>
<CheckBox Style="{StaticResource CustomCheckBox}"
HorizontalAlignment="Left" Margin="10,50,0,0" VerticalAlignment="Top"/>
<Grid Name="ImageGrid" Grid.Column="1" Margin="10,10,0,10"
ShowGridLines="True" Background="Gray">
<!--this is the grid where the images would go-->
</Grid>
</Grid>
Sorry about the indentation with that XAML, I couldn't get it to format right.
The rows/columns are defined elsewhere in the code, but I don't think I need to paste that considering it'll be replaced.
Again, if some other control is better suited, I can change to that.
You will want to use a wrap panel.
<WrapPanel Orientation="Horizontal">
<Image Width="50" Height="50" Source="bla.png" />
<Image Width="50" Height="50" Source="bla.png" />
<Image Width="50" Height="50" Source="bla.png" />
<Image Width="50" Height="50" Source="bla.png" />
</WrapPanel>
Use a WrapPanel to make layout of items fill the width of the window before adding a new row, inside of a ScrollViewer to allow scrolling vertically so the contents don't run out of viewable area.
<ScrollViewer>
<WrapPanel HorizontalAlignment="Center">
<!-- your items go here -->
</WrapPanel>
</ScrollViewer>
If your images are being added dynamically, hopefully you're adding them to a collection that your view can bind to instead of directly adding them to the view in your codebehind... Use an ItemsControl and define your own template for items and container:
<ScrollViewer>
<ItemsControl ItemsSource="{Binding Images}" HorizontalAlignment="Center">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding ...}" Height="150" Width="150"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
c# :
// here set number of images you want to parse
int qtyOfImages = 10;
for (int i = 0; i < qtyOfImages; i++) {
Image img = new Image();
BitmapImage bitmap = new BitmapImage();
using (var fs = new FileStream(path, FileMode.Open)) // open the image
{
bitmap.BeginInit();
bitmap.StreamSource = fs;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
}
bitmap.Freeze(); // bitmap isn't properly cleaned up and memory leaks can occur if this isn't here
img.Source = bitmap;
img.Margin = new Thickness(10);
img.Stretch = Stretch.Uniform;
//Grid.SetRow(img, i);
//Grid.SetColumn(img, j);
// set width and height so the images stay at the same size
img.Width = 300;
img.Height = 300;
ImageGrid.Children.Add(img);
}
while your xaml would be like:
<Grid ShowGridLines="True" Background="DimGray">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="175" Width="0"/>
<ColumnDefinition MinWidth="755" Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Name="lblWinSize" Content="Width, Height"
HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
<TextBox Name="txtnbox" Style="{StaticResource CustomTxtBox}"
TextWrapping="NoWrap" Width="Auto" Height="25" VerticalAlignment="Top"
Margin="10, 20, 10, 0"/>
<Separator Style="{StaticResource VerticalSeparator}"
HorizontalAlignment="Right" Height="Auto" Width="2" Margin="0,10,0,10"/>
<CheckBox Style="{StaticResource CustomCheckBox}"
HorizontalAlignment="Left" Margin="10,50,0,0" VerticalAlignment="Top"/>
<!--<Grid Name="ImageGrid" Grid.Column="1" Margin="10,10,0,10"
ShowGridLines="True" Background="Gray">
--><!--this is the grid where the images would go--><!--
</Grid>-->
<!-- set size of wrap panel to your window acutal width -->
<WrapPanel Orientation="Horizontal" Name="ImageGrid" Width="{Binding ElementName=Window, Path=ActualWidth}">
</WrapPanel>
</Grid>
dont forget to put Name="Window" at your window for this code to work
Hope that helps

Is there any control for auto resize items inside

is there any control that can auto resize items inside. I need to contain textblocks inside ItemsControl only in one row, so if total items width larger then container.Width, it will change each item's width. UWP
<ItemsControl Grid.Column="1"
ItemsSource="{Binding Path=NavigationHistory, ElementName=Main, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
x:Name="BroadComb"
MaxHeight="24"
Margin="10,0,0,0" VerticalAlignment="Center" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<HyperlinkButton Command="{Binding Path=NavigateCommand, ElementName=Main}" CommandParameter="{Binding}" Margin="10,0,0,0" Foreground="{ThemeResource AppAccentForegroundLowBrush}" >
<HyperlinkButton.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
TextTrimming="None"
Text="{Binding Path=DisplayName}"
FontSize="10"
FontWeight="Bold"
Foreground="{ThemeResource AppAccentForegroundLowBrush}">
<i:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{Binding Path=CanBeTrim}" Value="True">
<core:ChangePropertyAction PropertyName="TextTrimming" Value="WordEllipsis"/>
</core:DataTriggerBehavior>
<core:DataTriggerBehavior Binding="{Binding Path=CanBeTrim}" Value="False">
<core:ChangePropertyAction PropertyName="TextTrimming" Value="None"/>
</core:DataTriggerBehavior>
</i:Interaction.Behaviors>
</TextBlock>
<FontIcon Margin="10,0,0,0" HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="ms-appx:/Assets/Fonts/MyBook-Regular.ttf#MyBook"
FontSize="10"
Glyph="2" Foreground="{ThemeResource AppAccentForegroundLowBrush}" />
</StackPanel>
</DataTemplate>
</HyperlinkButton.ContentTemplate>
</HyperlinkButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
One possibility is to use a Grid with your desired controls in it's columns set to HorizontalAlignment="Stretch":
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="abc" HorizontalAlignment="Stretch" />
<TextBlock Grid.Column="1" Text="xyz" HorizontalAlignment="Stretch" />
</Grid>
This will stretch both controls over the maximum available width according to the Grid's container and make them smaller or bigger if the available space changes.
Most of the time, you will only want to set one column to fill the available space (Width="*") and set the other columns to a fixed or relative width. You can experiment with those settings.
Else we would need a more exact specification of what you want to achieve.
is there any control that can auto resize items inside. I need to contain textblocks inside ItemsControl only in one row, so if total items width larger then container.Width, it will change each item's width. UWP
What you need is to change the default ItemsPanel of GridView. You can create your own Custom Panel to let the texts be arranged in only one row:
Create your own custom Panel OneRowPanel.cs:
public class OneRowPanel:Panel
{
double itemHeight=0;
protected override Size MeasureOverride(Size availableSize)
{
int count = Children.Count;
foreach (FrameworkElement child in Children)
{
child.Measure(new Size(availableSize.Width/count,availableSize.Height));
if (child.DesiredSize.Height > itemHeight)
{
itemHeight = child.DesiredSize.Height;
};
}
// return the size available to the whole panel
return new Size(availableSize.Width, itemHeight);
}
protected override Size ArrangeOverride(Size finalSize)
{
// Get the collection of children
UIElementCollection mychildren = Children;
// Get total number of children
int count = mychildren.Count;
// Arrange children
int i;
for (i = 0; i < count; i++)
{
//get the item Origin Point
Point cellOrigin = new Point(finalSize.Width / count * i,0);
// Arrange child
// Get desired height and width. This will not be larger than 100x100 as set in MeasureOverride.
double dw = mychildren[i].DesiredSize.Width;
double dh = mychildren[i].DesiredSize.Height;
mychildren[i].Arrange(new Rect(cellOrigin.X, cellOrigin.Y, dw, dh));
}
// Return final size of the panel
return new Size(finalSize.Width, itemHeight);
}
}
Use it in your Xaml and set the TextBlock.TextTrimming to CharacterEllipsis:
<Page
x:Class="AutoResizeItemsSample.MainPage"
...
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="TextTemplate">
<TextBlock Text="{Binding Text}" TextTrimming="CharacterEllipsis">
</TextBlock>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Name="rootPanel">
<GridView Name="gridView" ItemTemplate="{StaticResource TextTemplate}" >
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:OneRowPanel ></local:OneRowPanel>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</StackPanel>
</Grid>
</Page>
Here is the Result:
Here is the complete demo:AutoResizeItemsSample.
Solve this easily with ListView. The ItemsPanel is already a StackPanel and the individual item will resize as needed. If you need the horizontal width of each item to be different, that's supported out of the box, too. I think the solution is to simply choose the ListView control.

Canvas oversteps it's grid-row limits

I put a canvas into a row of a grid-layout. The canvas doesn't except any maxhight limits of the canvas itself neither of the row-height limits. It just fills the entire user-controll.
I have this layout inside a grid:
<DockPanel Grid.Row="1" MaxHeight="32">
<StackPanel DockPanel.Dock="Right">...</StackPanel>
<Grid DockPanel.Dock="Left" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition MaxHeight="12" Height="12" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Canvas Grid.Row="0" VerticalAlignment="Stretch" SizeChanged="canvasBar_SizeChanged" Loaded="Canvas_Loaded">
...
</Canvas>
<Image Grid.Row="1">...</Image>
</Grid>
</DockPanel>
If I put another image instead of the canvas, it doesn't fill the entire user-control, but the canvas fills it. Am I missing any parameters here?
Edit:
SizeChanged and Loaded both trigger this function to draw rectangles:
Rectangle r = new Rectangle();
r.Height = canvasBar.ActualHeight;
r.Width = Rectwidth;
r.RadiusX = 1;
r.RadiusY = 1;
r.Margin = new Thickness(RecOffset, 0, 0, 0);
RecOffset += RectWidth + RectLimiterWidth;
r.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0));
r.StrokeThickness = 1;
r.Fill = new SolidColorBrush(LastBrcColor);
canvasBar.Children.Add(r);
Canvas does not clip the content of its child elements to its bounds by default. You need to set the ClipToBounds property to true:
<Canvas ClipToBounds="True" ...>
...
</Canvas>

Unable to change background colour for new button

I am using XAML and MVVM pattern for an application.
In part of my application I have a window split into 2 parts, a left column and right hand column/area
In the left column are a row of buttons ( generated on loading the window )
The right column/area will display a group of buttons depending on which button the user clicks in the left column, so for example say I have 4 department buttons in the left column, each department button will have a different number of stock items.
If I click button 1 in the left column, I do some code in the viewmodel to fetch the names of items in that department. And then I build a new observableCollection to display in the right column/area.
So this isnt a problem, the right amount of buttons get generated each time ok.
However when I try to change the background colour dynamically in the ViewModel, the colour is NOT upodated in the view.
The strange thing is, I can change the content, forecolour and other properties but just not the background colour. It appears the background will only generate correctly if loaded and run time. I cant change it otherwise while using the window.
I have tried Brushes, creating and assigning new style and even clearing the dependancy property of the button ( .ClearValue(Button.BackgroundProperty) )
Would any one know how i can get the background to change colour while the window is open and when i want to generate a set of buttons dynamically in my viewmodel?
Many thanks all... I have attached my XAML and C# snippet, the
XAML :
<dxd:DockLayoutManager Name="dlSalesScreen">
<dxd:DockLayoutManager.LayoutRoot>
<dxd:LayoutGroup Name="Root" Orientation="Horizontal" AllowSplitters="False">
<dxd:LayoutPanel AllowClose="False" AllowRename="False"
Caption="Departments" HorizontalScrollBarVisibility="Hidden"
CaptionAlignMode="AutoSize"
CaptionImageLocation="BeforeText" ShowPinButton="False" >
<!-- Scrollviewer for department buttons-->
<ScrollViewer x:Name="deptScrollviewer" Grid.Row="0" Grid.Column="0" Width="185" Height="Auto" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" PanningMode="VerticalOnly">
<ItemsControl ItemsSource="{Binding Departments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel VerticalAlignment="Top" Height="Auto" Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</dxd:LayoutPanel>
<dxd:LayoutPanel AllowClose="False" AllowRename="False"
Caption="Available stock in department" Width="Auto"
CaptionAlignMode="AutoSize"
CaptionImageLocation="BeforeText" ShowPinButton="False">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<!-- Scrollviewer for stock buttons-->
<ScrollViewer x:Name="stockScrollViewer" Grid.Row="0" Width="Auto" Height="Auto" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" PanningMode="VerticalOnly">
<ItemsControl ItemsSource="{Binding StockItems, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel VerticalAlignment="Top" HorizontalAlignment="Left" Orientation="Horizontal" Width="400" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
<Rectangle Grid.Row="1" Margin="0,0,0,0" Height="Auto" Fill="{StaticResource BottomRectangleGradient}" />
<Grid Name="gridButtonHolder" Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<GroupBox x:Name="grpStockItem" Grid.Column="0" Header="Selected Item" HorizontalAlignment="Left" Width="200" >
<Label x:Name="lblStockName" Content="{Binding SelectedStockItemLabel}" HorizontalAlignment="Left" />
</GroupBox>
<Button Name="btnSave" Content="Apply" Command="{Binding ConfirmSelectionCommand}" dxc:ThemeManager.ThemeName="Office2007Blue" Grid.Column="1" Width="110" Height="42" Margin="0,8,0,0" />
<Button Name="btnClose" Content="Cancel" dxc:ThemeManager.ThemeName="Office2007Blue" Grid.Column="2" Width="110" Height="42" Margin="0,8,0,0" />
</Grid>
</Grid>
</dxd:LayoutPanel>
</dxd:LayoutGroup>
</dxd:DockLayoutManager.LayoutRoot>
</dxd:DockLayoutManager>
C#
void DeptClicked(object sender, RoutedEventArgs e)
{
SelectedDeptID = Convert.ToInt32(((Button)sender).Tag.ToString());
_stockButtons = new ObservableCollection<Button>();
if (StockItemCount > 0)
{
for (int i = 0; i < StockItemCount; i++)
{
//_stockButtons.Add(new Button());
Button btn = new Button();
btn.Background = Brushes.Aquamarine;
btn.Height = 100;
btn.Width = 100;
btn.Content = i.ToString();
_stockButtons.Add(btn);
}
}
RaisePropertyChanged("StockItems");
}
public ObservableCollection<Button> Departments
{
get
{
if (_deptButtons == null)
{
_deptButtons = new ObservableCollection<Button>();
for (int i = 0; i < DeptCount; i++)
{
Button button = new Button();
button.Content = DepartmentNames[i];
button.Tag = DepartmentIDs[i].ToString();
button.Click += new RoutedEventHandler(DeptClicked);
button.Width = 128;
button.Height = 100;
_deptButtons.Add(button);
}
}
return _deptButtons;
}
}
Try something like that:
Button btn = new Button();
btn.Background = Brushes.Green;
btn.Height = 100; btn.Width = 100;
btn.Content = i.ToString();
ThemeManager.SetThemeName(btn, "None");
_stockButtons.Add(btn);
Class ThemeMagager is in namespace DevExpress.Xpf.Core.

Categories