Custom drawing background in Canvas - wpf

I want to create Program for drawing shapes.
Something like this (http://www.codeproject.com/Articles/22952/WPF-Diagram-Designer-Part-1).
To do this I consider use WPF and MVVM(PRISM).
My requirement is custom background drawing.
During implementation I met with some obstacles:)
View Code
public class DrawingAreaCanvas : Canvas, IDrawingAreaCanvas
{
.......
private IDrawingAreaModelView _modelView;
[Dependency]
public IDrawingAreaModelView ModelView
{
get { return _modelView; }
set
{
_modelView = value;
DataContext = _modelView;
}
}
protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
base.OnRender(dc);
_modelView.OnRender(dc); // Pass drawing to modelview
}
}
Is this approach correct ?
Regards,
Leszek

Related

Style WindowsForms Project

I want to style my forms and some controls on my project, e.g. dataGridView.
I know, I can make a method like this an set it for every dataGridView.
public static void StyleDataGridView(DataGridView dg)
{
dg.BorderStyle = BorderStyle.FixedSingle;
dg.RowHeadersVisible = false;
....
}
My question: is there a possibility to do such style code only once in my project? How?
First step with userControl worked very well.
But how to handle the Click, DoubleClick and the CellMouseDown Event?
My code so far:
public partial class ucGridView : UserControl
{
public object DataSource
{
get { return dataGridView.DataSource; }
set { dataGridView.DataSource = value; }
}
public ucGridView()
{
InitializeComponent();
}
}

change main form controls by trigger event inside canvas

I am currently working on a project that required me to use a canvas in order to draw rectangles around specific places in a picture (to mark places)
Each rectangle (actually "rectangle" since it is also a custom class that I created by inheriting from the Grid class and contain a rectangle object) contains properties and data about the marked place inside the picture.
my main form contains controls such as TextBox ,DropDownLists and etc.
Now what I am trying to do is that for each time I am clicking on the "rectangle" object the main form controls will be filled with the object data.
I do not have access to those controls from the canvas class.
this code is inside the costume canvas class to add the object into the canvas:
protected override void OnMouseLeftButtonDown( MouseButtonEventArgs e)
{
if(e.ClickCount==2)
{
testTi = new TiTest();
base.OnMouseLeftButtonDown(e);
startPoint = e.GetPosition(this);
testTi.MouseLeftButtonDown += testTi_MouseLeftButtonDown;
Canvas.SetLeft(testTi, e.GetPosition(this).X);
Canvas.SetTop(testTi, e.GetPosition(this).X);
this.Children.Add(testTi);
}
}
and by clicking an object that is placed inside the canvas i want to get the information.
for now just want to make sure i am getting the right object with a simple messagebox
void testTi_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show(sender.GetType().ToString());
}
this is my costume "Rectangle" class
class TiTest:Grid
{
private Label tiNameLabel;
private Rectangle tiRectangle;
private String SomeText = string.Empty;
private String version = "1.0";
private String application = "CRM";
private String CRID = "NNN";
public String SomeText1
{
get { return SomeText; }
set { SomeText = value; }
}
public Rectangle TiRectangle
{
get { return tiRectangle; }
set { tiRectangle = value; }
}
public Label TiNameLabel
{
get { return tiNameLabel; }
set { tiNameLabel = value; }
}
public TiTest()
{
this.SomeText = "Hello World!!";
this.TiNameLabel = new Label
{
Content = "Test Item",
VerticalAlignment = System.Windows.VerticalAlignment.Top,
HorizontalAlignment = System.Windows.HorizontalAlignment.Left
};
TiRectangle = new Rectangle
{
Stroke = Brushes.Red,
StrokeDashArray = new DoubleCollection() { 3 },//Brushes.LightBlue,
StrokeThickness = 2,
Cursor = Cursors.Hand,
Fill = new SolidColorBrush(Color.FromArgb(0, 0, 111, 0))
};
Background= Brushes.Aqua;
Opacity = 0.5;
this.Children.Add(this.tiNameLabel);
this.Children.Add(this.tiRectangle);
}
}
is there any way to access the main form controls from the costume canvas class or by the costume rectangle class?
Thanks in advance
You can have your main window be binded to a singletone ViewModel holding the properties of the rectangles.
ViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
#region Singletone
private static MainWindowViewModel _instance;
private MainWindowViewModel()
{
}
public static MainWindowViewModel Instance
{
get
{
if (_instance == null)
_instance = new MainWindowViewModel();
return _instance;
}
}
#endregion
#region Properties
private string _someInfo;
public string SomeInfo
{
get
{
return _someInfo;
}
set
{
if (_someInfo != value)
{
_someInfo = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("SomeInfo"));
}
}
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
In main window xaml
<TextBox Text="{Binding SomeInfo}"/>
Also set the view model as your main window data context (in main window constructor for exmaple)
this.DataContext = MainWindowViewModel.Instance;
Finally, from where you handle the click event of the rectangles (testTi_MouseLeftButtonDown), access the MainWindowViewModel instance and set it's properties accordingly.
MainWindowViewModel.Instance.SomeInfo = myRectangle.SomeInfo;
This will trigger the PropertyChanged event, which will update your control's on the main window.
If you are not familiar with the MVVM (Model, View. View Model) pattern you can read about it here
Hope this helps

override the super class methods in wpf Window

I wanna make a customized window base. So I made a custom window which inherits from Window.
For example:
public class MyWindowBase : Window
{
...
...
}
I wanna override the different Brushes of the super class Window for my own purpose.
In my previous experience, to override methods/properties with no abstract or virtual in the super class need the key word "new".
For example:
public new void DoSomething() { ........ base.DoSomething() ....... }
public new string SomeText { get { ... } set {......} }
It works in my previous work.
However, in this time of dealing with WPF Window, it doesn't work.
I tried to override the different Brushes of the super class Window as follows:
public new Brush BorderBrush
{
get { ... }
set { myBorderBrush = value; base.BorderBrush = null }
}
public new Brush Background
{
get { ... }
set { myBackground = value; base.Backgound = null; }
}
.....
.....
.....
I tried the change the value of the above Brushes in MyWindowBase, it just change the value of the super class Window, it doesn't change the value of myBorderBrush and myBackground.
So, how could I override the methods and properties of the super class Window?
Actually, I want to override the base background so that it will be null or transparent forever, but the changed value will be applied on my own custom Background.
Thank you very much!
If you only want to set the value, then you can set it using
this.BorderBrush = Brushes.Blue;
this.Background = Brushes.Red;
If you wish to overwrite the Property Metadata (for things like default value, property changed logic, or validation), you can use OverrideMetadata
Window.BackgroundProperty.OverrideMetadata(
typeof(MyWindowBase), myPropertyMetadata);
If you simply want to add some logic on Changed, you can use a DependencyPropertyDescriptor
var dpd = DependencyPropertyDescriptor.FromProperty(
Window.BackgroundProperty, typeof(Window));
dpd.AddValueChanged(this.Value, new EventHandler(BackgroundChanged));
private void BackgroundChanged(object sender, EventArgs e)
{
//do the code here
}
And if you're looking to override a Method, and not a Property, then you can use the override keyword
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
}

WPF: Drawing on top of a TextBlock

I want to be able to draw on to the top of a TextBlock, and have found a way to do this, but i cannot remove the drawing once it is there. Here is the code.
public class DerivedTextBlock : TextBlock {
public Boolean DrawExtra {
get { return (Boolean)GetValue(DrawExtraProperty); }
set { SetValue(DrawExtraProperty, value); }
}
// Using a DependencyProperty as the backing store for DrawExtra. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DrawExtraProperty =
DependencyProperty.Register("DrawExtra", typeof(Boolean), typeof(DerivedTextBlock), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsArrange));
public DrawingVisual DrawingVisual { get; set; }
public DerivedTextBlock() {
DrawingVisual = this.CreateDrawingVisualRectangle();
}
protected override int VisualChildrenCount {
get {
//if we want to draw our extra info, add one to
// our visualChildrenCount, usually with a textblock it is 0
if (DrawExtra) {
return base.VisualChildrenCount + 1;
}
else {
return base.VisualChildrenCount;
}
}
}
protected override Visual GetVisualChild(int index) {
return DrawingVisual;
}
// Create a DrawingVisual that contains a rectangle.
private DrawingVisual CreateDrawingVisualRectangle() {
DrawingVisual drawingVisual = new DrawingVisual();
// Retrieve the DrawingContext in order to create new drawing content.
DrawingContext drawingContext = drawingVisual.RenderOpen();
// Create a rectangle and draw it in the DrawingContext.
Rect rect = new Rect(new Point(10.0, 0), new Size(10.0 / 2.0, 10));
drawingContext.DrawRectangle(Brushes.LightBlue, (Pen)null, rect);
// Persist the drawing content.
drawingContext.Close();
return drawingVisual;
}
}
Reason I want to do this: We have a datagrid with a lot of cells, each cell displaying text. we show some validation information on the cells and we do this by using a template with a textblock and some paths hosten in a grid. the overhead of this adds extra elements to the visual tree and when we have to redraw (on loading, switching windows or on a sort) it takes a lot longer the more elements in the visual tree. when it is just a textblock it is about 1/3 - 1/2 faster than having the control with a grid. So we would like to draw our validation stuff right on top of the textbox.
Your problems are:
GetVisualChild() should return base.GetVisualChild(index) except when index==base.VisualChildrenCount.
You forgot to call AddVisualChild() when DrawingExtra becomes true or DrawingVisual changes
You forgot to call RemoveVisualChild() when DrawingExtra becomes false or DrawingVisual changes
You can fix #2 and #3 by setting a PropertyChangedCallback on DrawingExtra and adding code to the setter of DrawingVisual.
Explanation: It is the AddVisualChild() call that actually adds the visual to the tree. What is happening is that your visual is being found and displayed "accidentally" because of your error in GetVisualChild(), but it is not being properly linked into the visual tree so you'll encounter many problems.
Update
I edited your code as described above, and it worked perfectly. Here are the changes:
...
{
PropertyChangedCallback = (obj, e) =>
{
var textBlock = (DerivedTextBlock)obj;
if((bool)e.OldValue) textBlock.RemoveVisualChild(textBlock.DrawingVisual);
if((bool)e.NewValue) textBlock.AddVisualChild(textBlock.DrawingVisual);
}
});
public DrawingVisual DrawingVisual
{
get { return _drawingVisual; }
set
{
if(DrawExtra) RemoveVisualChild(_drawingVisual);
_drawingVisual = value;
if(DrawExtra) AddVisualChild(_drawingVisual);
}
}
private DrawingVisual _drawingVisual;
...
protected override int VisualChildrenCount
{
get { return base.VisualChildrenCount + (DrawExtra ? 1 : 0); }
}
protected override Visual GetVisualChild(int index)
{
return index==base.VisualChildrenCount ? DrawingVisual : base.GetVisualChild(index);
}

When inheriting a control in Silverlight, how to find out if its template has been applied?

When inheriting a control in Silverlight, how do I find out if its template has already been applied?
I.e., can I reliably get rid of my cumbersome _hasTemplateBeenApplied field?
public class AwesomeControl : Control
{
private bool _hasTemplateBeenApplied = false;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this._hasTemplateBeenApplied = true;
// Stuff
}
private bool DoStuff()
{
if (this._hasTemplateBeenApplied)
{
// Do Stuff
}
}
}
Nope that is the standard way to track whether the template has been applied.

Resources