i am trying to put a end-user license agreement (EULA) into a WP7 silverlight textblock control. however, it keeps truncating my text. why is this happening? is there a limit on the text size or number of characters a WP7 silverlight textblock can hold?
below is an example of what i've done in terms of xaml (the rest of the xaml surrounding is the default that is auto-generated).
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ScrollViewer>
<TextBlock x:Name="tbMsg" TextWrapping="Wrap"/>
</ScrollViewer>
</Grid>
i've also tried using a TextBox, but now, i can't even scroll within the TextBox. i've explicitly set the VerticalScrollBarVisibility to Visible too, but i still can't scroll down the TextBox. in fact, i don't even see the vertical scroll bar. i don't know if this observation is because i'm still viewing the UI via the emulator.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox x:Name="tbMsg" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/>
</Grid>
No UIElement can be larger than 2048 pixels in either direction (height or width). Any content which would be displayed beyond this area isn't displayed. Space for where this content would be is reserved within the visual tree though.
The work around for this is to use multiple elements to display large amounts of text.
Update
I've written my own parsers for dynaically displaying content of this sort. Ideally though you won't be working with large blocks of text at runtime though. This can be further complicated when the text contains links (to other pages, web content or email launchers).
When wanting to display EULAs or any large piece of text, you won't want to make it easy for the user to read and navigate. Afterall you are including the text as you want the user to read it.
If you have the text at design time you should take the opportunity to ensure that it is laid out appropriately and using separate TextBlocks for different sections and styling headings and sub-headings appropriately can help you do this.
It could be several things - the height of your textblock may be being constrained by another control, a style you have applied to the text may be causing it...
Can you post your source?
I want to share with you this code. It creates a number of TextBlocks and add as children to Stackpanel. You can create a Stackpanel inside your Scroll viewer since Scrollvewers can only take a single child element directly.
//constructor
List<char> countStoryvar = new List<char>(); //to store the text Body
private string incStorybody;
private int textMax = 2000; //You can modify this.
//methods
private void PlaceData()
{
incStorybody = "Your Story Source";
int countStory = incStorybody.Count();
countStoryvar = incStorybody.ToList();
double countStoryd = double.Parse(countStory.ToString());
if (countStoryd < textMax)
{
TextBlock txtBlock = new TextBlock();
txtBlock.TextWrapping = TextWrapping.Wrap;
readStackPanel.Children.Add(txtBlock);
}
else
{
double countStoryd2 = countStoryd / textMax; //fetch divisions
countStoryd2 = Math.Round(countStoryd2, 5); //getting Real no
string sountstring = countStoryd2.ToString();
string[] split = sountstring.Split(new string[] { "." }, StringSplitOptions.None); //to remove decimal
int countStoryi = int.Parse(split[0]);
int remainder = countStory - (textMax * countStoryi);
int iterationtimestin = countStoryi + 1;
for (int z = 0; z < iterationtimestin; z++)
{
int zlast = countStoryi - 1;
int multiple = 0;
int multiple1 = 0;
int multiplecounter = 0;
multiple = textMax * z;
if (z == 0)
{
multiplecounter = textMax;
}
else
{
if (z == countStoryi)
{
multiplecounter = countStory;
}
else
{
multiple1 = z + 1;
multiplecounter = textMax * multiple1;
}
}
LoadStackPanel(multiple, multiplecounter);
}
}
}
private void LoadStackPanel(int starting, int ending)
{
TextBlock txtBlock = new TextBlock();
txtBlock.TextWrapping = TextWrapping.Wrap;
for (int zi = starting; zi < ending; zi++)
{
incStoryInput = incStoryInput + countStoryvar[zi];
}
txtBlock.Text = incStoryInput;
readStackPanel.Children.Add(txtBlock);
incStoryInput = string.Empty;
}
Related
I am loading a large number of images, say 250+ and getting this Out of memory exception.
My Code:
while (kount < imageItems.Count)
{
for (int i = 0; i < _grid.RowDefinitions.Count; i++)
{
BitmapImage bit=null;
for (int j = 0; j < _grid.ColumnDefinitions.Count; j++)
{
imgGrd = new Image();
bit = new BitmapImage(new Uri(imageItems[kount].thumb_attachment, UriKind.RelativeOrAbsolute));
imgGrd.Source = bit;
imgGrd.Stretch = Stretch.UniformToFill;
_grid.Children.Add(imgGrd);
Grid.SetRow(imgGrd, i);
Grid.SetColumn(imgGrd, j);
//bit = null;
//imgGrd.Source = null;
kount++;
}
}
}
How to overcome this issue. thanks in advance..
See http://blogs.msdn.com/b/swick/archive/2011/04/07/image-tips-for-windows-phone-7.aspx for details on forcibly releasing memory used by images.
You should not create all of your images at once. The phone has ways to create and dispose of images for you. this is done by using some of the built in ItemsControl controls. The most popular of these is the ListBox. In order to let the ListBox create and dispose of the items you'll need to create a DataTemplate that will create the image.
<ListBox ItemsSource="{Binding ImageItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding thumb_attachment}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Instead of looping through your ImageItems and creating Images manually, you allow the phone to take care of this. This requires you to create an object to bind your page to that has an ImageItems property.
public class MainViewModel // Should probably implement INotifyPropertyChanged
{
public IEnumerable<ImageItem> ImageItems { get; set; }
}
With this your page would have it's DataContext set to be MainViewModel.
If you want to display the items in a grid then you can change the ItemsPanelTemplate of the ListBox to be the WrapPanel from the Windows Phone Toolkit.
<ListBox.ItemsPanelTemplate>
<toolkit:WrapPanel />
</ListBox.ItemsPanelTemplate>
I have added 10 images in a stackpanel horizontally which is inside a scrollviewer. When user swipe the page ,the scrollviewer stops at certain position, if the scroll stops in the middle of 2 images like the first image shown below i want to set the image with number 3 to be automatically scroll and fit with the left side of the screen like in the second image
for (int i = 0; i <= 9; i++)
{
Uri uri = new Uri("http://d1mu9ule1cy7bp.cloudfront.net//catalogues/47/pages/p_" + i + "/thump.jpg");
ImageSource img1 = new BitmapImage(uri);
Image rect = new Image { RenderTransform = new TranslateTransform() };
rect.Source = img1;
stack.Children.Add(rect);
}
XAML:
<Grid x:Name="LayoutRoot" Width="480" Background="Transparent" Margin="0,-33,0,0" Height="800">
<ScrollViewer HorizontalContentAlignment="Left" HorizontalAlignment="Left" Name="scroll" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible">
<StackPanel Name="stack" Width="Auto" Orientation="Horizontal" HorizontalAlignment="Left" >
</StackPanel>
</ScrollViewer>
</Grid>
The first thing you need to do is detect which item is overlapping the side of the screen. To do this, iterate over each item within the StackPanel and determine their location relative to some other element that has a fixed location on screen.
To do this, I use the following extension method:
/// <summary>
/// Gets the relative position of the given UIElement to this.
/// </summary>
public static Point GetRelativePosition(this UIElement element, UIElement other)
{
return element.TransformToVisual(other)
.Transform(new Point(0, 0));
}
i.e. for each item call the following;
Point position = stackPanelItem.GetRelativePosition(someFixedElement);
Using the location of each item, you should be able to work out which one overlaps the screen.
You then need to calculate by how much you need to scroll in order to ensure that your item is fully visible, then use ScrollViewer.ScrollToVerticalOffset to scroll to that location.
This probably isn't the nicest solution and I am sure there is a better way to achieve this but you could use the following :-
XAML :-
<ListBox x:Name="MyListBox"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
C# :-
DispatcherTimer myTimer = new DispatcherTimer();
// Constructor
public MainPage()
{
InitializeComponent();
for (int i = 0; i < 10; i++)
{
MyListBox.Items.Add(new Button()
{
Content = i.ToString(),
Width = 200,
Height = 100,
});
MyListBox.MouseMove += new MouseEventHandler(MyListBox_MouseMove);
}
myTimer.Interval = TimeSpan.FromSeconds(1);
myTimer.Tick += new EventHandler(myTimer_Tick);
}
private void myTimer_Tick(object sender, EventArgs e)
{
myTimer.Stop();
SnapFirstItem();
}
private void MyListBox_MouseMove(object sender, MouseEventArgs e)
{
myTimer.Stop();
myTimer.Start();
}
private void SnapFirstItem()
{
foreach (Button currentButton in MyListBox.Items)
{
bool visible = MyListBox.TestVisibility(currentButton, System.Windows.Controls.Orientation.Horizontal, true);
if (visible)
{
MyListBox.ScrollIntoView(currentButton);
break;
}
}
}
The TestVisibility extension method is from the following :-
http://blogs.msdn.com/b/ptorr/archive/2010/10/12/procrastination-ftw-lazylistbox-should-improve-your-scrolling-performance-and-responsiveness.aspx
I override listbox's ArrangeOverride method want to show itemSource like this:
(i collcation DependencyObject on PrepareContainerForItemOverride method)
1 2 3 4
5 6 7 8
.....
......100
but when i scroll the scrollbar the array change like this:
1
2
3
4
5
......
100
protected override Size ArrangeOverride(Size finalSize)
{
if (this._ItemsDictionary.Count <= 0)
{
return base.ArrangeOverride(finalSize);
}
base.ArrangeOverride(finalSize);
finalSize = this.MeasureOverride(_availableSize);
double xMemory = 0;
double yMemory = 0;
double maxBoderWidth = 0;
double maxHeight = 0;
foreach (FrameworkElement element in _ItemsDictionary.Values)
{
if (xMemory + element.DesiredSize.Width <= finalSize.Width)
{
element.Arrange(new Rect(xMemory, yMemory, element.DesiredSize.Width, element.DesiredSize.Height));
xMemory += element.DesiredSize.Width;
maxHeight = Math.Max(element.DesiredSize.Height, maxHeight);
}
else
{
yMemory += maxHeight;
maxBoderWidth = Math.Max(maxBoderWidth, xMemory);
xMemory = 0;
maxHeight = 0;
element.Arrange(new Rect(xMemory, yMemory, element.DesiredSize.Width, element.DesiredSize.Height));
xMemory += element.DesiredSize.Width;
maxHeight = Math.Max(element.DesiredSize.Height, maxHeight);
}
}
return finalSize;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
FrameworkElement fElement = element as FrameworkElement;
if (!_ItemsDictionary.ContainsKey(item))
{
_ItemsDictionary.Add(item, fElement);
}
}
I may be wrong. But it seems that your base class is ItemsPresenter (or something inherited from it like ListBox). It's not a good idia. Becouse EACH ItemsPresenter have it's own ItemsPanel! And Silverlight use this panel for layouting items. So ItemsPresenter can't layout it's own items directly, only trou ItemsPanel panel.
1) I recomend you to use WrapPanel (that is part of Silverlight SDK) so you have it for free, i think this is what you want. Just replace ListBox.ItemsPanel property with WrapPanel and you going to get result that you wanted
2) If you want create your own pannel you better create new class and inherit it from Panel
public class SomeNewPanel: Panel
{
protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)
{
//you can add here your custom measure logic
return base.MeasureOverride(availableSize);
}
protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
{
//you can add here your custom arrange logic
return base.ArrangeOverride(finalSize);
}
}
and then use it in ListBox like this.
<Page x:Class="SilverlightApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<!--Don't forget to add namespace of your newly created panel-->
xmlns:local="clr-namespace:SilverlightApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox x:Name="listBox1" ItemsSource="{Binding SomeItemSource}">
<!--ItemPanel property set or get Panel that-->
<!--will be used for layouting items-->
<ListBox.ItemsPanel>
<!--Here you and your newly created panle-->
<local:SomeNewPanel/>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
</Page>
i have a a Pivot that has a ListBox defined as its Pivot.ItemTemplate as the following.
<controls:Pivot x:Name="pivot">
<controls:Pivot.ItemTemplate>
<DataTemplate>
<ListBox x:Name="listBox">
...
</ListBox>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
how do i programmatically access the corresponding ListBox control corresponding to the Pivot.SelectedItem or Pivot.SelectedIndex?
i tried something similar to this link http://www.windowsphonegeek.com/tips/how-to-access-a-control-placed-inside-listbox-itemtemplate-in-wp7.
var count = VisualTreeHelper.GetChildrenCount(pivotItem);
for(int i=0; i < count; i++) {
var child = VisualTreeHelper.GetChild(pivotItem, i);
if(child is ListBox) {
//do something
} else {
Debug.WriteLine(child.GetType());
}
}
for some reason, i get System.Windows.Controls.Grid on the Debug.WriteLine.
the reason why i need to get a handle or access the ListBox inside the Pivot (that is currently on display/selected), is because i need to reset its view (scroll it back to the top). the ListBox is data bound to ObservableCollection, and when i update the collection, the scroll position needs to be placed back to the top; otherwise, everything works (data binding/visual display), except now the view is stuck in the middle or where the user currently is. if there's an easier way to do this without getting a handle on the ListBox, i'm open to that solution as well.
just in case anyone is interested, i tinkered and came up with something that works specifically for my case. the code is below. basically, i had to get the PivotItem first.
PivotItem pivotItem = pivot.ItemContainerGenerator.ContainerFromItem(myObject) as PivotItem;
i then created a local variable to store the ListBox (if it's found) and recursed the tree view model.
ListBox listBox = null;
Recurse(pivotItem, ref listBox);
and my Recurse function looks like the following.
private void Recurse(DependencyObject obj, ref ListBox listBox) {
if(obj is ListBox) {
listBox = obj as ListBox;
return;
}
var count = VisualTreeHelper.GetChildrenCount(obj);
for(int i=0; i < count; i++) {
var child = VisualTreeHelper.GetChild(obj, i);
Recurse(child, ref listBox);
}
}
try:
(Listbox)VisualTreeHelper.GetChild((pivot.SelectedItem as PivotItem), 0);
Looks like this was a while back, but this is what worked for me:
First get the PivotItem:
PivotItem pivotItem = Pivot.ItemContainerGenerator.ContainerFromItem(Pivot.SelectedItem) as PivotItem;
Then get the first child, a ListBox, from the PivotItem:
private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject {
var count = VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0)
return null;
for (int i = 0; i < count; i++) {
var child = VisualTreeHelper.GetChild(parentElement, i);
if (child != null && child is T) {
return (T)child;
} else {
var result = FindFirstElementInVisualTree<T>(child);
if (result != null)
return result;
}
}
return null;
}
Then call:
ListBox listBox = FindFirstElementInVisualTree<ListBox>(pivotItem);
use StackPanel inside your ListBox
this link may help you
http://blogs.msdn.com/b/oren/archive/2010/11/08/wp7-silverlight-perf-demo-1-virtualizingstackpanel-vs-stackpanel-as-a-listbox-itemspanel.aspx
I have a large canvas. In the casvas I'm adding textblock in code behind on drage event. Each time I add a textblock the Scrollviewer set/shows the first textbloc. Thus I have to manually scroll up to last text block. So I want to problematically set the Scrollviewer at last element of the canvas after a new textblock added. XAML:-
<ScrollViewer x:Name="sv" HorizontalScrollBarVisibility="Auto" Margin="6,6,-835,66">
<Canvas x:Name="canvas" Height="450" Width="12000" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto">
</Canvas>
</ScrollViewer>
Code behind C#:-
private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
{
if (tb_conter > 24)
return;
TextBlock[] tb = new TextBlock[elemet];
for (int i = 0; i < elemet; i++)
tb[i] = new TextBlock();
currentPoint = e.GetPosition(this.ContentPanel);
double x = currentPoint.X - oldPoint.X;
if (x >= 100)
{
tb[tb_conter].SetValue(Canvas.LeftProperty, tb_canvasLeft);
tb[tb_conter].SetValue(Canvas.TopProperty, tb_canvasTop);
tb[tb_conter].Text = time_scale.ToString();
canvas.Children.Add(tb[tb_conter]);
time_scale++;
tb_conter++;
tb_canvasLeft += tb_canvasTop;
}
else
Debug.WriteLine(x.ToString());
}
You want the ScrollViewer.ScrollToVerticalOffset method.
Better still would be adding items to an ObservableCollection<string> in a view model and binding that to a ListBox on the page.