I want to create an custom InkCanvas Adorner and found the logic behind:
You can re-use the existing lasso functionality of the InkCanvasEditingMode.Select mode. Then, in the SelectionChanged event, you can get a reference to the selected strokes (and/or elements). Now clear the selection (to get rid of the standard adorner) and then bring up your custom adorner.
How can i inherit the InkCanvas class with the editing mode in my own class and get access to the Events?
class myInkCanvasClass : InkCanvas ?
{
base class constructor call ?
...
}
[DebuggerDisplay("[{Scene}]Strokes:{Strokes.Count}, Children:{Children.Count}")]
public class InkCanvas_Sandeep : InkCanvas
{
public int PagId = -1;
public InkCanvas_Sandeep()
{
DefaultDrawingAttributes.Color = Colors.Red;
DefaultDrawingAttributes.FitToCurve = true;
DefaultDrawingAttributes.Height = 2;
DefaultDrawingAttributes.Width = 2;
DefaultDrawingAttributes.IgnorePressure = false;
DefaultDrawingAttributes.IsHighlighter = false;
DefaultDrawingAttributes.StylusTip = System.Windows.Ink.StylusTip.Ellipse;
DefaultDrawingAttributes.StylusTipTransform = Matrix.Identity;
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
SnapsToDevicePixels = true;
}
}
public void createMultipleInstances()
{
InkCanvas_Sandeep canvas new InkCanvas_Sandeep();
canvas.PagId = ++PageDetails.PageId;
}
You shouldn't have to inherit from InkCanvas, SelectionChanged is a public event on InkCanvas so you can just add a handler to it. Also the EditingMode is a public property that you can set on an instance of InkCanvas as well. So to add the handler to SelectionChanged and toggle the EditingMode between Ink and Select you can just use the public API of an InkCanvas instance.
Basic example:
inkCanvas.SelectionChanged += InkCanvas_SelectionChanged;
inkCanvas.EditingMode = InkCanvasEditingMode.Select;
I managed to inherit the InkCanvas Class to my CustomInkCanvas Class and get the EventListener of SelectionChanged:
public class CustomInkCanvas : InkCanvas
{
//variables
//constructor
public CustomInkCanvas()
{
//...
}
override protected void OnSelectionChanged(EventArgs e)
{
MessageBox.Show("Selection Changed");
}
}
So if i change a Selection i get noticed.
Related
I have customized a TabPage, but found that there are problems as follows:
First, I Create two custom TabPage, It worked.
But there was a problem when I closed the document and then I reopened the document:
enter image description here
Look, TabPage becomes four, but I found the problem in the "designer.cs" document.
//
// blK_TabControl1
//
this.blK_TabControl1.Controls.Add(this.blK_TabPage6);
this.blK_TabControl1.Controls.Add(this.blK_TabPage7);
this.blK_TabControl1.Location = new System.Drawing.Point(4, 12);
this.blK_TabControl1.Name = "blK_TabControl1";
this.blK_TabControl1.SelectedIndex = 0;
this.blK_TabControl1.Size = new System.Drawing.Size(604, 196);
this.blK_TabControl1.TabIndex = 14;
this.blK_TabControl1.TabPages.AddRange(new System.Windows.Forms.TabPage[] {
this.blK_TabPage6,
this.blK_TabPage7});
After the normal TabControl add TabPage, there is no "TabPages.AddRange()" this code, how can I fix it?
Here is my code:
public class BLK_TabPageCollectionEditor : CollectionEditor
{
public BLK_TabPageCollectionEditor(Type type)
: base(type)
{
}
protected override bool CanSelectMultipleInstances()
{
return false;
}
protected override Type CreateCollectionItemType()
{
return typeof(BLK_TabPage);
}
protected override object CreateInstance(Type itemType)
{
BLK_TabPage tabPage = (BLK_TabPage)itemType.Assembly.CreateInstance(itemType.FullName);
IDesignerHost host = (IDesignerHost)this.GetService(typeof(IDesignerHost));
host.Container.Add(tabPage);
//this.Context.Container.Add(tabPage);
tabPage.Text = tabPage.Name;
return tabPage;
}
}
public class BLK_TabControl : TabControl
{
[EditorAttribute(typeof(BLK_TabPageCollectionEditor), typeof(UITypeEditor))]
[MergableProperty(false)]
public new TabControl.TabPageCollection TabPages
{
get
{
return base.TabPages;
}
}
}
Thanks in advance.
I have tried your code. Looks like everything is fine. But based on designer-generated code and your image description the only thing I can suggest is to hide serialization of TabPages property:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorAttribute(typeof(BLK_TabPageCollectionEditor), typeof(UITypeEditor))]
[MergableProperty(false)]
public new TabControl.TabPageCollection TabPages
{
get
{
return base.TabPages;
}
}
I have a MainWindow class, and that is the main window of the app. I've created another class just below the MainWindow class, and I need to add an event to a Canvas that was created in MainWindow. The method I want to add as event is also in MainWindow.
public partial class MainWindow : Window
{
public void Moving(object sender, MouseEventArgs e)
{
bla bla;
}
public Canvas Getcanvas
{
get
{
return canvas;
}
}
}
public class Ka
{
public Ka()
{
MainWindow.Getcanvas.MouseMove += new MouseEventHandler(//HERE!!! I DONT KNOW WHAT GOES HERE, here should probably be MainWindow.Moving but I get error "An object reference.."
}
}
Please help me !
var mainWindowInstant = (MainWindow)App.Current.MainWindow;
mainWindowInstant.Getcanvas.MouseMove += new MouseEventHandler(...);
i don't know how to define a control button in c# ? and then define some special properties and effects to it ,rather than what we have in visual studio right now.
Try extending class System.Windows.Forms.Button
namespace MyDemo {
public class MyButton : System.Windows.Forms.Button {
public MyButton() {
Text = "This is custom text";
BackColor = Color.Red;
}
}
}
You should use MyButton class in your application.
To add a property to a button, just use get & set . Here is an example code:
public class CustomButton : Button
{
string _LockStatus;
public string LockStatus
{
get { return _LockStatus; }
set { _LockStatus = value; }
}
}
I'm trying to create a diagramming application in C# / WPF. What I going for is somewhat similar to Microsoft Visio although I'm not trying to clone it. I kind of wrote this question as I was coding and just put all the issues I had into it in case someone will find it useful. Maybe I've been thinking too hard but I feel like I could throw up on my keyboard and produce better code, so feel free to give any suggestions on every detail you catch (grammar excluded :-))
In short:
Why are all the items positioned at (0,0)?
Code:
public class Diagram : MultiSelector
{
public Diagram()
{
this.CanSelectMultipleItems = true;
// The canvas supports absolute positioning
FrameworkElementFactory panel = new FrameworkElementFactory(typeof(Canvas));
this.ItemsPanel = new ItemsPanelTemplate(panel);
// Tells the container where to position the items
this.ItemContainerStyle = new Style();
this.ItemContainerStyle.Setters.Add(new Setter(Canvas.LeftProperty, new Binding("X")));
this.ItemContainerStyle.Setters.Add(new Setter(Canvas.TopProperty, new Binding("Y")));
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
FrameworkElement contentitem = element as FrameworkElement;
Binding leftBinding = new Binding("X");
Binding topBinding = new Binding("Y");
contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
contentitem.SetBinding(Canvas.TopProperty, topBinding);
base.PrepareContainerForItemOverride(element, item);
}
public class DiagramItem : ContentControl
{
private Point _location;
public DiagramItem()
{
}
static DiagramItem()
{
}
public Point Location
{
get { return _location; }
set
{
_location = value;
}
}
public double X
{
get { return _location.X; }
set
{
_location.X = value;
}
}
public double Y
{
get { return _location.Y; }
set
{
_location.Y = value;
}
}
}
//...
Ok, so the idea is that the Diagram : ItemsControl places its item on a Canvas panel at the position defined in the Item DiagramItem.Location. IOW when I change the X property in a DiagramItem the Diagram moves the item on the x-axis.
Note: MultiSelector is derived from ItemsControl and Selector and is only used here because I need the displayed item to be selectable.
Please note that I'd prefer not to use xaml if possible.
In long:
A Diagram instance as seen by the user has these requirements:
Has multiple DiagramItems.
User can select multiple DiagramItems.
DiagramItems can be resized, rotated and dragged anywhere on the Diagram.
Possible to navigate between DiagramItems using the keyboard.
I basically have two and possibly three classes relevant to this question.
Diagram extends System.Windows.Controls.Primitives.MultiSelector : Selector : ItemsControl
DiagramItem extends ContentControl or some other Control
The Diagram.ItemsPanel aka the visual panel which displays the items should be a panel which supports absolute positioning, like the Canvas.
How should I implement a class derived from MultiSelector and what resources can you point at which are relevant to this question?
What does one have to consider when implementing a custom MultiSelector / ItemsControl?
Resources:
I've found very few resources relevant to my issue, but then again I'm not sure what I'm supposed to be looking for. I've read the source code for ListBox and ListBoxItem using Reflector but didn't find it very useful.
Other resources:
System.Windows.Controls.Primitives.MultiSelector
System.Windows.Controls.ItemsControl
ItemsControl.ItemsPanel
System.Windows.Controls.Canvas
Positioning items when Canvas is the ItemsPanel of a ItemsControl
Using Templates to customize WPF controls
Create an items control
OK, apparently this can easily be achieved by using bindings and the property framework.
public class Diagram : MultiSelector
{
public Diagram()
{
this.CanSelectMultipleItems = true;
// The canvas supports absolute positioning
FrameworkElementFactory panel = new FrameworkElementFactory(typeof(Canvas));
this.ItemsPanel = new ItemsPanelTemplate(panel);
// Tells the container where to position the items
this.ItemContainerStyle = new Style();
this.ItemContainerStyle.Setters.Add(new Setter(Canvas.LeftProperty, new Binding("X")));
this.ItemContainerStyle.Setters.Add(new Setter(Canvas.TopProperty, new Binding("Y")));
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
FrameworkElement contentitem = element as FrameworkElement;
Binding leftBinding = new Binding("XProperty");
leftBinding.Source = contentitem;
Binding topBinding = new Binding("YProperty");
topBinding.Source = contentitem;
contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
contentitem.SetBinding(Canvas.TopProperty, topBinding);
base.PrepareContainerForItemOverride(element, item);
}
public class DiagramItem : ContentControl
{
public static readonly DependencyProperty XProperty;
public static readonly DependencyProperty YProperty;
public static readonly RoutedEvent SelectedEvent;
public static readonly RoutedEvent UnselectedEvent;
public static readonly DependencyProperty IsSelectedProperty;
public DiagramItem()
{
}
static DiagramItem()
{
XProperty = DependencyProperty.Register("XProperty", typeof(Double), typeof(DiagramItem));
YProperty = DependencyProperty.Register("YProperty", typeof(Double), typeof(DiagramItem));
SelectedEvent = MultiSelector.SelectedEvent.AddOwner(typeof(DiagramItem));
UnselectedEvent = MultiSelector.SelectedEvent.AddOwner(typeof(DiagramItem));
IsSelectedProperty = MultiSelector.IsSelectedProperty.AddOwner(typeof(DiagramItem));
}
public Double X
{
get
{
return (Double)this.GetValue(XProperty);
}
set
{
this.SetValue(XProperty, value);
}
}
public Double Y
{
get
{
return (Double)this.GetValue(YProperty);
}
set
{
this.SetValue(YProperty, value);
}
}
public Point Location
{
get
{
return new Point(X, Y);
}
set
{
this.X = value.X;
this.Y = value.Y;
}
}
}
The magic is in the proper usage of Bindings, the key was to add the contentitem as Source. The next step is obviously to handle the selection of items, but that's another question on its own.
If it is any help, I wrote a code project article based on my graphing and diagramming custom control called NetworkView:
http://www.codeproject.com/Articles/182683/NetworkView-A-WPF-custom-control-for-visualizing-a
I want to create a subclass of TabPage that contains some control, and I want to control the layout and properties of those controls through the designer. However, if I open my subclass in the designer, I can't position them like I could on a UserControl. I don't want to have to create a TabPage with an UserControl instance on it, I want to design the TabPage directly.
How do I do that? I've tried changing the Designer and DesignerCategory attributes, but I haven't found any values that help.
I've had a similar problem in the past.
What i did first was switch from inheriting Usercontrol to tabpage like so
class UserInterface : UserControl // Do designer bit then change it to
class UserInterface : TabPage
Second i Just put all my controls and stuff in the usercontrol and docked that into a tabpage.
third i've made a generic class that takes any usercontrol and does the docking automatically.
so you can take your 'UserInterface' class and just get a type that you can add to a System.Windows.Forms.TabControl
public class UserTabControl<T> : TabPage
where T : UserControl, new ()
{
private T _userControl;
public T UserControl
{
get{ return _userControl;}
set
{
_userControl = value;
OnUserControlChanged(EventArgs.Empty);
}
}
public event EventHandler UserControlChanged;
protected virtual void OnUserControlChanged(EventArgs e)
{
//add user control docked to tabpage
this.Controls.Clear();
UserControl.Dock = DockStyle.Fill;
this.Controls.Add(UserControl);
if (UserControlChanged != null)
{
UserControlChanged(this, e);
}
}
public UserTabControl() : this("UserTabControl")
{
}
public UserTabControl(string text)
: this( new T(),text )
{
}
public UserTabControl(T userControl)
: this(userControl, userControl.Name)
{
}
public UserTabControl(T userControl, string tabtext)
: base(tabtext)
{
InitializeComponent();
UserControl = userControl;
}
private void InitializeComponent()
{
this.SuspendLayout();
//
// UserTabControl
//
this.BackColor = System.Drawing.Color.Transparent;
this.Padding = new System.Windows.Forms.Padding(3);
this.UseVisualStyleBackColor = true;
this.ResumeLayout(false);
}
}
I handle this by designing the pages themselves as individual forms, which are then hosted inside tab pages at runtime.
How do you put a form inside a TabPage?
form.TopLevel = false;
form.Parent = tabPage;
form.FormBorderStyle = FormBorderStyle.None; // otherwise you get a form with a
// title bar inside the tab page,
// which is a little odd