Unable to find child element from XAML - wpf

I have a UserControl and trying to find (using FindResource) of DoubleAnimation element in code behind.
Examp:-
<UserControl ....
<Canvas Width="400" Height="400" Loaded="Canvas_Loaded">
<Canvas.Resources>
<Storyboard x:Key="sd" x:Name="sBoard ">
<DoubleAnimation x:Name="SomeAnimation" ...
I am trying to find “SomeAnimation” in Canvas_Loaded method.
Please help

FindResource method expect a resource key which SomeAnimation doesn't have.
You can use it to find the Storyboard resource with using the sd key and find your animation from there.
private void Canvas_Loaded(object sender, RoutedEventArgs e)
{
var canvas = sender as Canvas;
var storyboard = canvas.FindResource("sd") as Storyboard;
var someAnimation = storyboard.Children.First() as DoubleAnimation;
}
If you do that in order to activate the animation you can do it using BeginStoryboard method
var storyboard = canvas.FindResource("sd") as Storyboard;
canvas.BeginStoryboard(storyboard);
or simply
storyboard.Begin();
Hope this helps

Related

Clone element to display as an image/bitmap

I'm trying to create a snapshot/image/bitmap of an element that I can display as content in another control.
It seems the suggested way to do this is with a VisualBrush, but I can't seem to get it to create a snapshot of the current value and keep that state. When you alter the original source, the changes are applied to all the "copies" that have been made too.
I have made a simple example to show what I mean.
What I want is for the items added to the stackpanel to have the opacity that was set when they were cloned. But instead, changing the opacity on the source changes all "clones".
<StackPanel Width="200" x:Name="sp">
<DockPanel>
<Button Content="Clone"
Click="OnCloneButtonClick" />
<TextBlock Text="Value" x:Name="tb" Background="Red" />
</DockPanel>
</StackPanel>
private void OnCloneButtonClick(object sender, RoutedEventArgs e)
{
tb.Opacity -= 0.1;
var brush = new VisualBrush(tb).CloneCurrentValue();
sp.Children.Add(new Border() { Background = brush, Width = tb.ActualWidth, Height = tb.ActualHeight });
}
I am afraid the visual elements aren't cloned when you call CloneCurrentValue().
You will have to clone the element yourself, for example by serializing the element to XAML and then deserialize it back using the XamlWriter.Save and XamlReader.Parse methods respectively:
private void OnCloneButtonClick(object sender, RoutedEventArgs e)
{
tb.Opacity -= 0.1;
var brush = new VisualBrush(Clone(tb));
sp.Children.Add(new Border() { Background = brush, Width = tb.ActualWidth, Height = tb.ActualHeight });
}
private static Visual Clone(Visual visual)
{
string xaml = XamlWriter.Save(visual);
return (Visual)XamlReader.Parse(xaml);
}

How to fade an image in on load silverlight?

Can anyone point me to a resource on how to "fade in" an image on load in silverlight? Basically I have a listbox of items that are returned from a web service and some times the images take a little longer to load, so I wanted to fade them in as they download. I read that I might need a storyboard for this effect. Is this the best route or are there alternatives?
I'm not aware of any alternatives. The StoryBoard is the best route. You could just animate the Opacity of the image from 0 to 100.
Put the Storyboard in the resources for the UserControl () or in the App.xaml.
Then in your OnOpened event (as you mentioned in the comment):
protected void OnOpened(object sender, EventArgs e)
{
// params might be incorrect
this.fadeInStoryBoard.Stop();
// your image controls will need x:names set
this.fadeInAnimation.SetValue(Storyboard.TargetNameProperty, ((Image)sender).Name);
this.fadeInStoryBoard.Start();
}
The example storyboard is from:
http://www.codeproject.com/KB/silverlight/AgDynAnimations.aspx
and starting the storyboard: http://blogs.msdn.com/b/silverlight_sdk/archive/2008/03/26/target-multiple-objects-properties-with-one-animation-silverlight.aspx
Here's a utility function to perform the task
private void FadeIn(UIElement uilelement)
{
uilelement.Opacity = 0.0;
uilelement.Visibility = Visibility = Visibility.Visible;
var timeline = new DoubleAnimation() { To = 1.0, Duration =TimeSpan.FromSeconds(3.0) };
Storyboard.SetTarget(timeline, uilelement);
Storyboard.SetTargetProperty(timeline, new PropertyPath(UIElement.OpacityProperty));
var sb = new Storyboard();
sb.Children.Add(timeline);
sb.Begin();
}
function void image1_Opened(object sender, EventArgs e)
{
FadeIn(sender as Image);
}
You should set the Image to Collapsed, or set its initial Opacity to 0.
<Image Source="{Binding ImagePath}"
Name="image1"
Visibility="Collapsed"
ImageOpened="image1_ImageOpened" />

Find Silverlight TreeViewItem control by Header

I am trying to create a TreeView from the Silverlight TreeView control. I have my data being pulled from a WCF service that pulls from EF. All of the data is coming in fine. I have the page set up where I can input a UserName, click a button, and the data will populate the first generation in the TreeView. So, I'm dynamically building TreeViewItems to put into my TreeView with a Selected RoutedEventHandlers attached to each one. When I click on one of the TreeViewItem nodes, it kicks off the tvi_Selected function in which I want to populate TreeViewItems under the TreeViewItem that I just selected.
I run into problem when I am in my delegate function prox_GetChildMembersCompleted. I can't figure out a way to do a FindControl type lookup on the TreeViewItem that I want to add the child TreeViewItem elements to. So, I thought that I would just create a protected field where I would store the Header information to because it contain only the UserName. I just need to be able to access a specific TreeViewItem by Header or some other method that is alluding me.
You can see that in my Selected eventhandler, that I am getting the Header info by casting the sender object to a TreeViewItem. In the the delegate function prox_GetChildMembersCompleted that is called inside of tvi_Selected, the sender object is WCFDataClient so I can't grab the same data from that sender. Any insight into this would be much appreciated even if you suggest a method that is completely different.
<UserControl xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
x:Class="FloLOS2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot" Background="#5C7590">
<StackPanel>
<TextBox x:Name="txtUserName" Width="120" Margin="5"></TextBox>
<TextBlock x:Name="txtFillBlock" Width="300" Margin="5" Foreground="White" Text="Change me"></TextBlock>
<Button x:Name="btnSubmit" Margin="5" Content="Get Frontline" Width="120" Click="btnSubmit_Click" />
<data:DataGrid x:Name="MembersGrid" Margin="5"></data:DataGrid>
<controls:TreeView x:Name="MembersTree" Margin="5"></controls:TreeView>
</StackPanel>
</Grid>
</UserControl>
namespace FloLOS2
{
public partial class MainPage : UserControl
{
string sParentID;
public MainPage()
{
InitializeComponent();
}
private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
GetMyDataRef.GetMyDataClient prox = new FloLOS2.GetMyDataRef.GetMyDataClient();
prox.GetMembersCompleted += new EventHandler<FloLOS2.GetMyDataRef.GetMembersCompletedEventArgs>(prox_GetMembersCompleted);
prox.GetMembersAsync(txtUserName.Text);
}
void prox_GetMembersCompleted(object sender, FloLOS2.GetMyDataRef.GetMembersCompletedEventArgs e)
{
GetMyDataRef.Member[] members = e.Result.ToArray();
foreach (var x in members)
{
TreeViewItem tvi = new TreeViewItem() { Header = x.UserName };
tvi.Selected += new RoutedEventHandler(tvi_Selected);
MembersTree.Items.Add(tvi);
}
//MembersTree.Items.Add(tvi);
}
void prox_GetChildMembersCompleted(object sender, FloLOS2.GetMyDataRef.GetMembersCompletedEventArgs e)
{
GetMyDataRef.Member[] members = e.Result.ToArray();
TreeViewItem tviParent = new TreeViewItem();
// *** Find TreeViewItem control based on Header ***
foreach (var x in members)
{
TreeViewItem tviChild = new TreeViewItem() { Header = x.UserName };
tviChild.Selected += new RoutedEventHandler(tvi_Selected);
tviParent.Items.Add(tviChild);
}
}
void tvi_Selected(object sender, RoutedEventArgs e)
{
try
{
TreeViewItem item = (TreeViewItem)sender;
txtFillBlock.Text = item.Header.ToString();
sParentID = item.Header.ToString();
GetMyDataRef.GetMyDataClient prox = new FloLOS2.GetMyDataRef.GetMyDataClient();
prox.GetMembersCompleted += new EventHandler<FloLOS2.GetMyDataRef.GetMembersCompletedEventArgs>(prox_GetChildMembersCompleted);
prox.GetMembersAsync(item.Header.ToString());
}
catch (Exception ex)
{
txtFillBlock.Text = ex.InnerException.ToString();
}
}
}
}
I figured out a way to do it. I went and assigned a Name to the dynamically generated TreeViewItems as the UserName. I also stored the sender UserName in a protected string, then called this line of code to get the parent TreeViewItem:
TreeViewItem tviParent = (TreeViewItem)LayoutRoot.FindName(sParentID);
Thanks for what would have been great answers! :)

Parent TreeView Item ghost selected event!

I have a TreeView that launches a new window when each of its TreeViewItems Selected event is raised.
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300">
<Grid>
<TreeView Name="treeView1">
<TreeViewItem Header="Root">
<TreeViewItem Header="Parent" Selected="ParentTreeViewItem_Selected">
<TreeViewItem Header="Child" Selected="TreeViewItem_Selected" ></TreeViewItem>
</TreeViewItem>
</TreeViewItem>
</TreeView>
</Grid>
</Window>
Code Behind
namespace WpfApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void TreeViewItem_Selected(object sender, RoutedEventArgs e)
{
Window w = new Window();
w.Show();
e.Handled = true;
}
private void ParentTreeViewItem_Selected(object sender, RoutedEventArgs e)
{
}
}
}
When I click on the child node the new window is launched as expected. However imediatly afterwords its parents Selected eventis fired stealing focus from the new window, and marking the parent node as the current selection!
My expectation was that the newly launched window would have focus, and the node that was clicked would turn gray indicating to the users his/hers selection. Does anyone have any idea of why this happens and how I can prevent it?
Thanks,
Brette
Thought I would post the answer. I finally found a way around this. Setting w.Owner = this; has no effect. Turns out launching a new window on the Selected event of a TreeViewItem causes some focus issues. I have not found out what the root cause is by executing this on the Dispatcher seems to correct it. See Below
private void ChildTreeViewItem_Selected(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => new Window().Show()));
}
Hope this saves someone else some time.
Brette
Add:
w.Owner = this
Example:
private void TreeViewItem_Selected(object sender, RoutedEventArgs e)
{
Window w = new Window();
w.Owner = this;
w.Show();
e.Handled = true;
}

Find UI element corresponding to an item in a Silverlight ItemsControl

I have a list of strings displayed by a Silverlight ItemsControl. The DataTemplate is a Border control with a TextBlock as its child. How can I access the border control corresponding to an item? For example, I might want to do this to change the background color.
An easier way to do this is to grab the Parent of the textblock and cast it as a Border. Here is a quick example of this:
Xaml
<Grid>
<ItemsControl x:Name="items">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<TextBlock MouseEnter="TextBlock_MouseEnter" MouseLeave="TextBlock_MouseLeave" Text="{Binding}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Code behind
public Page()
{
InitializeComponent();
items.ItemsSource = new string[] { "This", "Is", "A", "Test" };
}
private void TextBlock_MouseEnter(object sender, MouseEventArgs e)
{
var tx = sender as TextBlock;
var bd = tx.Parent as Border;
bd.Background = new SolidColorBrush(Colors.Yellow);
}
private void TextBlock_MouseLeave(object sender, MouseEventArgs e)
{
var tx = sender as TextBlock;
var bd = tx.Parent as Border;
bd.Background = new SolidColorBrush(Colors.White);
}
The example sets the background on the border by grabbing the parent of the textbox.
You can override the ItemsControl.GetContainerForItemOverride method and save the object-container pairs in a dictionary.
see this: http://msdn.microsoft.com/en-us/library/bb613579.aspx and this: http://blogs.msdn.com/wpfsdk/archive/2007/04/16/how-do-i-programmatically-interact-with-template-generated-elements-part-ii.aspx. Unfortunately, it won't work in SL because SL DataTemplate class doesn't have the FindName method.

Resources