Display Custom Cursor in WPF Application - wpf

I have a set of cursors (.cur files) that I want to use with my WPF/VB.net application, without changing the cursors system-wide. I am assuming that I would somehow use each WPF object's "cursor" property, but I'm not sure how to use my own cursors.
What should I do to accomplish this?

Have you tried using the file path overload to create a cursor?
Cursor cursor = new Cursor("<path>");
Or the stream for that matter?
Once you have a cursor object you can assign it to the controls where it should be shown. (FrameworkElement.Cursor)
If you use the cursor as a resource, e.g. in a cursors folder in your project
you can reference it anywhere in your XAML, e.g.
<Window Cursor="Cursors/wait_il.cur">...

assuming that cursor is in /Resources/ folder and build action is set to Resource:
declare:
<TextBlock x:Key="MyCursor" Cursor="/Resources/grab.cur" />
Then apply to the main window in initializer:
this.Cursor = (FindResource("MyCursor") as TextBlock).Cursor;

Ok since H.B was winging at me here is a class :p
public class CustomCursor
{
private System.Windows.Input.Cursor _cursor = null;
public System.Windows.Input.Cursor Cursor
{
get
{
if (_cursor == null)
_cursor = GetCursor();
return _cursor;
}
}
public string RelativePath { get; set; }
public CustomCursor()
{
}
public CustomCursor(string relativePath)
{
RelativePath = relativePath;
}
public System.Windows.Input.Cursor GetCursor()
{
if (RelativePath == null)
throw new ArgumentNullException("You must set RelativePath first");
string directory = Directory.GetCurrentDirectory();
string absPath = directory + '\\' + RelativePath;
if (!File.Exists(absPath))
throw new FileNotFoundException();
return new System.Windows.Input.Cursor(absPath);
}
}
Use in code behind like this:
this.Cursor = new CustomCursor("grab.cur").Cursor;
Or declare in xaml:
<local:CustomCursor x:Key="MyCursor" RelativePath="grab.cur"/>
And reference like this:
this.Cursor = (FindResource("MyCursor") as CustomCursor).Cursor;

Related

creating items collection in a custom control

I have a Custom control inheriting from Control class in my WinForm. My control contains multiple panels and other UIElements.
This is what my control is supposed to look like
There's a database panel,
database panel contains a single checkbox only.
and there's a Server panel,
server panel contains many database panels and a single label; the header label.
And finally there's the container panel that contains all my Server panels.
I found this Item Collection option for a User Control but I couldn't really understand the accepted answer on it. If someone could help explain it better that would be great.
Also, if someone could just put some links for creating advanced custom controls. I've been reading all day about it and I still can't make any sense of it all. Is there a step-by-step guide for advanced custom controls?
[Edit]
Basically what I need is to create a custom collection within my custom control. Currently my control is built as Winform Control Library which I build and then I use in my main program later.
So in my main program, I can just drag and drop the component on my form and use it.
By default, the custom control will load with one Server that contains one database.
What I want is to be able to add/remove other databases/servers to it if I need to, in my MAIN program
I'm having trouble explaining exactly what I need because I simply do not understand how the whole custom control/items collection thing works really, and i'm sorry for that. I would really appreciate some links that explains this stuff clearly
here's my code for this control:
This code only creates my default control, but I am UNABLE to add to it. The collection property appears in my property windows but when I add items to it and click okay nothing happens.
public class Database : System.Windows.Forms.Panel
{
public CheckBox _ckbDatabase;
public Database()
{
_ckbDatabase = new CheckBox();
this.BackColor = _pnlDatabaseBackColor;
this.Size = _pnlDatabaseSize;
this.AutoSize = false;
this.Height = 40;
this.Width = 200;
this.Location = _pnlDatabaseLocation;
_ckbDatabase.Top = 10;
_ckbDatabase.Left = 15;
_ckbDatabase.TextAlign = _ckbdbTextAlignment;
_ckbDatabase.Font = _ckbdbFont;
_ckbDatabase.ForeColor = Color.White;
this.Controls.Add(_ckbDatabase);
}
#Propterties
}
public class Server : System.Windows.Forms.Panel
{
private Label _lblserver;
private Database database;
public Server()
{
_lblserver = new Label();
database = new Database();
this.BackColor = _pnlServerBackColor;
this.Size = _pnlServerSize;
this.AutoSize = false;
_lblserver.Dock = _lblserverDock;
_lblserver.Font = _lblsrvFont;
_lblserver.BackColor = _lblServerBackColor;
_lblserver.AutoSize = false;
_lblserver.Text = SRV;
database.Top = 35;
database._ckbDatabase.Text = DB;
this.Controls.Add(_lblserver);
this.Controls.Add(database);
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public DatabaseCollection DatabaseCollection { get; set; }
#Propterties
}
public class ServersCollection : CollectionBase
{
public Server this[int index]
{
get { return (Server)List[index]; }
}
public void Add(Server server)
{
List.Add(server);
}
public void Remove(Server server)
{
List.Remove(server);
}
}
How about something simple like this:
public class Server {
public string Name { get; set; }
public List<Database> Databases { get; set; }
public Server() {
Databases = new List<Database>();
}
}
public class Database {
public string Name { get; set; }
public bool Enabled { get; set; }
}
Then you can just add it like this:
List<Server> servers = new List<Server>();
Server serverA = new Server { Name = "Server A" };
serverA.Databases.Add(new Database { Name = "Database 1", Enabled = true });
serverA.Databases.Add(new Database { Name = "Database 2", Enabled = false });
Server serverB = new Server { Name = "Server B" };
serverB.Databases.Add(new Database { Name = "Database 1", Enabled = false });
serverB.Databases.Add(new Database { Name = "Database 2", Enabled = false });
servers.Add(serverA);
servers.Add(serverB);
When you link to the Item Collection part it seemed like you wanted to be able to add servers and databases in design mode but then you mention you want to do it by code? If this is not what you want you need to give us more information.
Looks to me like you are mostly there. First off, here's a more complete collection class:
public class ServersCollection : IEnumerable<Server>
{
private List<Server> _servers = new List<Server>();
public Server this[int index]
{
get { return _servers[index]; }
}
public IEnumerator<Server> GetEnumerator()
{
foreach (var server in _servers)
yield return server;
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public void Add(Server server)
{
_servers.Add(server);
}
public void Remove(Server server)
{
//You might consider a deliberate loop to evaluate a proper match
//Don't forget to Dispose() it first!
_servers.Remove(server);
}
public void Clear()
{
for (Int32 i = _servers.Count - 1; i >= 0; i--)
_servers[i].Dispose();
_servers.Clear();
}
}
Add an instance of the ServersCollection class to the container control, the one at the top level that holds server panels:
private ServersCollection _servers = new ServersCollection();
public ServersCollection Servers { get { return _servers; } }
Use that as a way for it to add Server controls to its own collection of controls.
Do a similar thing with the DatabaseCollection in the Server class, again so that it can add Database panels to its controls collection.
Then, wherever you have an instance of a control, you will also have access to the collection of what it holds:
myControl.Servers
//-or-
myServer.Databases
...allowing you to add/remove, as such:
myControl.Servers.Add(new Server());
//-or-
myServer.Databases.Add(new Database());
Points of emphasis
Your classes are controls, but they also own other controls. Proper use of the Dispose pattern will be crucial or you'll have memory issues throughout.
I would remove these lines, they don't matter unless you intend to add servers/DBs at form design time (i.e. fixed entries or defaults):
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public DatabaseCollection DatabaseCollection { get; set; }
Finally, you could (should!) take that collection class further, with overloads for Add() and Remove() that do a better job of deciding when/how/what to do based on more than an instance, e.g. by name? You could also add another indexer to fetch by name, for instance, instead of just index (which you might not readily know).

How to pass value from one window to another

How do I pass a value from one a variable to a textbox after it's set? On winforms, I used to use form1.textbox1.text = variable in winforms.
I set, and get the variable from this...
Public Shared Property containerstring() As String
Get
Return m_containerstring
End Get
Set(value As String)
m_containerstring = value
End Set
End Property
Private Shared m_containerstring As String
Basically, I have a window... where the user chooses a variable, this variable is then set # containerstring. When this form closes, I wanted to push this variable to the currently open window's textbox.
I'm new to WPF, forgive the noobness.
This is how I do it for a window, and this works perfectly... for windows. I'm looking to do the same thing with a control.
Dim strWindowToLookFor As String = GetType(MainWindow).Name
Dim win = ( _
From w In Application.Current.Windows _
Where DirectCast(w, Window).GetType.Name = strWindowToLookFor _
Select w _
).FirstOrDefault
If win IsNot Nothing Then
DirectCast(win, MainWindow).Title = SelectedContainer
End If
You can make a Window closing Event like :
this.Closed += MyWindow_Closed;
and then set your variable in the corresponding method.
private void MyWindow_Closed()
{
TextBox1.Text = a;
}
You could use a PubSubEvent which is available in Prism.Events. This will allow you to subscribe to events.
Using Prism.Events;
define your Event.
public class MyEvents : PubSubEvent<object>
{
public MyEvents();
}
In your first window or code behind
[Import]
public IEventAggregator EventAggregator
{
get;
set;
}
and you can use this property in your program to send whatever value you want to send.
For example
private void MyWindow_Closed()
{
MyEvents myEvents = EventAggregator.GetEvent<MyEvents>();
myEvents.Publish(yourvalue);
}
Once you have publised you can Subscribe to the same event in any other part of your program like this.
MyEvents myEvents = EventAggregator.GetEvent<MyEvents>();
myEvents.Subscribe(MyEventMethod, ThreadOption.UIThread, true);
and get your data here
void MyEventMethod(object obj)
{
// do wharever you want
}

Under SelectionChanged read out the underlying data from a List

Im busy with my app and i walked in some problems when i click on a photo in my listbox PhotoFeed.
I got 1 List<> with in it the strings UrlTumb and UrlFull.
I got 1 ListBox with in it a WrapPanel filled with images wich i set the Image.Source from my UrlTumb.
What my problem is when i click on a photo in my listbox i want to navigate to a new page and display there the original image (UrlFull) now i can only get my UrlTumb from my Image.Source but i want my UrlFull which is stored in the List. Now is my question how do i obtain the UrlFull. So how can i back trace which item i clicked and get the UrlFull from that item so i can send it with my NavigationService.Navigate
I can do it on an dirty way and create an invisible textblock besides the image in my ListBox and put the UrlFull in there but i would like to do it in a proper way
So what do i place in the ????? spot in this line
NavigationService.Navigate(new Uri("/PhotoInfo.xaml?urlfull={0}", ????? , UriKind.Relative));
Greetings Cn
There are multiple options:
Use selected item's index listBox.SelectedIndex to get the index
of the selected property which will correspond to the index in your
source (it might not if you filter the collection using collection
source, but I think that is not the case)
Use selected item listBox.SelectedItem this will return the
SelectedItem which will contain your object. (Note, that if your
selection mode set to multiple, this will return only the firstly
selected item)
Use SelectemItems. It will allow you to get an array of selected
items (Note: this should be normally used only when your list's
selection mode is set to multiple)
Use SelectedValue, which will contain the value of the SelectedItem
(this will save you and extra step.
Use arguments of the Selection changed event AddedItems.
Bellow is the code snippet of 3 options above. x, y, z will all be your selected names (e.g. "Mike")
XAML:
<ListBox x:Name="lb"
ItemsSource="{Binding Names}"
SelectionChanged="NameChanged" />
Code behind:
public class Person
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
private List<Person> people = new List<Person>
{
new Person{Name = "Lewis"},
new Person{Name = "Peter"},
new Person{Name = "Brian"}
};
public List<Person> People
{
get
{
return this.people;
}
set
{
this.people = value;
}
}
private void NameChanged(object sender, SelectionChangedEventArgs e)
{
var x = this.people[lb.SelectedIndex];
var y = lb.SelectedItem;
var z = lb.SelectedItems[0];
var h = lb.SelectedValue;
var u = e.AddedItems[0];
var person = e.AddedItems[0] as Person;
if (person != null)
{
var result = person.Name;
}
}
For the differences between SelectedValue and SelectedItem refer here SelectedItem vs SelectedValue

how to get the region name?

using Silverlight & Prism.
i create a new scoped region inside a TabControl like so:
IRegionManager regionManager = tabControl.Add(viewRegions, UNIQUEID, true);
then from the TabControl SelectionChanged event i want to get the name of that region.
so i go:
TabItem item = e.AddedItems[0] as TabItem;
FrameworkElement view = item.Content as FrameworkElement;
IRegionManager xxx = RegionManager.GetRegionManager(view);
so now i have the scoped region manager at hand = xxx!
but how do i get its name? (the "UNIQUEID" param i have assigned to it ).
HOW?
If you have the RegionManager, and the View, then you can get the region Name (but I don't know why you'd ever want to). If you loop through the regionmanger like this you can get what you want. You'll have to keep a reference around to the scoped RegionManager, but there's no way around that. (There is some extra code demonstrating other things that someone might want to do too)
private void UnloadRegion()
{
foreach (IRegion region in xxx.Regions)
{
for (int ix = region.ActiveViews.Count() - 1; ix >= 0; ix--)
{
if (WhateverYourCurrentViewIs == region.ActiveViews.Last())
{
string RegionName = region.Name;
//there is the name
{
}
}
}

How can I databind dynamically loaded DataGridViews?

I'm developing a Windows Forms application in VS2008. I want to display a unknown, but small number of DataGridViews on a form, using code like this:
foreach (QueryFilter f in Query.Filter)
{
DataGridView grid = CreateGridView(String.Format("GridView{0}", filters.Count));
grid.Location = new System.Drawing.Point(3, 9 + (filters.Count * grid.Height + 9));
BindingList<QueryFilterNode> nodes = new BindingList<QueryFilterNode>();
foreach (QueryFilterNode node in f)
nodes.Add(node);
grid.DataSource = nodes;
panel1.Controls.Add(grid);
filters.Add(nodes);
}
The grid(s) are added to the panel, but the data inside is not displayed. My guess is setting the DataSource property doesn't actualy bind the grid, because (for example) the dataGridView_ColumnAdded event is not fired.
QueryFilter and QueryFilterNode are just POCO's and contain data of course.
For completeness sake the construction of the DataGridView:
private DataGridView CreateGridView(string name)
{
DataGridView grid = new DataGridView();
grid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
grid.Name = name;
grid.Size = new System.Drawing.Size(484, 120);
grid.ColumnAdded += new System.Windows.Forms.DataGridViewColumnEventHandler(this.dataGridView_ColumnAdded);
return grid;
}
Hmm, it seems it was my own mistake.
QueryFilterNode, used as datasource ( BindingList<QueryFilterNode> ) wasn't a POCO but a datacontract. Snippet:
[DataContract(Name = "QueryFilterNode")]
public class QueryFilterNode
{
[DataMember(IsRequired = true)]
public string FieldCode;
For some reason these cannot be databound. I used a simple class like this in my BindingList and it just worked.
class QueryFilterNodeSimple
{
public string FieldCode
{ get; set; }

Resources