I am trying to bing a grid size (i.e. Width and Height) to one of its child (i.e. a Viewbox). I tried this :
Binding bind = new Binding();
bind.Source = this._vb;
this._container.SetBinding(Grid.DataContextProperty, bind);
But it did not work as expected so I tried this
Binding bindWidth = new Binding();
bindWidth.Source = this._vb.Width;
this._container.SetBinding(Grid.WidthProperty, bindWidth);
Binding bindHeight = new Binding();
bindHeight.Source = this._vb.Height;
this._container.SetBinding(Grid.HeightProperty, bindHeight);
I wanted to zoom the Viewbox to have its child zoomed as well and update the Grid parent of my Viewbox. I also tried to do the opposite way (zoom the grid binded to my viewbox but it did not work).
Does someone know why it happens ?
Width an Height properties to guide the calculation of Width and Height. Try binding to ActualWidth/ActualHeight instead.
var binding = new Binding("ActualHeight");
binding.Source = this._vb;
this._container.SetBinding("Height", binding);
This will update the Height property on the _container to match the ActualHeight of the _vb object.
Related
I have a custom object of type "Module", where I store an Image and a Name. These objects are stored in a ListView, where I drag and drop them onto a Canvas, so I can arrange them (Kind of like a puzzle). First, I just drew the Image:
var module = e.Data.GetData("MyFormat") as Module;
Canvas CanvasView = sender as Canvas;
Image image = new Image();
image.Source = module.ModuleImage;
Point enterPoint = e.GetPosition(this.moduleCanvas);
Point PointToDraw = new Point(0, 0);
PointToDraw.X = enterPoint.X - DropPosition.X;
PointToDraw.Y = enterPoint.Y - DropPosition.Y;
//+35 and +43 so the Module gets dropped in the way you picked it up
image.SetValue(Canvas.LeftProperty, PointToDraw.X + 35);
image.SetValue(Canvas.TopProperty, PointToDraw.Y + 43);
CanvasView.Children.Add(image);
But then I realized, I need an Object on the canvas, not just an image, so I tried this:
ListViewItem lvitem = new ListViewItem();
var module = e.Data.GetData("MyFormat") as Module;
Canvas CanvasView = sender as Canvas;
lvitem.Content = module;
CanvasView.Children.Add(lvitem);
But this won't render the Image on the canvas of course. It just tells me MyNamespace.Module. How can I make the Canvas render the Image of the object, the ListViewItem contains?
If the Image property of your Module class returns an actual Image element, you could set the Content property to this one:
lvitem.Content = module.Image;
If Image returns a path, you could set the Content property to a ContentControl with a ContentTemplate that you may create programmatically using either a FrameworkElementFactory or XamlReader.Parse. In the ContentTemplate, you define the Image element:
ContentControl cc = new ContentControl();
cc.Content = new LongTextConverter();
FrameworkElementFactory frameworkElementFactory = new FrameworkElementFactory(typeof(Image));
frameworkElementFactory.SetBinding(Image.SourceProperty, new Binding("Image"));
cc.ContentTemplate = new DataTemplate() { VisualTree = frameworkElementFactory };
lvitem.Content = cc;
Or use a ListView with a Canvas as the ItemsPanel. See this answer for an example. You could then set the ItemsSource of the ListView to an IEnumerable<Module> and define an ItemTemplate that will be applied to each Module.
I'm currently trying to create a visual component to have scrolling text (left to right and right to left) - pretty much an html marquee.
I have a grid divided in several columns & rows, and I want to place my component inside one of the grid slots.
The grid (named UIGrid) is generated like this :
for (int i = 0; i < xDivisions; i++)
{
ColumnDefinition newColumn = new ColumnDefinition();
UIGrid.ColumnDefinitions.Add(newColumn);
}
for (int i = 0; i < yDivisions; i++)
{
RowDefinition newRow = new RowDefinition();
UIGrid.RowDefinitions.Add(newRow);
}
The component I'm adding is just a border with a textblock as a child. I place the border inside the Grid like this :
border = new Border();
Grid.SetColumn(border, xPosition);
Grid.SetRow(border, yPosition);
textBlock = new TextBlock();
border.Child = textBlock;
textBlock.Text = "Scrolling text from left to right";
UIGrid.Children.Add(border);
I'm using a timer to increment the textblock margin, here's the timer callback simplified body :
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
double textWidth = textBlock.DesiredSize.Width;
double visibleWidth = componentBase.ActualWidth;
double targetMargin = textWidth < visibleWidth ? visibleWidth : textWidth;
if (margin.Left == targetMargin)
{
margin.Left = -textWidth;
} else
{
margin.Left++;
}
When the text slides from left to right, it behaves nicely :
https://s10.postimg.org/p0nt7vl09/text_good.png
Text "leaving" the grid slot is hidden.
However, when I set the textblock's margin as negative so it may come back inside the viewable area from the left, the text is visible even though it's outside its allocated slot :
https://s10.postimg.org/pownqtjq1/text_bad.png
I've tried using padding instead, but I can't set a negative padding. I've tried a few other things, but I feel like I've encountered a roadblock.
What could I do to get a nicely scrolling text ?
If you want nicely scrolling text ListView might be a better option. It is dynamic and you can bind it to your object. It would take a lot of this guess work out.
Ed Plunkett led me in the right direction with the Clip property. The idea is to do this :
border.Clip = new RectangleGeometry
{
Rect = new Rect(0, 0, border.ActualWidth, border.ActualHeight)
};
Of course, that doesn't work if the border hasn't been rendered yet (and of course it isn't when my code is running). You can force the measurement to take place using 'Measure' as I did to measure the text length in pixels, but it behaved strangely on my border. I wouldn't get the correct size at all.
In the end, I simply subscribed to the border's SizeChanged event :
border.SizeChanged += OnSizeComputed;
When that event is fired, I create the RectangleGeometry using ActualWidth & ActualHeight.
I have a Canvas named mainCanvas and I'm programatically adding a ScrollViewer and a StackPanel to it in order of
...mainCanvas
......scrollView
.........pnl
............ (more stacked controls)
I'm attempting to get my StackPanel to auto size to the mainCanvas size and allow scrolling when it's too large. Code so far is below
mainCanvas.Children.Clear();
// Create the container
ScrollViewer scrollView = new ScrollViewer();
scrollView.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
scrollView.CanContentScroll = true;
scrollView.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
scrollView.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
StackPanel pnl = new StackPanel();
//pnl.Height = 500; //Works and allows scrolling but doesn't resize
pnl.Height = Double.NaN; //(Double.NaN is Auto) Doesn't Work - StackPanel overflows parent window
pnl.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
pnl.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
scrollView.Content = pnl;
// Add the ScrollView and StackPanel to Parent Window
mainCanvas.Children.Add(scrollView);
Unfortunately, the StackPanel doesn't fit to the parent and doesn't autosize.
mainCanvas already exists in XAML with settings:
Width= "Auto"
Height= "Auto"
HorizontalAlignment = "Stretch"
VerticalAlignment = "Stretch"
I can get things semi-working by using pnl.Height = 500; which shows me the scrollbar does work if the Stackpanel height is restricted. But this is just manually fitting the height to the full screen size and so doesn't autosize when resizing the app.
I hoped setting pnl.Height = Double.NaN; to auto and V/H adjustment to Stretch would work but the StackPanel still overlaps all controls to it's maximum size.
Can anyone point me in the right direction to get my StackPanel to fit the parent mainCanvas and autosize when I resize either the parent and/or the main app window with scrolling?
Thank you
I believe Canvas is for absolute positioning only. Using a Grid as your panel instead would probably give you the desired result.
The StackPanel won't stretch to fill its container, as you noticed. But you can bind its MinWidth and MinHeight properties to its container's width/height.
// give the canvas a name, so you can bind to it
mainCanvas.Name = "canvas";
// create the binding for the Canvas's "ActualHeight" property
var binding = new System.Windows.Data.Binding();
binding.ElementName = "canvas";
binding.Path = new PropertyPath("ActualHeight");
// assign the binding to the StackPanel's "MinHeight" dependency property
sp.SetBinding(StackPanel.MinHeightProperty, binding);
TextBlock tbl= new TextBlock();
tbl.text="Kishore";
double x=tbl.ActualHeight;
double y=tbl.ActualWidth;
If i execute the code from the loaded event in Metro - winRT will return 0 for both.
How can I get the ActualWidth in the Loaded or SizeChanged event?
Call Measure() then Arrange() and then ActualWidth and ActualHeight will be updated.
Can also do this via
UpdateLayout();
testBlock.ActualWidth
This could be useful when calculating multiple objects heights and widths.
TextBlock tbl = new TextBlock();
tbl.Text = "Kishore";
tbl.Measure(new Size(0, 0));
double x = tbl.ActualHeight;
I'm creating a scrollbar in codebehind like so:
ScrollBar b = new ScrollBar();
Grid ScrollbarGrid = GetTemplateChild( "ScrollbarGrid" ) as Grid;
b.Orientation = Orientation.Horizontal;
ScrollbarGrid.Children.Add(b);
What I need is for the scrollbar handle to be of a size I set myself if that is at all possible?
You can use ViewportSize
like b.ViewportSize = 5;
take a look at here for more information.
and MSDN's Track Class how thumb size calculates
You can set the Height and Width property of the scroll bar, is this what you need ?