Folks!
I lean C# and I'm using the book "Head First C# - 3rd Edition.". But my first example not work. My first program successfully build, then I am press button "start" program crashing.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Media.Animation;
// Документацию по шаблону элемента "Основная страница" см. по адресу http://go.microsoft.com/fwlink/?LinkId=234237
namespace Save_The_Humans
{
/// <summary>
/// Основная страница, которая обеспечивает характеристики, являющимися общими для большинства приложений.
/// </summary>
public sealed partial class MainPage : Save_The_Humans.Common.LayoutAwarePage
{
Random random = new Random();
public MainPage()
{
this.InitializeComponent();
}
/// <summary>
/// Заполняет страницу содержимым, передаваемым в процессе навигации. Также предоставляется любое сохраненное состояние
/// при повторном создании страницы из предыдущего сеанса.
/// </summary>
/// <param name="navigationParameter">Значение параметра, передаваемое
/// <see cref="Frame.Navigate(Type, Object)"/> при первоначальном запросе этой страницы.
/// </param>
/// <param name="pageState">Словарь состояния, сохраненного данной страницей в ходе предыдущего
/// сеанса. Это значение будет равно NULL при первом посещении страницы.</param>
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
}
/// <summary>
/// Сохраняет состояние, связанное с данной страницей, в случае приостановки приложения или
/// удаления страницы из кэша навигации. Значения должны соответствовать требованиям сериализации
/// <see cref="SuspensionManager.SessionState"/>.
/// </summary>
/// <param name="pageState">Пустой словарь, заполняемый сериализуемым состоянием.</param>
protected override void SaveState(Dictionary<String, Object> pageState)
{
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
AddEnemy();
}
private void AddEnemy()
{
ContentControl enemy = new ContentControl();
enemy.Template = Resources["EnemyTemplate"] as ControlTemplate;
AnimateEnemy(enemy, 0, playArea.ActualWidth - 100, "(Canvas.Left)");
AnimateEnemy(enemy, random.Next((int)playArea.ActualHeight - 100),
random.Next((int)playArea.ActualHeight - 100), "(Canvas.Top)");
playArea.Children.Add(enemy);
}
private void AnimateEnemy(ContentControl enemy, double from, double to, string propertyToAnimate)
{
Storyboard storyboard = new Storyboard() { AutoReverse = true, RepeatBehavior = RepeatBehavior.Forever };
DoubleAnimation animation = new DoubleAnimation()
{
From = from,
To = to,
Duration = new Duration(TimeSpan.FromSeconds(random.Next(4, 6)))
};
Storyboard.SetTarget(animation, enemy);
Storyboard.SetTargetProperty(animation, propertyToAnimate);
storyboard.Children.Add(animation);
storyboard.Begin();
}
}
}
VS 2012 for Windows 8 said me: "'maxValue' must be greater than zero."
What did I do wrong and how can I fix this bag?
Link source code and VS project: https://dropmefiles.com/RmCbZ
Screen error message:
This is caused by random.Next((int)playArea.ActualHeight - 100). When you are using .Next(maxvalue) with just one value it has to be a positive one.
Additional information: When using it like .Next(minvalue, maxvalue) it is ok having two negative values.
maxValue
Type: System.Int32
The exclusive upper bound of the random number to be generated. maxValue must be greater than or equal to 0. (From here)
What you can do to resolve this problem:
Make sure that playArea.ActualHeight is greater than 100. (set a breakpoint and check the value of this variable)
Are you sure you have to substract 100? (Depends on your scenario)
You could use random.Next((int)playArea.ActualHeight - 100, /*maxvalue*/)
Edit: I took the time to scan through the according chapter of this book and noticed, that the default dimensions of a Canvas (called playArea) is 100x100 and nothing tells you to increase the size... According to your original problem I assume that you accidently made it even smaller. So you could try going back to the designer and increase the size of playArea (and maybe the whole window).
Related
I have some csv files that I try to read and then divide them in two columns or list and plot them in a mathematical chart.
The csv files contains two columns, one for voltage and one for time. I read the csv files and use Interactive Data display
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Controls;
namespace TWord.Pages
{
/// <summary>
/// Interaction logic for Pico.xaml
/// </summary>
public partial class Pico : Page
{
/// <summary>
/// Members
/// </summary>
int numEvent;
StreamReader myCSVStream;
int currentSlide;
ListOfList<double> AllEventsList;
/// <summary>
/// Constructor
/// </summary>
public Pico()
{
InitializeComponent();
}
#region Button Event
/// <summary>
/// Implement the button function to read the csv files.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCSV_Browser_Click(object sender, RoutedEventArgs e)
{
// Creates a null stream
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = openFileDialog.RestoreDirectory = true;
// Initial directory to open to
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
// only open the csv files
openFileDialog.Filter = "csv files (*.csv)|*.csv|All files (*.*)|*.*";
// Applying filter index
openFileDialog.FilterIndex = 2;
// Create a new instance of list of lists and
// run the ReadCSV for each of files.
if (openFileDialog.ShowDialog() == true)
{
// Names of the files imported
string[] filePath = openFileDialog.FileNames;
// Path of the file
numEvent = openFileDialog.FileNames.Length;
AllEventsList = new ListOfList<double>();
foreach (var address in filePath)
{
ReadCSV(address);
}
}
// only if thr browser had done the work
//if (AllEventsList != null)
// DrawPlot(0);
}
#endregion
#region Help Functions
/// <summary>
/// Help function to make graphs and reading the csv files.
/// </summary>
private void ReadCSV(string s)
{
string line;
// new stream to read each line
myCSVStream = new StreamReader(s);
// one list for voltage
List<double> voltage = new List<double>();
// one list for time
List<double> time = new List<double>();
// reading whole csv file and split it into two columns
while ((line = myCSVStream.ReadLine()) != null)
{
try
{
string[] parm = line.Trim().Split(',');
voltage.Add(double.Parse(parm[0], CultureInfo.InvariantCulture));
time.Add(double.Parse(parm[1], CultureInfo.InvariantCulture));
}
catch { }
}
// add it to the list of lists.
AllEventsList.Add(voltage);
AllEventsList.Add(time);
// Draw the first plot
DrawPlot(0);
}
#endregion
#region
/// <summary>
/// Drawing the plot for the CSVs
/// </summary>
private void DrawPlot(int i)
{
// Array for Voltage
double[] voltage = AllEventsList[2 * i].ToArray();
// Array for time
double[] time = AllEventsList[2 * i + 1].ToArray();
//plot to the linegraph
linegraph.Plot(time,voltage,);
}
#endregion
}
}
The XAML file to this is according to :
<GroupBox Grid.Row="1" Grid.Column="0" Header="Sampled points" Style="{StaticResource GroupboxStyle}" FontFamily="{StaticResource LatoThin}" Foreground="{StaticResource TercoTextBrush}">
<d3:Chart BottomTitle="Time" LeftTitle="voltage" Margin="-10" Style="{DynamicResource ChartStyle}">
<d3:LineGraph x:Name="linegraph" Description="Simple linegraph" Stroke="Blue" StrokeThickness="2" Margin="-19,0,0,-23"/>
</d3:Chart>
</GroupBox>
The result is that the line itself sticks out of the graph grid. as image below: Ive been sitting here and tried to modify the style of the graph with no luck. Anyone had this problem? The reason I use Interactive Data display is that it is very simple to use. Just needs two arrays and you are done. If you have any better suggestions that is Free of charge I would be happy to know about it. but not Oxyplot . I couldn't make it work
Your margin for your LineGraph XAML markup is shifting the line.
Margin is specified as:
<object Margin="left,top,right,bottom"/>
So a margin of -19,0,0,-23 specifies a shift to a xaml element 19 units to the left and 23 units down. Which is what you are seeing.
Change:
<d3:LineGraph x:Name="linegraph" Margin="-19,0,0,-23" Description="Simple linegraph" Stroke="Blue" StrokeThickness="2" />
To:
<d3:LineGraph x:Name="linegraph" Margin="0" Description="Simple linegraph" Stroke="Blue" StrokeThickness="2" />
I have a WPF xaml template and associated code behind with a variety of controls. The user can move these controls around so that one has the layout that one desires. However, once the user restarts the program, the controls return to their original locations. How do I make it so that the user can save the layout?
You can save, reload the layout (xaml):
After the user changes the layout [on Window Closing event], You can save a XAML file base changed layout using XamlWriter static class. In fact you serialize the container control and save it in a file.
Also you need some codes [in the window constructor after InitializeComponent()] to reload serialized layout of the container control [and its controls] from the file.
I put a sample (wrote by Matt Searles), here:
<StackPanel>
<WrapPanel x:Name="wrapPanel1" Height="200"></WrapPanel>
<Button Click="AddButton">Add Button</Button>
<Button Click="SaveButtons">Save Buttons</Button>
<Button Click="ReloadButtons">Reload Buttons</Button>
</StackPanel>
Code behind:
/// <summary>
/// Add a button to wrapPanel1
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddButton(object sender, RoutedEventArgs e)
{
// Create the Button.
Button button = new Button();
button.Height = 50;
button.Width = 100;
button.Background = Brushes.AliceBlue;
button.Content = "Click Me";
wrapPanel1.Children.Add(button);
}
/// <summary>
/// Save wrapPanel1 to AA.xaml
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SaveButtons(object sender, RoutedEventArgs e)
{
StringBuilder outstr = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
XamlDesignerSerializationManager dsm = new XamlDesignerSerializationManager(XmlWriter.Create(outstr, settings));
dsm.XamlWriterMode = XamlWriterMode.Expression;
XamlWriter.Save(wrapPanel1, dsm);
string savedControls = outstr.ToString();
File.WriteAllText(#"AA.xaml", savedControls);
}
/// <summary>
/// Reload the buttons in AA.xaml
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ReloadButtons(object sender, RoutedEventArgs e)
{
StreamReader sR = new StreamReader(#"AA.xaml");
string text = sR.ReadToEnd();
sR.Close();
StringReader stringReader = new StringReader(text);
XmlReader xmlReader = XmlReader.Create(stringReader);
WrapPanel wp = (WrapPanel)System.Windows.Markup.XamlReader.Load(xmlReader);
wrapPanel1.Children.Clear(); // clear the existing children
foreach (FrameworkElement child in wp.Children) // and for each child in the WrapPanel we just loaded (wp)
{
wrapPanel1.Children.Add(CloneFrameworkElement(child)); // clone the child and add it to our existing wrap panel
}
}
/// <summary>
/// Clone a framework element by serializing and deserializing it
/// </summary>
/// <param name="originalElement"></param>
/// <returns></returns>
FrameworkElement CloneFrameworkElement(FrameworkElement originalElement)
{
string elementString = XamlWriter.Save(originalElement);
StringReader stringReader = new StringReader(elementString);
XmlReader xmlReader = XmlReader.Create(stringReader);
FrameworkElement clonedElement = (FrameworkElement)XamlReader.Load(xmlReader);
return clonedElement;
}
So I've been digging into the whole SuspendLayout()/ResumeLayout() logic for a while now and I've been trying to implement it in the most efficient manner. One question I'm unable to find an answer for is that of which I've asked in the title : Does the BringToFront() method go before or after you call ResumeLayout()? Does it matter? My initial thought process is no, it doesn't matter, because it's only changing the z-index of the control and not effecting the control's layout, but I just want to be sure.
Here's block of code from my project where my question comes into play:
Note:This project runs on a Motorola MC65 mobile device and uses .net compact 3.5 framework
/// <summary>
/// Initializes the <see cref="VerifyReplacementPanel"/> class
/// </summary>
/// <param name="hostControl">The panel this control is being added to</param>
/// <param name="original">The product being replaced</param>
/// <param name="replacement">The product replacing with</param>
/// <param name="logHelper">The log helper interface</param>
public VerifyReplacementPanel(Control hostControl, ProductModel original, ProductModel replacement, ILogHelper logHelper)
{
hostControl.SuspendLayout();
SuspendLayout();
HostControl = hostControl;
Product = original;
Replacement = replacement;
_logHelper = logHelper;
Size = Size.FullScreen();
// original product panel
var panOrig = new blkPan(472, 75) { Location = new Point(4, 147), BackColor = Color.White };
var originalProductPanel = new ProductPanelArrayModel(panOrig, _logHelper);
originalProductPanel.AddPanelWithPic(original);
Controls.Add(panOrig);
// replacement product panel
var panRepl = new blkPan(472, 75) { Location = new Point(4, panOrig.B + 100), BackColor = Color.White };
var replacementProductPanel = new ProductPanelArrayModel(panRepl, _logHelper);
replacementProductPanel.AddPanelWithPic(replacement);
Controls.Add(panRepl);
// no button
var btnNo = new PushButton("No", ObjectName, true) { Location = new Point(38, Bottom - 93 - 36) };
btnNo.Click += btnNo_Click;
Controls.Add(btnNo);
_btnNoTop = btnNo.Top;
// yes button
var btnYes = new PushButton("Yes", ObjectName, true) { Location = new Point(259, btnNo.Top) };
btnYes.Click += btnYes_Click;
Controls.Add(btnYes);
ResumeLayout(false);
HostControl.Controls.Add(this);
BringToFront();
HostControl.ResumeLayout();
}
My question is interested in this section :
ResumeLayout(false);
HostControl.Controls.Add(this);
BringToFront();
HostControl.ResumeLayout();
Also, am I even using it correctly? Thank you for your time.
I'm currently facing a problem with printing a Plotmodel to an XPS-File.
What I have so far:
/// <summary>
/// Plotmodel to XPS-File
/// </summary>
/// <param name="model">The model</param>
/// <param name="fileName">The fileName</param>
/// <param name="width">Width of the model</param>
/// <param name="height">Height of the model</param>
public void Export(PlotModel model, string fileName, double width, double height)
{
try
{
using (Package xpsPackage = Package.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (var doc = new XpsDocument(xpsPackage))
{
var g = new Grid();
var p = new OxyPlot.Wpf.Plot { Model = model }; //Problem?
g.Children.Add(p);
var size = new Size(width, height);
g.Measure(size);
g.Arrange(new Rect(size));
g.UpdateLayout();
if (xpsdw == null) //XpsDocumentWriter xpsdw
xpsdw = XpsDocument.CreateXpsDocumentWriter(doc);
}
if (xpsdw != null)
{
xpsdw.Write(g);
}
}
}
}
This Code works fine (once), but the Problem is: No matter how often you use this method, you will always have just one Page with data. So if you want to print a second Plotmodel into the XPS-File the old one is deleted and you can only see the new one.
So the Question is:
Do you have an idea, how to append the new Plotmodel to the old XPS-File without overwriting it?
I also tried to use:
XpsExporter.Export(model, fileName, width, height);
instead of my function, but this didn't worked either.
If you know in advance that you will be writing multiple plots to a single file, you should look into VisualsToXpsDocument.
If you truly must append additional pages to an existing document on disk, it will be more difficult. You will need to dig down through the existing document to get to a FixedDocument (a child of the FixedDocumentSequence). Once you have the FixedDocument, you can add a new PageContent object to it. There is an example near the bottom of this thread.
I need an Image that is grayed out when disabled (IsEnabled=False). A grayed out version of the image can be produced by reading the BitmapImage into a FormatConvertedBitmap which is shown here.
I have been able to get this working with a UserControl but now I would like the same behavior in a specialized Image class for more flexibility. I don't care if this is implemented in XAML, code-behind or both, but it needs to be a subclass of Image.
The usage could be:
<DisableableImage Source="Images/image1.png" />
<DisableableImage Source="Images/image1.png" IsEnabled="False" />
<!-- Since IsEnabled is inherited down the tree,
the image will be grayed out like the rest of the button -->
<Button IsEnabled="False">
<StackPanel Orientation="Horizontal">
<TextBlock>OK</TextBlock>
<DisableableImage Source="Images/ok.png" />
</StackPanel>
</Button>
Have a look at this link
EDIT:
Or this one (all you need is the AutoGreyableImage class)
I made a little comparison based on the following solutions.
The approaches in the link provided by the OP
The links provided by Thomas Levesque
AutoDisabledImage
AutoGreyableImage
Greyscale Effect
Since I already had a licens for the Infragistics Net Advantage for WPF it was easy to try it out
Here is the result
So the best approach depends on what results you are after. As for me, I think the result produced by AutoDisabledImage from Infragistics is too bright, AutoGreyableImage does a pretty good job (Identical result to Approach 1 (OP link)) and GreyscaleEffect produces the best result.
if you use this a lot consider creating a custom Effect introduced with .NET 3.5 SP1 (not bitmapeffect) to render such an operation on your GPU. this effect can then be easily controlled by triggers.
More complete version of the AutoGreyableImage by Thomas Lebrun. For anyone interested, I started using Thomas Lebruns class and ran into a couple of nullreference exceptions, as well as finding out that an image would not be disabled if the isEnabled property was set first and the source set after.
So here's the class that finally did the trick for me. À propos, you can of course add the matter of opacity into this, but I decided to leave that up to the xaml around the image.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Media;
namespace MyDisabledImages
{
/// <summary>
/// Class used to have an image that is able to be gray when the control is not enabled.
/// Based on the version by Thomas LEBRUN (http://blogs.developpeur.org/tom)
/// </summary>
public class AutoGreyableImage : Image
{
/// <summary>
/// Initializes a new instance of the <see cref="AutoGreyableImage"/> class.
/// </summary>
static AutoGreyableImage()
{
// Override the metadata of the IsEnabled and Source property.
IsEnabledProperty.OverrideMetadata(typeof(AutoGreyableImage), new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnAutoGreyScaleImageIsEnabledPropertyChanged)));
SourceProperty.OverrideMetadata(typeof(AutoGreyableImage), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnAutoGreyScaleImageSourcePropertyChanged)));
}
protected static AutoGreyableImage GetImageWithSource(DependencyObject source)
{
var image = source as AutoGreyableImage;
if (image == null)
return null;
if (image.Source == null)
return null;
return image;
}
/// <summary>
/// Called when [auto grey scale image source property changed].
/// </summary>
/// <param name="source">The source.</param>
/// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
protected static void OnAutoGreyScaleImageSourcePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs ars)
{
AutoGreyableImage image = GetImageWithSource(source);
if (image != null)
ApplyGreyScaleImage(image, image.IsEnabled);
}
/// <summary>
/// Called when [auto grey scale image is enabled property changed].
/// </summary>
/// <param name="source">The source.</param>
/// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
protected static void OnAutoGreyScaleImageIsEnabledPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
AutoGreyableImage image = GetImageWithSource(source);
if (image != null)
{
var isEnabled = Convert.ToBoolean(args.NewValue);
ApplyGreyScaleImage(image, isEnabled);
}
}
protected static void ApplyGreyScaleImage(AutoGreyableImage autoGreyScaleImg, Boolean isEnabled)
{
try
{
if (!isEnabled)
{
BitmapSource bitmapImage = null;
if (autoGreyScaleImg.Source is FormatConvertedBitmap)
{
// Already grey !
return;
}
else if (autoGreyScaleImg.Source is BitmapSource)
{
bitmapImage = (BitmapSource)autoGreyScaleImg.Source;
}
else // trying string
{
bitmapImage = new BitmapImage(new Uri(autoGreyScaleImg.Source.ToString()));
}
FormatConvertedBitmap conv = new FormatConvertedBitmap(bitmapImage, PixelFormats.Gray32Float, null, 0);
autoGreyScaleImg.Source = conv;
// Create Opacity Mask for greyscale image as FormatConvertedBitmap does not keep transparency info
autoGreyScaleImg.OpacityMask = new ImageBrush(((FormatConvertedBitmap)autoGreyScaleImg.Source).Source); //equivalent to new ImageBrush(bitmapImage)
}
else
{
if (autoGreyScaleImg.Source is FormatConvertedBitmap)
{
autoGreyScaleImg.Source = ((FormatConvertedBitmap)autoGreyScaleImg.Source).Source;
}
else if (autoGreyScaleImg.Source is BitmapSource)
{
// Should be full color already.
return;
}
// Reset the Opcity Mask
autoGreyScaleImg.OpacityMask = null;
}
}
catch (Exception)
{
// nothin'
}
}
}
}
Create a DisableableImage class that is a typical WPF control. Inside, place two elements: the image, and a rectangle that appears only when the control is disabled. The rectangle should be the same width and height as the image, and it should overlay the image. With a color of gray and an alpha of somewhere around 40%, you should get an effect similar to actually graying out the image -- without all the effort to actually modify the image itself.