Translate ImageButton from C# to XAML - wpf

I worked out the C# code to create an ImageButton (below) that has three images (one base-image and two overlays) and three text boxes as the face of the button. I am inheriting from the Button class, which unfortunately includes several components that I didn't realize would surface until after coding and need to remove, namely the bright-blue surrounding border on IsMouseOver, and any visible borders between the buttons, as the buttons will end up in a wrapPanel and the borders need to be seamless. Now that the format has been worked out in C#, I expect that I need to translate to XAML so that I can create a ControlTemplate to get the functionality necessary, however I am not certain as to the process of translating from C# to XAML. I would appreciate if anyone is aware of a good overview/resource that discusses what will be required to convert so that I can translate appropriately? Thanks.
public class ACover : Button
{
Image cAImage = null;
Image jCImage = null;
Image jCImageOverlay = null;
TextBlock ATextBlock = null;
TextBlock AbTextBlock = null;
TextBlock RDTextBlock = null;
private string _TracksXML = "";
public ACover()
{
Grid cArtGrid = new Grid();
cArtGrid.Background = new SolidColorBrush(Color.FromRgb(38, 44, 64));
cArtGrid.Margin = new System.Windows.Thickness(5, 10, 5, 10);
RowDefinition row1 = new RowDefinition();
row1.Height = new GridLength(225);
RowDefinition row2 = new RowDefinition();
row2.Height = new GridLength(0, GridUnitType.Auto);
RowDefinition row3 = new RowDefinition();
row3.Height = new GridLength(0, GridUnitType.Auto);
RowDefinition row4 = new RowDefinition();
row4.Height = new GridLength(0, GridUnitType.Auto);
cArtGrid.RowDefinitions.Add(row1);
cArtGrid.RowDefinitions.Add(row2);
cArtGrid.RowDefinitions.Add(row3);
cArtGrid.RowDefinitions.Add(row4);
ColumnDefinition col1 = new ColumnDefinition();
col1.Width = new GridLength(0, GridUnitType.Auto);
cArtGrid.ColumnDefinitions.Add(col1);
jCImage = new Image();
jCImage.Height = 240;
jCImage.Width = 260;
jCImage.VerticalAlignment = VerticalAlignment.Top;
jCImage.Source = new BitmapImage(new Uri(Properties.Settings.Default.pathToGridImages + "jc.png", UriKind.Absolute));
cArtGrid.Children.Add(jCImage);
cArtImage = new Image();
cArtImage.Height = 192;
cArtImage.Width = 192;
cArtImage.Margin = new System.Windows.Thickness(3, 7, 0, 0);
cArtImage.VerticalAlignment = VerticalAlignment.Top;
cArtGrid.Children.Add(cArtImage);
jCImageOverlay = new Image();
jCImageOverlay.Height = 192;
jCImageOverlay.Width = 192;
jCImageOverlay.Margin = new System.Windows.Thickness(3, 7, 0, 0);
jCImageOverlay.VerticalAlignment = VerticalAlignment.Top;
jCImageOverlay.Source = new BitmapImage(new Uri( Properties.Settings.Default.pathToGridImages + "jc-overlay.png", UriKind.Absolute));
cArtGrid.Children.Add(jCImageOverlay);
ATextBlock = new TextBlock();
ATextBlock.Foreground = new SolidColorBrush(Color.FromRgb(173, 176, 198));
ATextBlock.Margin = new Thickness(10, -10, 0, 0);
cArtGrid.Children.Add(ATextBlock);
AlTextBlock = new TextBlock();
AlTextBlock.Margin = new Thickness(10, 0, 0, 0);
AlTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(173, 176, 198));
cArtGrid.Children.Add(AlTextBlock);
RDTextBlock = new TextBlock();
RDTextBlock.Margin = new Thickness(10, 0, 0, 0);
RDTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(173, 176, 198));
cArtGrid.Children.Add(RDTextBlock);
Grid.SetColumn(jCImage, 0);
Grid.SetRow(jCImage, 0);
Grid.SetColumn(jCImageOverlay, 0);
Grid.SetRow(jCImageOverlay, 0);
Grid.SetColumn(cArtImage, 0);
Grid.SetRow(cArtImage, 0);
Grid.SetColumn(ATextBlock, 0);
Grid.SetRow(ATextBlock, 1);
Grid.SetColumn(AlTextBlock, 0);
Grid.SetRow(AlTextBlock, 2);
Grid.SetColumn(RDTextBlock, 0);
Grid.SetRow(RDTextBlock, 3);
this.Content = cArtGrid;
}
public string A
{
get { if (ATextBlock != null) return ATextBlock.Text;
else return String.Empty; }
set { if (ATextBlock != null) ATextBlock.Text = value; }
}
public string Al
{
get { if (AlTextBlock != null) return AlTextBlock.Text;
else return String.Empty; }
set { if (AlTextBlock != null) AlTextBlock.Text = value; }
}
public string RD
{
get { if (RDTextBlock != null) return RDTextBlock.Text;
else return String.Empty; }
set { if (RDTextBlock != null) RDTextBlock.Text = value; }
}
public ImageSource Image
{
get { if (cArtImage != null) return cArtImage.Source;
else return null; }
set { if (cArtImage != null) cArtImage.Source = value; }
}
public string TracksXML
{
get { return _TracksXML; }
set { _TracksXML = value; }
}
public double ImageWidth
{
get { if (cArtImage != null) return cArtImage.Width;
else return double.NaN; }
set { if (cArtImage != null) cArtImage.Width = value; }
}
public double ImageHeight
{
get { if (cArtImage != null) return cArtImage.Height;
else return double.NaN; }
set { if (cArtImage != null) cArtImage.Height = value; }
}
}

XAML basically represents an object graph, so the translation should normally be pretty mechanical:
C# new translates to a XAML element tag, e.g. Grid cArtGrid = new Grid(); translates to <Grid Name="cArtGrid"></Grid>.
C# property setters translate to attributes if the value is simple, e.g. cArtGrid.Background = new SolidColorBrush(Color.FromRgb(38, 44, 64)); translates to <Grid Background="#FF262C40">.
If the property value is complex, you'll need to use XAML property element syntax.
Adding to collections typically requires XAML property element syntax, e.g. <Grid><Grid.RowDefinitions><RowDefinition Height="225" /></Grid.RowDefinitions></Grid>.
But for the Children collection you can just put the element directly inside e.g. cArtGrid.Children.Add(jCImage); becomes <Grid><Image ... /></Grid>. (The same applies to the Content property though this won't really affect you here.)
Attached property SetXxx calls translate into attributes with the dot notation e.g. Grid.SetColumn(ATextBlock, 0); becomes <Grid><TextBlock Grid.Column="0" /></Grid>.
You'll need to understand how value types like colours and thicknesses are represented e.g. the #AARRGGBB notation for colours and the CSV notation for thicknesses. MSDN will usually show this for the relevant types or properties that have those types.
In general, looking up the property in MSDN and looking at the XAML syntax should give you a good start.

It sounds like you're attempting to extend the button with some new functionality. So the first thing you want to do is take advantage of the dependency system so that your properties can be bound in XAML. Look at this article on MSDN for information on declaring new dependency properties.
A prime candidate for a dependency property would be the Image property.
Actually, what I recommend is using the new CustomControl template in visual studio to provide some boilerplate code for you. Part of the boilerplate is declaring a themes.xaml file which provides a default template for your control. That template is what will hold your translated XAML for your control.
The good thing about XAML is that it is an initialization language. Once you get the dependency properties declared on your AlbumCover you bind to them in the template for your control. For more details about how this works, look at Charles Petzold's article on creating lookless controls in WPF.
You've got the basic look and functionality for your control in place. Following these two resources should help you integrate within the WPF ecosystem.

Related

Resizing of an AutoScroll Panel affects scrolled position

When I resize the following form with the right resize handle, the contained TableLayoutPanel gets decorated with scroll bars (as intended, panel1.AutoScroll = true) for smaller form sizes, but the TableLayoutPanel also gets displaced from its original position. See images below: after resizing the form with right resize handle only, the second one has its scroll bars not leftmost and the left border of the content is cut off.
It seems somehow that this behavior is tied to the existence of the nested RadioButtons because if I remove them (or replace them by another TextBox for example), the "normal" behavior is restored (TableLayoutPanel stays in place during resize).
What properties do I have to set in order to keep the content always stationary relative to the (top)left borders?
BTW: When I replace the panel1 by a TabControl + one TabPage, the "normal" behavior is also restored.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
/// <summary>
/// Description of Form3.
/// </summary>
public partial class Form3 : Form
{
const int textBoxNameWidth = 500;
TableLayoutPanel testControl1;
Panel panel1;
TextBox textBoxName;
RadioButton radioButtonNo;
RadioButton radioButtonYes;
TableLayoutPanel tableLayoutPanelDecision;
public Form3()
{
testControl1 = new TableLayoutPanel();
panel1 = new Panel();
textBoxName = new TextBox();
radioButtonNo = new RadioButton();
radioButtonYes = new RadioButton();
tableLayoutPanelDecision = new TableLayoutPanel();
testControl1.AutoSize = true;
testControl1.AutoSizeMode = AutoSizeMode.GrowAndShrink;
testControl1.Location = new Point(0, 0);
testControl1.Dock = DockStyle.None;
testControl1.ColumnCount = 2;
testControl1.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
testControl1.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
testControl1.RowCount = 2;
testControl1.RowStyles.Add(new RowStyle(SizeType.AutoSize));
testControl1.RowStyles.Add(new RowStyle(SizeType.AutoSize));
testControl1.Controls.Add(textBoxName, 1, 0);
testControl1.Controls.Add(tableLayoutPanelDecision, 1, 1);
textBoxName.Text = "New Boolean";
textBoxName.TextAlign = HorizontalAlignment.Center;
textBoxName.Anchor = (AnchorStyles.Left | AnchorStyles.Right);
textBoxName.TabStop = false;
textBoxName.Width = textBoxNameWidth;
tableLayoutPanelDecision.AutoSize = true;
tableLayoutPanelDecision.ColumnCount = 2;
tableLayoutPanelDecision.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50f));
tableLayoutPanelDecision.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50f));
tableLayoutPanelDecision.RowCount = 1;
tableLayoutPanelDecision.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tableLayoutPanelDecision.Controls.Add(radioButtonYes, 0, 0);
tableLayoutPanelDecision.Controls.Add(radioButtonNo, 1, 0);
tableLayoutPanelDecision.Dock = DockStyle.Fill;
radioButtonNo.Checked = true;
radioButtonNo.AutoSize = true;
radioButtonNo.TabIndex = 1;
radioButtonNo.TabStop = true;
radioButtonNo.Text = "False";
radioButtonNo.UseVisualStyleBackColor = true;
radioButtonNo.Anchor = AnchorStyles.None;
radioButtonYes.AutoSize = true;
radioButtonYes.TabIndex = 0;
radioButtonYes.Text = "True";
radioButtonYes.UseVisualStyleBackColor = true;
radioButtonYes.Anchor = AnchorStyles.None;
panel1.AutoScroll = true;
panel1.Controls.Add(testControl1);
panel1.Dock = System.Windows.Forms.DockStyle.Fill;
panel1.Location = new System.Drawing.Point(0, 0);
panel1.Name = "panel1";
panel1.Size = new System.Drawing.Size(560, 219);
panel1.TabIndex = 1;
AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(560, 219);
Controls.Add(panel1);
Name = "Form3";
Text = "Form3";
}
}
}
The panel is trying to keep focusable controls within view for the user. To change that, you would have to use your own panel:
public class PanelEx : Panel {
protected override Point ScrollToControl(Control activeControl) {
return this.DisplayRectangle.Location;
}
}

Is a dashed border around a selected text/image element possible in Silverlight?

I have an image editor I'm developing in silverlight which has multiple text and image elements on one canvas, that are draggable etc. I need feedback for the user to highlight the selected element when it is clicked on by the user and highlight a different element instead if another is clicked. I think I should do this with a dashed border around the element, but I don't know if it's possible.
Below is my code relating to the elements -
Project.cs
namespace ImageEditor.Client.BLL
{
public class Project : INotifyPropertyChanged
{
private int numberOfElements;
#region Properties
private ObservableCollection<FrameworkElement> elements;
public ObservableCollection<FrameworkElement> Elements
{
get { return elements; }
set
{
elements = value;
NotifyPropertyChanged("Elements");
}
}
private FrameworkElement selectedElement;
public FrameworkElement SelectedElement
{
get { return selectedElement; }
set
{
selectedElement = value;
NotifyPropertyChanged("SelectedElement");
}
}
private TextBlock selectedTextElement;
public TextBlock SelectedTextElement
{
get { return selectedTextElement; }
set
{
selectedTextElement = value;
NotifyPropertyChanged("SelectedTextElement");
}
}
private Image selectedImageElement;
public Image SelectedImageElement
{
get { return selectedImageElement; }
set
{
selectedImageElement = value;
NotifyPropertyChanged("SelectedImageElement");
}
}
#endregion
#region Methods
private void AddTextElement(object param)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = "New Text";
textBlock.Foreground = new SolidColorBrush(Colors.Gray);
textBlock.FontSize = 25;
textBlock.FontFamily = new FontFamily("Arial");
textBlock.Cursor = Cursors.Hand;
textBlock.Tag = null;
AddDraggingBehavior(textBlock);
textBlock.MouseLeftButtonUp += element_MouseLeftButtonUp;
this.Elements.Add(textBlock);
numberOfElements++;
this.SelectedElement = textBlock;
this.selectedTextElement = textBlock;
}
private BitmapImage GetImageFromLocalMachine(out bool? success, out string fileName)
{
OpenFileDialog dialog = new OpenFileDialog()
{
Filter = "Image Files (*.bmp;*.jpg;*.gif;*.png;)|*.bmp;*.jpg;*.gif;*.png;",
Multiselect = false
};
success = dialog.ShowDialog();
if (success == true)
{
fileName = dialog.File.Name;
FileStream stream = dialog.File.OpenRead();
byte[] data;
BitmapImage imageSource = new BitmapImage();
using (FileStream fileStream = stream)
{
imageSource.SetSource(fileStream);
data = new byte[fileStream.Length];
fileStream.Read(data, 0, data.Length);
fileStream.Flush();
fileStream.Close();
}
return imageSource;
}
else
{
fileName = string.Empty;
return new BitmapImage();
}
}
private void AddImageElement(object param)
{
bool? gotImage;
string fileName;
BitmapImage imageSource = GetImageFromLocalMachine(out gotImage, out fileName);
if (gotImage == true)
{
Image image = new Image();
image.Name = fileName;
image.Source = imageSource;
image.Height = imageSource.PixelHeight;
image.Width = imageSource.PixelWidth;
image.MaxHeight = imageSource.PixelHeight;
image.MaxWidth = imageSource.PixelWidth;
image.Cursor = Cursors.Hand;
image.Tag = null;
AddDraggingBehavior(image);
image.MouseLeftButtonUp += element_MouseLeftButtonUp;
this.Elements.Add(image);
numberOfElements++;
this.SelectedElement = image;
this.SelectedImageElement = image;
}
}
private void OrderElements()
{
var elList = (from element in this.Elements
orderby element.GetValue(Canvas.ZIndexProperty)
select element).ToList<FrameworkElement>();
for (int i = 0; i < elList.Count; i++)
{
FrameworkElement fe = elList[i];
fe.SetValue(Canvas.ZIndexProperty, i);
}
this.Elements = new ObservableCollection<FrameworkElement>(elList);
}
public void element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
this.SelectedElement = sender as FrameworkElement;
if (sender is TextBlock)
{
this.SelectedTextElement = sender as TextBlock;
FadeOut(this.SelectedTextElement);
}
else if (sender is Image)
{
this.SelectedImageElement = sender as Image;
FadeOut(this.SelectedImageElement);
}
}
#endregion
More than needed there but you get a good idea of how it all works from that. How might I go about it? I'm still pretty new to silverlight
Edit:
This is my start attempt at a DashBorder Method, wherein I'm trying to make a rectangle the same dimensions as the selected element which will go around the element
public static void DashBorder(FrameworkElement element)
{
Rectangle rect = new Rectangle();
rect.Stroke = new SolidColorBrush(Colors.Black);
rect.Width=element.Width;
rect.Height=element.Height;
rect.StrokeDashArray = new DoubleCollection() { 2, 2 };
}
It appears to do nothing and isn't what I want to do anyway. Is there no way to make a dash border on a FrameworkElement directly?
I don't know how, but google does.
You can use the StrokeDashArray to achieve the desired effect,
example:
<Rectangle Canvas.Left="10" Canvas.Top="10" Width="100" Height="100"
Stroke="Black" StrokeDashArray="10, 2"/>
The first number in StrokeDashArray is the length of the dash, the
second number is the length of the gap. You can repeat the dash gap
pairs to generate different patterns.
Edit:
To do this in code create a rectangle and set it's StrokeDashArray property like this (code untested):
Rectangle rect = new Rectangle();
rect.StrokeThickness = 1;
double[] dashArray = new double[2];
dashArray[0] = 2;
dashArray[1] = 4;
rect.StrokeDashArray = dashArray;

WPF Performance Issues

I have a WPF Application which allows user to enter production Data.
For that reason i created a Usercontrol which uses an WPF Toolkit Accordion. In Code behind i create 15 Accordion Items. Each Item has an Stackpanel and 5-10 Textboxes in it.
When adding 12 of these controls to the main Content Control it takes about 10 seconds.
What can be the cause of this behaviour?
public XXXMeasurementControl(Measurement meas)
{
InitializeComponent();
if (meas.ID == -2)
{
LineNameTextBlock.Text = "Total";
}
else
{
LineNameTextBlock.Text = meas.MeasureDate.ToString("HH:mm") + " - " + meas.MeasureDate.AddHours(1).ToString("HH:mm");
}
this.cells = meas.MainCells;
this.meas = meas;
Binding b = new Binding();
Remark.DataContext = Meas;
b.Mode = BindingMode.TwoWay;
b.Path = new PropertyPath("Remark");
BindingOperations.SetBinding(Remark, TextBox.TextProperty, b);
//Create Cells Start
foreach (Cell c in cells)
{
//Creating Textboxes & Bindings for Stations from Maincells
if (c.Name != "OQC")
{
//Setting Qualified Overall (=Qualified from Cell Appearance Check)
Common.BindTextBlock(QualifiedOverallTextBlock, c, "Qualified");
if (c.Name.Contains("Appearance Check"))
Common.BindTextBlock(QualifiedOverallTextBlock, c, "Qualified");
//Setting Scrap Rate (=Waste from Cell Acoustic Test)
if (c.Name.Contains("Acoustic Test"))
Common.BindTextBlock(ScrapRateTextBlock, c, "WasteRate");
AccordionItem aci = new AccordionItem();
StackPanel sp = new StackPanel();
StackPanel groupData = new StackPanel();
StackPanel all = new StackPanel();
all.Children.Add(sp);
all.Children.Add(groupData);
if (c.Stations != null)
//All Single Cell Line Controls
if (meas.ID != -2)
{
for (int i = 0; i < c.Stations.Count; i++)
{
NumberTextbox t = Common.CreateNumberTextbox(c.Stations[i], "Value", BindingMode.TwoWay, false, null, 80, 22);
t.LostFocus += new RoutedEventHandler(t_LostFocus);
c.Stations[i].PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(LineControl_PropertyChanged);
//Handling if Qualified Field is Editable
if (c.Stations[i].Name.Contains("Qualified"))
{
t.Background = new SolidColorBrush(Colors.BlanchedAlmond);
groupData.Children.Add(t);
}
else
{
sp.Children.Add(t);
}
}
}
groupData.Children.Add(Common.CreateNumberTextbox(c, "RejectQty", BindingMode.OneWay, true,null, 80, 22));
groupData.Children.Add(Common.CreateNumberTextbox(c, "PassRate", BindingMode.OneWay, true, new SolidColorBrush(Colors.BlanchedAlmond), 80, 22));
groupData.Children.Add(Common.CreateNumberTextbox(c, "RejectRate", BindingMode.OneWay, true, new SolidColorBrush(Colors.BlanchedAlmond), 80, 22));
aci.Header = "";
aci.Content = all;
MainCellsAccordion.Items.Add(aci);
}
}
}
I too experience terrible performance with the Accordion control in the WPF Toolkit. I have an Accordion control within a tab, and whenever I switch to that tab it takes a solid 2-3 seconds to initialize the contents. I do not have this problem when the Accordion Control is not being used.
I think the Accordion is your culprit.

Menu click event object parameter references menu, not underlying object

I added a Line with C# code to my canvas, along with a context menu and attached event. I would like to rotate the Line using a context menu choice, not the menu text in the context menu:
newMenuItem1.PreviewMouseDown += new MouseButtonEventHandler((sx, ex) => {
MenuItem menuItem = (MenuItem)sx;
string theHeader = menuItem.Header.ToString();
if (theHeader.Contains("90")) {
Line ow = ex.Source as Line;
rt = new RotateTransform(90, 25, 50);
ow.RenderTransform = rt;
}
});
This code produces a null reference exception. If I substitute:
UIElement ow = ex.Source as UIElement;
The actual menu text will rotate!
Edit:
Here is more code, I am now trying originalsource too:
private void button1_Click(object sender, RoutedEventArgs e)
{
Line g = new Line();
g.Stroke = System.Windows.Media.Brushes.LawnGreen;
g.X1 = 0; g.X2 = 100;g.Y1 = 0;g.Y2 = 0;
g.HorizontalAlignment = HorizontalAlignment.Left;
g.VerticalAlignment = VerticalAlignment.Center;
g.StrokeThickness = 6;
ContextMenu k = new ContextMenu();
g.ContextMenu = k;
MenuItem newMenuItem1 = new MenuItem();
MenuItem newMenuItem2 = new MenuItem();
MenuItem newMenuItem3 = new MenuItem();
newMenuItem1.Header = "Rotate 90";
newMenuItem2.Header = "Rotate 180";
newMenuItem3.Header = "Rotate 270";
newMenuItem1.PreviewMouseDown += new MouseButtonEventHandler((sx, ex) => {
MenuItem menuItem = (MenuItem)sx;
string theHeader = menuItem.Header.ToString();
if (theHeader.Contains("90")) {
Line ow = (Line)ex.OriginalSource;
rt = new RotateTransform(90, 25, 50);
ow.RenderTransform = rt;
}
});
g.ContextMenu.Items.Add(newMenuItem1);
g.ContextMenu.Items.Add(newMenuItem2);
g.ContextMenu.Items.Add(newMenuItem3);
Canvas.SetTop(g, 18);
Canvas.SetLeft(g, 18);
MyCanvas.Children.Add(g);
///////
I also tried:
private static T FindAncestor<T>(DependencyObject current)
where T : DependencyObject
{
do
{
if (current is T)
{
return (T)current;
}
current = VisualTreeHelper.GetParent(current);
}
while (current != null);
return null;
}
but it does not work. My next plan is to get coordinates off the canvas, and try to determine what control sits there. This will become tricky though if an object is transformed, because I believe the UI sees it at the original position. I've experimented with other controls as well, like the TextBox and get similar issues.
A really quick and dirty way to do this would be to add your line to the menu item's tag property and retrieve it in the PreviewMouseDown handler
When creating your context menu:
newMenuItem1.Tag = g;
In you handler:
Line ow = ((FrameworkElement)ex.Source).Tag as Line;
The less quick and dirty way to do this would be to use the ContextMenuOpening event on your line as that should be sent with the sender equal to the control itself. You could then store a reference to the line somewhere and retrieve it again in the menu item click event. This works better when you have multiple lines (which I'm guess is what you intend) and just one context menu (instead of producing a bunch of copies of the same menu as you are doing now).

Using a Storyboard animation on a programmatically-added control

I'm trying to fade in a new control to my application's "app" area which is programmatically added after the existing controls are removed. My code looks like this:
void settingsButton_Clicked(object sender, EventArgs e)
{
ContentCanvas.Children.Clear();
// Fade in settings panel
NameScope.SetNameScope(this, new NameScope());
SettingsPane s = new SettingsPane();
s.Name = "settingsPane";
this.RegisterName(s.Name, s);
this.Resources.Add(s.Name, s);
Storyboard sb = new Storyboard();
DoubleAnimation settingsFade = new DoubleAnimation();
settingsFade.From = 0;
settingsFade.To = 1;
settingsFade.Duration = new Duration(TimeSpan.FromSeconds(0.33));
settingsFade.RepeatBehavior = new RepeatBehavior(1);
Storyboard.SetTargetName(settingsFade, s.Name);
Storyboard.SetTargetProperty(settingsFade, new PropertyPath(UserControl.OpacityProperty));
ContentCanvas.Children.Add(s);
sb.Children.Add(settingsFade);
sb.Begin();
}
However, when I run this code, I get the error "No applicable name scope exists to resolve the name 'settingsPane'."
What am I possibly doing wrong? I'm pretty sure I've registered everything properly :(
I wouldn't hassle with the NameScopes etc. and would rather use Storyboard.SetTarget instead.
var b = new Button() { Content = "abcd" };
stack.Children.Add(b);
var fade = new DoubleAnimation()
{
From = 0,
To = 1,
Duration = TimeSpan.FromSeconds(5),
};
Storyboard.SetTarget(fade, b);
Storyboard.SetTargetProperty(fade, new PropertyPath(Button.OpacityProperty));
var sb = new Storyboard();
sb.Children.Add(fade);
sb.Begin();
I solved the problem using this as parameter in the begin method, try:
sb.Begin(this);
Because the name is registered in the window.
I agree, the namescopes are probably the wrong thing to use for this scenario. Much simpler and easier to use SetTarget rather than SetTargetName.
In case it helps anyone else, here's what I used to highlight a particular cell in a table with a highlight that decays to nothing. It's a little like the StackOverflow highlight when you add a new answer.
TableCell cell = table.RowGroups[0].Rows[row].Cells[col];
// The cell contains just one paragraph; it is the first block
Paragraph p = (Paragraph)cell.Blocks.FirstBlock;
// Animate the paragraph: fade the background from Yellow to White,
// once, through a span of 6 seconds.
SolidColorBrush brush = new SolidColorBrush(Colors.Yellow);
p.Background = brush;
ColorAnimation ca1 = new ColorAnimation()
{
From = Colors.Yellow,
To = Colors.White,
Duration = new Duration(TimeSpan.FromSeconds(6.0)),
RepeatBehavior = new RepeatBehavior(1),
AutoReverse = false,
};
brush.BeginAnimation(SolidColorBrush.ColorProperty, ca1);
It is possible odd thing but my solution is to use both methods:
Storyboard.SetTargetName(DA, myObjectName);
Storyboard.SetTarget(DA, myRect);
sb.Begin(this);
In this case there is no error.
Have a look at the code where I have used it.
int n = 0;
bool isWorking;
Storyboard sb;
string myObjectName;
UIElement myElement;
int idx = 0;
void timer_Tick(object sender, EventArgs e)
{
if (isWorking == false)
{
isWorking = true;
try
{
myElement = stackObj.Children[idx];
var possibleIDX = idx + 1;
if (possibleIDX == stackObj.Children.Count)
idx = 0;
else
idx++;
var myRect = (Rectangle)myElement;
// Debug.WriteLine("TICK: " + myRect.Name);
var dur = TimeSpan.FromMilliseconds(2000);
var f = CreateVisibility(dur, myElement, false);
sb.Children.Add(f);
Duration d = TimeSpan.FromSeconds(2);
DoubleAnimation DA = new DoubleAnimation() { From = 1, To = 0, Duration = d };
sb.Children.Add(DA);
myObjectName = myRect.Name;
Storyboard.SetTargetName(DA, myObjectName);
Storyboard.SetTarget(DA, myRect);
Storyboard.SetTargetProperty(DA, new PropertyPath("Opacity"));
sb.Begin(this);
n++;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + " " + DateTime.Now.TimeOfDay);
}
isWorking = false;
}
}

Resources