I am looking for a way to draw a simple shape on a canvas with the shape being made in another class ShapeManager. This ShapeManager decides what shape it is and assigns a color to it coming from ColorManager.
I apologize in advance for the long code, this is my first post and I am still just learning C# and OOP in general.
Canvas Window
A window with a canvas on it (cvs_Drawing). Should place a shape it gets from CanvasManager.ShapeManager.CreateNewShape(), but throws a NullReference.
public partial class CanvasWindow : Window
{
public string CanvasName { get; set; }
public CanvasManager CanvasManager { get; set; }
public CanvasWindow(string name)
{
InitializeComponent();
CanvasManager= new CanvasManager();
CanvasName = name;
this.Title = CanvasName;
}
//Click event to draw the chosen shape on canvas
private void cvs_Drawing_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
try
{
Shape shapeDrawing = CanvasManager.ShapeManager.CreateNewShape();
Point location = e.GetPosition(cvs_Drawing);
Canvas.SetTop(shapeDrawing, location.Y);
Canvas.SetLeft(shapeDrawing, location.X);
cvs_Drawing.Children.Add(shapeDrawing);
}
//catch block here
CanvasManager
Creates CanvasWindows and provides interaction between CanvasWindow and ShapeManager. Multiple CanvasWindows is normally a possibility.
public CanvasWindow CanvasWindow { get; set; }
public MainWindow MainWindow { get; set; }
public ShapeManager ShapeManager { get; set; }
//Constructors
public CanvasManager(MainWindow w)
{
MainWindow = w;
ShapeManager = new ShapeManager(w);
}
public CanvasManager() { }
//Add a brand new canvas
public CanvasWindow CreateNewCanvas(string name)
{
CanvasWindow = new CanvasWindow(name);
return CanvasWindow;
}
ShapeManager
Creates Shapes needed for CanvasWindow
public MainWindow Window { get; set; }
public Shape NewShape { get; set; }
public ColorManager ColorManager { get; set; }
public List<string> ListShapes { get; set; } = new List<string>();
public ShapeManager(MainWindow w)
{
Window = w;
ListShapes.Add("Ellipse");
ListShapes.Add("Rectangle");
ColorManager = new ColorManager();
}
public ShapeManager() { }
#region Shape Creation
public Shape CreateNewShape()
{
Color newShapeColor = ColorManager.CreateNewColor();
if (Window.cb_Shapes.SelectedItem.ToString() == "Ellipse")
{
NewShape = new Ellipse
{
Width = Int32.Parse(Window.tb_Width.Text),
Height = Int32.Parse(Window.tb_Height.Text),
Fill = new SolidColorBrush(newShapeColor)
};
return NewShape;
}
else
{
NewShape = new Rectangle
{
Width = Int32.Parse(Window.tb_Width.Text),
Height = Int32.Parse(Window.tb_Height.Text),
Fill = new SolidColorBrush(newShapeColor)
};
return NewShape;
}
}
ColorManager
Creates the color for the shape that was created in ShapeManager.
public MainWindow Window { get; set; }
public Color NewColor { get; set; }
//Constructors
public ColorManager(MainWindow w)
{
Window = w;
}
//public ColorManager(){}
//Add new color method
public Color CreateNewColor()
{
NewColor = new Color
{
A = 255,
R = Byte.Parse(Window.tb_RedValue.Text),
G = Byte.Parse(Window.tb_GreenValue.Text),
B = Byte.Parse(Window.tb_BlueValue.Text)
};
return NewColor;
}
TL;DR. I can't create a shape on the canvas, always get a NullReference every time I click on the canvas.
Your code has an error here
public CanvasManager(){ ShapeManager = new ShapeManager(MainWindow); }
// CanvasManager.cs , Line 33
you passed MainWindow, which is null
and it comes from here
public CanvasManager CanvasManager { get; set; } = new CanvasManager();
// CanvasWindow.xaml.cs, Line 28
You can correct your code like this:
// in CanvasWindow.xaml.cs, Line 28
public CanvasWindow(string name, MainWindow mainWindow)
{
InitializeComponent();
**CanvasManager = new CanvasManager(mainWindow);**
CanvasName = name;
//ShapeManager = new ShapeManager();
this.Title = CanvasName;
...
...
...
// NewDrawingWindow.xaml.cs, Line 47
CanvasWindow canvasWindow = new CanvasWindow(tb_Drawing_Name.Text, Window);
// CanvasManager.cs, Line 38
CanvasWindow = new CanvasWindow(name, MainWindow);
Related
I would like to serialize this class by creating multiple objects. the method works and the objects are saved in the xml file but the values of the List variable are always the same for all objects. how can i do to correct.?
[Serializable()]
public class TextureValues
{
[XmlAttribute("Texture_Info")]
public string Name { get; set; }
public string Date { get; set; }
public List<Point> Points { get; set; }
public int Pensize { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public TextureValues() { }
public TextureValues(string name, string date ,List<Point> points,int pensize,int width,int heigth)
{
this.Name = name;
this.Date = date;
this.Points = points;
this.Pensize = pensize;
this.Width = width;
this.Height = heigth;
}
}
Below the method I used in the form to enter object parameters:
public partial class TextureMaker : Form
{
List<TextureValues> textureInfo = new List<TextureValues>();
List<Point> p = new List<Point>();
public TextureMaker()
{
InitializeComponent();
}
private void panelText_Click(object sender, EventArgs e)
{
p.Add(panelText.PointToClient(Cursor.Position));
}
private void buttonSave_Click(object sender, EventArgs e)
{
textureInfo.AddRange(new TextureValues[]
{
new TextureValues(textBoxName.Text,DateTime.Now.ToString(),p,(int)numericPenSize.Value,(int)numTextWidth.Value,(int)numTextHeight.Value)
});
var path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\textures.xml";
FileStream stream = File.Create(path);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<TextureValues>));
xmlSerializer.Serialize(stream, textureInfo);
stream.Close();
p.Clear();
}
}
What's wrong with this picture?
Instead of displaying a nice picture of a prehistoric plant, the string of the location of the bitmap is being displayed!
Here's the XAML (snippet):
<DataTemplate x:Key="YoungPicCell">
<StackPanel Orientation="Horizontal">
<Image Height="200" Width="200" Stretch="None" Source="{Binding Path=YoungPicBmp}" />
</StackPanel>
</DataTemplate>
The filenames (and other data) are loaded at runtime from an XML file.
Here is the data being loaded from the XML file at runtime:
public class LVData
{
public string Name { get; set; }
public string YoungPic { get; set; }
public BitmapSource YoungPicBmp { get { return new BitmapImage(new Uri("{YoungPic}")); } }
public string MediumPic { get; set; }
public BitmapSource MediumPicBmp { get { return new BitmapImage(new Uri("{MediumPic}")); } }
public string AdultPic { get; set; }
public BitmapSource AdultPicBmp { get { return new BitmapImage(new Uri("{AdultPic}")); } }
public bool SaltWater { get; set; }
public bool FreshWater { get; set; }
public bool Grasslands { get; set; }
public bool Swamp { get; set; }
public bool TropicalForest { get; set; }
public bool Forest { get; set; }
public bool ForestEdge { get; set; }
public bool Sand { get; set; }
public bool Coastal { get; set; }
public bool RiverBorder { get; set; }
public bool LakeBorder { get; set; }
public bool Floodplain { get; set; }
}
public class WindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
//called when a property is changed
protected void RaisePropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
private ObservableCollection<LVData> _plantList = new ObservableCollection<LVData>();
public ObservableCollection<LVData> lsvData
{
get { return _plantList; }
set { _plantList = value; RaisePropertyChanged("lsvData"); }
}
public void PopulateDataFromXML(string filename)
{
XDocument loaded = XDocument.Load(#"DinoIslandPlants.xml");
var Plants = from x in loaded.Descendants("Plants")
select new
{
Name = x.Descendants("Name").First().Value,
YoungPic = x.Descendants("YoungPic").First().Value,
MediumPic = x.Descendants("MediumPic").First().Value,
AdultPic = x.Descendants("AdultPic").First().Value,
SaltWater = x.Descendants("SaltWater").First().Value,
FreshWater = x.Descendants("FreshWater").First().Value,
Grasslands = x.Descendants("Grasslands").First().Value,
Swamp = x.Descendants("Swamp").First().Value,
TropicalForest = x.Descendants("TropicalForest").First().Value,
Forest = x.Descendants("Forest").First().Value,
ForestEdge = x.Descendants("ForestEdge").First().Value,
Sand = x.Descendants("Sand").First().Value,
Coastal = x.Descendants("Coastal").First().Value,
RiverBorder = x.Descendants("RiverBorder").First().Value,
LakeBorder = x.Descendants("LakeBorder").First().Value,
Floodplain = x.Descendants("Floodplain").First().Value
};
foreach (var _plant in Plants)
{
_plantList.Add(new LVData {
Name = _plant.Name,
YoungPic = _plant.YoungPic,
MediumPic = _plant.MediumPic,
AdultPic = _plant.AdultPic,
SaltWater = Convert.ToBoolean(_plant.SaltWater),
FreshWater = Convert.ToBoolean(_plant.FreshWater),
Grasslands = Convert.ToBoolean(_plant.Grasslands),
Swamp = Convert.ToBoolean(_plant.Swamp),
TropicalForest = Convert.ToBoolean(_plant.TropicalForest),
Forest = Convert.ToBoolean(_plant.Forest),
Sand = Convert.ToBoolean(_plant.Sand),
Coastal = Convert.ToBoolean(_plant.Coastal),
RiverBorder = Convert.ToBoolean(_plant.RiverBorder),
LakeBorder = Convert.ToBoolean(_plant.LakeBorder),
Floodplain = Convert.ToBoolean(_plant.Floodplain)
});
}
RaisePropertyChanged("lsvData");
}
}
When binding to an Image control you need to bind to a BitmapSource. This should be pretty straight forward. Change the type of the property (or add a new one) to BitmapSource and then in the get do something like this:
... get { return new BitmapImage(new Uri("{PathToImage}")); }
where PathToImage is a recognizable path to the image you want to display.
I would like to know if it is possible to match object with their instance name.
I got :
class AnimatedEntity : DrawableEntity
{
Animation BL { get; set; }
Animation BR { get; set; }
Animation TL { get; set; }
Animation TR { get; set; }
Animation T { get; set; }
Animation R { get; set; }
Animation L { get; set; }
Animation B { get; set; }
Orientation orientation ;
public virtual int Draw(SpriteBatch spriteBatch, GameTime gameTime)
{
//draw depends on orientation
}
}
and
enum Orientation {
SE, SO, NE, NO,
N , E, O, S,
BL, BR, TL, TR,
T, R, L, B
}
Where Orientation is an Enum and Animation a class.
Can I call the correct Animation from the Orientation with the same name ?
Instead of storing the Animations in properties, how about using a dictionary?
Dictionary<Orientation, Animation> anim = new Dictionary<Orientation, Animation> {
{ Orientation.BL, blAnimation },
{ Orientation.BR, brAnimation },
{ Orientation.TL, tlAnimation },
{ Orientation.TR, trAnimation },
{ Orientation.T, tAnimation },
{ Orientation.R, rAnimation },
{ Orientation.L, lAnimation },
{ Orientation.B, bAnimation }
};
You can then use anim[orientation] to access the appropriate animation.
Indeed a Dictionary would be a good option. It could even have an Animation index if the animations would be set from outside:
class AnimatedEntity : DrawableEntity
{
Dictionary<Orientation, Animation> Animations { get; set; }
public AnimatedEntity()
{
Animations = new Dictionary<Orientation, Animation>();
}
public Animation this[Orientation orientation]
{
get{ return Animations[orientation]; }
set{ Animations[orientation] = value;}
}
Orientation Orientation { get; set; }
public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
{
Animation anim = Animations[Orientation];
}
}
Would be used like:
AnimatedEntity entity = new AnimatedEntity();
entity[Orientation.B] = bAnimation;
entity[Orientation.E] = eAnimation;
entity[Orientation.SE] = seAnimation;
I have a Custom UIElement I created below.
class ClickItem : UIElement
{
public ClickItem()
{
}
public ClickItem(Color color)
{
this.Color = color;
Ellipse _e = new Ellipse();
_e.Fill = new SolidColorBrush(this.Color);
_e.StrokeThickness = 1;
_e.Stroke = Brushes.Black;
_e.Width = 10;
_e.Height = 10;
this.Plotter = _e;
}
public Point CenterPoint { get; set; }
public Ellipse Plotter { get; set; }
public Color Color { get; set; }
}
How do I make the Plotter Ellipse the visual for the UIElement so when I add a ClickItem to a canvas, the `Plotter' shows up.
Canvas canvas = new Canvas();
ClickItem clickItem = new ClickItem(Colors.Red);
canvas.Add(clickItem);
I can do this but I don't know how to get the ClickItem from this if I click on it.
canvas.Add(clickItem.Plotter);
I think you should inherit from user control, or some other relevant lower class, and add the ellipse as a child of your ClickItem.
I have a few types that make up a hierarchy like this:
+ Image0.Name
Effect0.Name
Effect1.Name
Effect2.Name
Layer0.Name
Layer1.Name
Layer2.Name
...
+ Image1.Name
Effect0.Name
Effect1.Name
Effect2.Name
Layer0.Name
Layer1.Name
Layer2.Name
...
+ Image2.Name
Effect0.Name
Effect1.Name
Effect2.Name
Layer0.Name
Layer1.Name
Layer2.Name
...
But I can't get my head around the data binding. Here is the code for the types:
public class Image
{
public string Name { get; set; }
public IEnumerable<Effect> Effects { get; set; }
public IEnumerable<Layer> Layers { get; set; }
}
public class Effect
{
public string Name { get; set; }
public Effect ( string name )
{
this.Name = name;
}
}
public class Layer
{
public string Name { get; set; }
public Layer ( string name )
{
this.Name = name;
}
}
public class EditorView : INotifyPropertyChanged
{
IEnumerable<Node> images;
public IEnumerable<Node> Images
{
get { return images; }
set
{
this.images = value;
this.RaisePropertyChanged ( "Images" );
}
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged ( string propertyName )
{
var handler = this.PropertyChanged;
if ( handler != null )
handler ( this, new PropertyChangedEventArgs ( propertyName ) );
}
}
Additionally these types (Effect, Layer) has a unique icon per type, if you can also show how to bind this, that would help me a lot in understanding it all.
This is how I normally do it, create a base class for the child items and then create I property that returns all the child Items
public class Image
{
public string Name { get; set;}
public IEnumerable<Effect> Effects { get; set; }
public IEnumerable<Layer> Layers { get; set; }
public IEnumerable<Node> Nodes { get { return ((IEnumerable<Node>)Layers).Union((IEnumerable<Node>)Effects); } }
}
public class Effect : Node
{
public Effect(string name)
{
this.Name = name;
}
}
public class Layer : Node
{
public Layer(string name) { this.Name = name; }
}
public class Node
{
public string Name { get; set; }
public Image Icon { get; set; }
}
You should be able to set the Image Property (url of image but you can change the property type) of the respective Effects and Layers and then I've already wired it up, this should work
<TreeView Height="221" HorizontalAlignment="Left" Margin="12,12,0,0" Name="treeView1"
VerticalAlignment="Top" Width="479" ItemsSource="{Binding Images}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"></TextBlock>
<Image Source="{Binding Icon}"></Image>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
EDIT
And then set the TreeView Item's DataContext to your ViewModel, just as an example I did this in the code behind:
Image img = new Image();
Effect effect = new Effect("Effect1");
Layer layer = new Layer("Layer1");
img.Name = "Image1";
List<Effect> effects = new List<Effect>();
effects.Add(effect);
img.Effects = effects;
List<Layer> layers = new List<Layer>();
layers.Add(layer);
img.Layers = layers;
List<WpfApplication1.Image> Images = new List<Image>();
Images.Add(img);
EditorView ev = new EditorView();
ev.Images = Images;
treeView1.DataContext = ev;
EDIT2: Pasted complete code (without using statements):
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new EditorView();
}
}
public class Image
{
public string Name { get; set;}
public IEnumerable<Effect> Effects { get; set; }
public IEnumerable<Layer> Layers { get; set; }
public IEnumerable<Node> Nodes { get { return ((IEnumerable<Node>)Layers).Union((IEnumerable<Node>)Effects); } }
}
public class Effect : Node
{
public Effect(string name)
{
this.Name = name;
}
}
public class Layer : Node
{
public Layer(string name) { this.Name = name; }
}
public class Node
{
public string Name { get; set; }
public string Icon { get; set; }
}
public class EditorView : INotifyPropertyChanged
{
public EditorView()
{
Image img = new Image();
WpfApplication1.Effect effect = new WpfApplication1.Effect("Effect1");
WpfApplication1.Layer layer = new Layer("Layer1");
img.Name = "Image1";
List<Effect> effects = new List<WpfApplication1.Effect>();
effects.Add(effect);
img.Effects = effects;
List<Layer> layers = new List<Layer>();
layers.Add(layer);
img.Layers = layers;
List<WpfApplication1.Image> Images = new List<Image>();
Images.Add(img);
this.Images = Images;
}
IEnumerable<Image> images;
public IEnumerable<Image> Images
{
get
{
return images;
}
set { this.images = value; this.RaisePropertyChanged("Images");
}
} public event
PropertyChangedEventHandler
PropertyChanged;
void RaisePropertyChanged(string propertyName)
{ var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You need to implement the HierarchicalDataTemplate. For sample of it look at the last of this article - http://msdn.microsoft.com/en-us/library/ms742521.aspx and this one - http://blogs.msdn.com/b/chkoenig/archive/2008/05/24/hierarchical-databinding-in-wpf.aspx