I have winform hosting WPF control text block where the contents of text block is dynamic. I want to set the height of the text block based on content. mean while text block is hosted in windows usercontrol (TitleBarHost) and in turn this windows control is dynamically added in another winform at run time. Below is piece of code where control is added dynamically.
Control titleBar = new TitleBarHost(titleInfo);
(titleBar as ICustomUI).Initialize(_application, extraData);
panelHeader.Controls.Add(titleBar);
titleBar.Dock = DockStyle.Top;
TitleBarView.xaml
<Grid>
<TextBlock x:Name="txtTitleBar" Text="{Binding Text}" Style="{StaticResource TextBlockStyle}"/>
</Grid>
TitleBarHost.cs
public void Initialize(object application, object configurationData)
{
m_Model = new TitleBarModel(this.titleInfo, application, configurationData);
m_ViewModel = new TitleBarViewModel(m_Model);
m_View = new TitleBarView { DataContext = m_ViewModel };
if (m_ViewModel != null)
{
m_View.FormatString(m_ViewModel.Text);
}
elementHost1.Child = m_View;
}
I need to set the text block height dynamic based on content. I tried to use the ActualHeight prop of text block but doesn't work. Also tried using height Auto, doesn't works!
Related
I have a WrapPanel containing an arbitrary number of jagged sized elements. I'd like to implement drag select for my items.
It seems pretty obvious how to HitTest for a point, but how can I find all items within a rectangular area?
You may use VisualTreeHelper.HitTest with a GeometryHitTestParameters argument and a HitTestFilterCallback that checks if a Visual is a direct child of the Panel.
Something like this:
var selectedElements = new List<DependencyObject>();
var rect = new RectangleGeometry(...);
var hitTestParams = new GeometryHitTestParameters(rect);
var resultCallback = new HitTestResultCallback(
result => HitTestResultBehavior.Continue);
var filterCallback = new HitTestFilterCallback(
element =>
{
if (VisualTreeHelper.GetParent(element) == panel)
{
selectedElements.Add(element);
}
return HitTestFilterBehavior.Continue;
});
VisualTreeHelper.HitTest(
panel, filterCallback, resultCallback, hitTestParams);
It looks a little complicated, but the HitTestFilterCallback is necessary to get all Visuals in the visual tree, not only those that actually got hit. For example if your panel contains Label controls, the HitTestResultCallback will only be called for the Border and TextBlock child Visuals of each Label.
The option for controlling hit test visibility is the IsHitTestVisible property. This property allows you to control hit test visibility regardless of the brush with which the UIElement is rendered.
Also, You want to set the Fill to Transperent
<Rectangle Width="200" Height="200" Margin="170,23,12,35" Fill="Transparent" IsHitTestVisible="True" />
According to Stefan Wick's blog, freeing memory from Images is just as simple as doing:
BitmapImage bitmapImage = image.Source as BitmapImage;
bitmapImage.UriSource = null;
image.Source = null;
However, how can I achieve the same effect If I am using data binding in Xaml like this?:
// inside MainPage.xaml
<Button Tap="GetImages">Get Images</Button>
<ListBox ItemSource="{Binding Links}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- I am not binding to Image's Source directly, because I want to use the bitmap's 'Background creation' option and it's download progress event in the future -->
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
//inside MainPage.xaml.cs
public void GetImages(object sender, RoutedEventArgs e) {
(DataContext as ViewModel).GetMeSomeImages();
}
// inside ViewModel.cs
public void GetMeSomeImages() {
List<string> links = ThisMethodGetsLinks();
Links.Clear();
foreach(var link in links)
Links.Add(link);
}
ObservableCollection<string> _links;
public ObservableCollection<string> Links {
get {
if (_links == null)
_links = new ObservableCollection<string>();
return _links;
}
}
In this scenario, each button tap would consume additional memory until the phone/emulator crashes. Images are not freed from memory despite the Listbox's ItemSource property being cleared.
The BitmapCreateOptions Enumeration defines the BackgroundCreation enumeration thusly:
Causes a BitmapSource to be initialized as soon as it is declared. This option uses the image cache for previously used URIs. If an image is not in the image cache, the image will be downloaded and decoded on a separate background thread.
This makes me think that when you change the UriSource property, and the old Image is disposed, the background thread handling the download of the bitmap is not notified, and that background thread continues to download the image. This may be done because the phone implements it's own cacheing of all images (note the presence of the "IgnoreImageCache" element of the BitmapCreateOptions enumeration).
This is likely the culprit, however another possibility is that virtualization of the ListBox is not actually happening. The most frequent reason for this is if the items in the list are not explicitly defined to have the same height. Virtualizing in the ListBox uses VirtualizingStackPanel under the covers, and requires every item to be the same height. If any item is a different height, the virtualzing behavior is cancelled. Below is some code that should help you determine if virt. is actually happening or not. Another thing with Virtualizing is that currently your Images don't have a set height until the image data is downloaded. This means that before images are downloaded, all images have a height of 0 pixels. If all images have a height of 0 pixels, then that means all of them are "in view" according to the virt. logic, they should all begin downloading.
In summary, try these things:
Change the CreateOptions to something different (or don't set it at all)
Explicitly set the height of the image tag inside the listbox. (this is a must)
Use the below code to see if virt. is achieved.
Simple Structure to Contain Image Data:
using System.Diagnostics;
public class BoundImage
{
private string imageURL;
public static int TotalImagesRequested = 0;
public BoundImage(string url)
{
imageURL = url;
}
public string ImageURL
{
get
{
TotalImagesRequested++;
// Watch the output window and see if TotalImagesRequested is
// growing to a crazy high amount (if it is it will eventually
// reach the total Count of the _links variable. But your
// app may crash before that happens.
Debug.WriteLine("Images being requested: " + TotalImagesRequested);
return imageURL;
}
}
}
Altered Property for Exposing the Links:
//inside MainPage.xaml.cs
public void GetImages(object sender, RoutedEventArgs e)
{
(DataContext as ViewModel).GetMeSomeImages();
}
// inside ViewModel.cs
public void GetMeSomeImages()
{
List<string> links = ThisMethodGetsLinks();
Links.Clear();
_links = new ObservableCollection<BoundImage>();
foreach(string link in links)
{
_links.Add(new BoundImage(link));
}
}
ObservableCollection<BoundImage> _links;
public ObservableCollection<BoundImage> Links
{
get
{
if (_links == null)
_links = new ObservableCollection<BoundImage>();
return _links;
}
set
{
_links = value;
}
}
Altered XAML to Hook Binding to ImageURL property of BoundImage:
// inside MainPage.xaml
<Button Tap="GetImages">Get Images</Button>
<ListBox ItemSource="{Binding Links}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- I am not binding to Image's Source directly, because I want to use the bitmap's 'Background creation' option and it's download progress event in the future -->
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding ImageURL}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm using the Microsoft RibbonControl on a UserControl (it needs to be so we can host it on a stub form to host the WPF in our MDI system). Sadly, the title of the Ribbon displays Top/Left in the ribbon's header, and it looks ridiculous. How do I get at that sucker?
I am working on just about the same thing right now. I solved it by using a datatemplate for the ribbon title:
<r:Ribbon.TitleTemplate>
<DataTemplate>
<TextBlock Text="Put you title here" Margin="3,3,0,0"></TextBlock>
</DataTemplate>
</r:Ribbon.TitleTemplate>
If the ribbon is used in a RibbonWindow, you probably also want to add a glow to the title text to be able to read it properly when placed over a dark background. In that case, add this XAML inside the TextBlock:
<TextBlock.BitmapEffect>
<OuterGlowBitmapEffect GlowColor="White" Opacity="0.7" GlowSize="10"/>
</TextBlock.BitmapEffect>
There is one more problem with the Ribbon when used within a RibbonWindow; the title text will either be placed correctly when window state is Normal or when window is maximized. To solve this I bound the TextBlock Margin to a property in the codebind:
public Thickness TitleMargin
{
get { return this.WindowState == WindowState.Maximized ? new Thickness(0, 3, 0, 0) : new Thickness(0); }
}
To get this working, you also need to fire a PropertyChanged event each time the window state changes:
protected override void OnStateChanged(EventArgs e)
{
OnPropertyChanged("TitleMargin");
base.OnStateChanged(e);
}
hello community any one can please say how to add controls dynamically into a Stack Panel
note: what i need is i have to create a menu which get data from database and creates menu items accordingly can any one say how can i create such menus i am new to silver light
I am using silverlight 3 beta and expression blend3 + sketch flow please help me to know how to design those
Excuse the variable names, but here is a code snippet of dynamically adding items to a stack panel
StackPanel split = new StackPanel();
TextBlock expected = new TextBlock();
expected.Text = "Expected Final Bonus";
TextBlock meh = new TextBlock();
meh.Text = Math.Round(((QuoteData)results.First()).ExpectedBonus * 100, 2) + "%";
split.Children.Add(expected);
split.Children.Add(meh);
TextBlock disc = new TextBlock();
disc.Text = "Discretionary Percentage";
TextBlock number = new TextBlock();
number.Text = Math.Round(((QuoteData)results.First()).Discretionary * 100, 2) + "%";
split.Children.Add(disc);
split.Children.Add(number);
Here you can see that I also created the stack panel dynamically, however, you can also create it using XAML.
Something like this should work:
<StackPanel Grid.Row="3" Grid.Column="1" Name="split" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto">
First, if your StackPanel is already in your XAML, handle the Loaded event:
<StackPanel x:Name="spValue" Loaded="spValue_Loaded">
</StackPanel>
private void spValue_Loaded(object sender, RoutedEventArgs e)
{
StackPanel stackPanel = (sender as StackPanel);
stackPanel.Children.Clear();
stackPanel.Children.Add(XamlReader.Load(XElement.Parse(xaml).ToString()) as FrameworkElement);
}
The controls are created with XAMLReader from your stuff loaded from the DB. You can adapt all that to your particular scenario (menu and menu items...)
In Silverlight a tooltip can have as many elements in it as you want.
However, it doesn't receive focus so you can't have user interactivity in it.
Could you, though, start a video playing as soon as the tooltip opens and have the video stop as soon as the tooltip closes?
This is my first answer on Stack Overflow so I ask for your good humor.
I think you could run your video in the tooltip by using a video brush.
Here's some code I used to paint a fire video on the bar in the chart that represented heating with corn. ( long story) right here, you can see it is set to the fill of an ellipse.
#region video brush setup
protected void setupVideo()
{
VideoBrush _vb;
MediaElement mevideo;
_vb = new VideoBrush();
mevideo = new MediaElement();
mevideo.SetValue(Grid.NameProperty, "video");
Uri videoUri = new Uri("http://www.faxt.com/videos/ezburnboilerfire.wmv", UriKind.Absolute);
mevideo.Source = videoUri;
mevideo.Visibility = Visibility.Collapsed;
mevideo.MediaEnded += new RoutedEventHandler(me_MediaEnded);
MediaRoot.Children.Add(mevideo);
_vb.SetSource(mevideo);
Ellipse el = new Ellipse();
el.Width = 100;
el.Height = 100;
el.Fill = _vb;
MediaRoot.Children.Add(el);
}
You could do it with a VideoBrush as suggested by BPerreault, but you could also just set Tooltip.Content to a MediaElement.
That is because the Content property of Tooltip inherits from ContentControl and the Content property of a ContentControl can be any type of object, such as a string, a UIElement, or a DateTime. When Content is set to a UIElement (like MediaElement), the UIElement is displayed in the ContentControl. When Content is set to another type of object, a string representation of the object is displayed in the ContentControl. (from documentation)
It should be something like this:
<TextBlock x:Name="myText" Text="MouseOver and you'll get a ToolTip!">
<ToolTipService.ToolTip>
<MediaElement x:Name="myVideo" Source="Butterfly.wmv" Width="300" Height="300" />
</ToolTipService.ToolTip>
</TextBlock >