I am working on a Windows Store Hub App using XAML and C#. I am not proficient in C#. I understand the basics. Please go easy on me. I know you're wondering why I would even attempt this and so am I at this point. I come from a web design background and could have used Javascript. But I have really learned a lot by doing it and googling what I didn't understand. The app controls really made me jump through hoops to do anything I wanted to do which must not be anything anyone else wants to do or there would be more documentation. I should also mention I've never worked very much with forms so I don't have that background either.
I actually do have a question. I am almost finished and on the last hub section. I want to have textboxes that accept user input. This will be for integers and will have a running total. I can write that code albeit primitively. What I can't do is access the textboxes inside the hub. If I try to put them outside the hub I can but then they don't scroll with the page so I have textboxes floating there.
If they weren't in the hub I could just write:
private void Button_Click(object sender, RoutedEventArgs e)
{
int a = Convert.ToInt32(tbOne.Text);
int b = Convert.ToInt32(tbTwo.Text);
int c = a + b;
Total.Text = c.ToString();
}
Of course, it will be more complicated than that but that is the basic idea. Inside the hub, it does not recognize the x:name.
I would appreciate any insight into this or links if anyone has any. I couldn't find anything by searching.
Investigate the MVVM pattern. Accessing all controls by name is not the best way to do this. You want to set the data context of the your Hub to a seperate class that has properties like TextBox1Text and TextBox2Text and that implements INotifyPropertyChanged. Then in XAML bind those to the controls like . This will give you access to those controls nested in the Hub.
Related
Okay, im positive this has an answer somewhere but I have been banging my head against a wall FOREVER trying to get this to work, an working around it for days, and im losing my mind here. I cannot find a single example that works or does what I want... at least not that I understand how its written.
Im writing a custom control, basically a content view with a calculator in it. One of the controls in this is an entry.
What i want is VERY simple... when you create an entry in XAML you can do
<Entry TextChanged="FunctionToRun">
and then whenever the text is changed, an event is fired and that function is run.
In my case i want to add a custom event to my calculator class so that when i create one on a page:
<local:myCalculator CountUpdated="FunctionToRun">
that function gets run.
Everything I look at online talks about using an ICommand and all this - but literally every single example I have tried leads me to either:
A) Not be able to link my function in XAML (errors)
B) Only calls something inside the calculator class.... but doesnt trigger any events, and i cannot force it to.
I think i completely do not understand ICommand, and no matter how many examples I ahve looked at I cannot get what im after.
Anyone able to help? im sure its stupidly simple...
Turns out I was being completely blind and didnt realize i had implemented my event on the item with:
public EventHandler<EventArgs> EventName = {get;set;}
Which is absolutely not how you do it - I wont rewrite the reasoning when I can just find an existing answer:
event EventHandler vs EventHandler
Why do we need the "event" keyword while defining events?
Anyhow - it was a blank-minded mistake while coding a lot at once. This should be
public event EventHandler<EventArgs> EventName;
for many reasons - one of the most minor being it allows you to bind properly from XAML.
I want to fill an updatepanel with new dynamic controls in response to a button click.
However, I also want to be able to access the values of these dynamic controls in response to an event in one of the controls.
Specifically, I want the button to bring up two dropdownmenus. One of the menus (or both if need be) is in another update panel. I want the first menu in the update panel to change its data in response to a value getting selected in the other menu.
I think my problem is that when I cause a postback with one dropdownmenu I lose the other dropdownmenu because I created it in the button_click handler.
I know I should create dynamic controls in the Page_Init method (or so ive heard) but I only want the controls to show up if the button is clicked. There are other buttons on the page which need to create a different set of dynamic controls.
Thanks.
There are a lot of ways you can handle this, and which approach to take really depends on your project's requirements and your available resources.
The smoothest way to do it that would generally provide the best user experience would be to use a Javascript technique to hide and show controls as the page required them. JQuery is the library I would recommend for this. On the most basic level, you simply wire the control's activation (such as a button_click event) and hide or show a div containing the dynamic content as necessary, like so:
$("#control").show();
// and
$("#control").hide();
Alternatively, you can do this in C# by using the Visible property on many of the normal web controls for ASP.NET. The usual code-behind approach would look something like this:
private void btnControl_Click(object sender, EventArgs e)
{
var dynamicControl1 = FindControl("dynamicControl1");
dynamicControl.Visible = false; // or true, as the case may be
}
This particular approach is mostly attached to code-behinds, though, which I would encourage you to avoid if possible. They are practically impossible to test and will make projects a pain to work in. You can use a similar approach in the MVC3 framework, of course, it will just be a little different how you send and receive the control you are setting to not be visible. The other benefit this has that is kind of nice is that if something is set to not be visible, it tends not to even be displayed in the HTML generated by the templating engine (YMMV depending on the engine, but I know this is true in Razor). So someone viewing the source of your webpage won't be able to see inactive controls, which may or may not be something that appeals to you.
EDIT: I see the problem is less to do with how to display these things, and more with how to create and read them back given on-the-fly input.
I'm sure there's a way to do this with Javascript (which would more than probably be the cleanest and best way to do this), but I'm not good enough with JS to know the answer to that one. The way you would handle this in ASP.NET is make the div you're going to add controls to server-side (by using runat='server', then add what you need there. Again, the trivial code-behind approach would be something like:
private void btnControl_Click(object sender, EventArgs e)
{
foreach(var checkBoxChecked in chkBoxes.Where(x => x.Checked))
{
div.Controls.Add(new WebControl()) // or whatever the heck else it is you need.
}
}
This presumes that you have an IEnumerable<CheckBox> to iterate over, of course. You may also want an IList<WebControl> to keep track of all the junk you're adding. You will also need to make sure the CSS is applied properly to the div for the controls you're adding. And again, code-behinds are pretty awful and I use the example only because it'd be easy to spin up in a project to test for yourself.
I have very little experience making my own events. I'm currently using forms and controls to handle events, so I'm trying to stick to the WinForm way of dealing with events.
WinForm controls already have their own events. Since events are made with a certain delegate type, I have to match the delegate signature in the methods I use to handle what goes on during an event. As far as I can tell, this means I have to take in two parameters in my event handlers: a source Object and an EventArgs.
I'm trying to figure out how to pass various information between controls through DragDrop related events. I've been able to find various code snippets online for different situations, but I'd like to have a better understanding of how the information is actually passed around.
When it comes to DragDrop events in particular, it seems my information will be passed through a DataObject. That, in turn, is passed as a parameter to the DragDrop.DoDragDrop method.
This is where my understanding starts to diminish. In most examples I've seen, it looks like some sort of data format is specified. The data format itself is of type string. Usually the data format is passed along with the data into the DataObject.
What is this data format doing? Is it just showing the type of the data involved? I've seen examples where the data format was tested, and various actions took place depending on what the data format had been. Couldn't you just do a typeof(YourData) to check for the type? I don't understand how a data format is useful.
http://msdn.microsoft.com/en-us/library/ms741842.aspx
In the above link, the first example shows a DataObject being created with no data format being specified. It explains that the data format is automatically chosen and that your object is converted by default.
Can you just pass any object into the DataObject? Then when the DragDrop event takes place on the target control, can that control access the methods and fields of the object passed? Or will the object be converted into some other form by the DataObject? How about various structures?
I've also done some drag and dropping from a Windows explorer icon to my forms. I was able to get the icon's file path with some example code I found. It also used a data format.
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
SUMMARY:
I'm trying to get an understanding of how data is passed through WinForm events. I don't understand some of what I've seen in various DragDrop examples. I understand that data is somehow stored in various formats, and that there is a way to extract that data. I don't understand what a data format is used for. I don't understand exactly what sorts of data can be transferred through a DataObject. My understanding of EventArgs in general is fairly lacking.
Feel free to comment on anything I've mentioned here. If I stated something incorrectly, point it out. Anything that will help me understand this subject better is appreciated.
EDIT:
I decided to explain where I plan to go with this. Maybe someone can use what I'm trying to do as a way to explain some of what I asked.
I have a form that contains a certain type of control. I'm trying to make the placement of the controls highly customizable and dynamic. Whenever another control is added to the form by the user, every control is automatically repositioned to keep things orderly.
I'm currently trying to allow the user to drag a control around the Form to resposition it. Wherever the user decides to drop the control, all of the other controls will move out of the way to make room for the move control.
If I'm going to be able to move the dragged control and all the other controls on the form properly, I need to be able to get certain information from the dragged control. The main data that would need to be passed through the events would take the form of a Location property that uses a System.Drawing.Point structure.
Here's something to give you an idea of how it's done.
First drop two panels on a Form, and set their colors to two different colors.
public Form1()
{
InitializeComponent();
panel1.MouseDown += new MouseEventHandler(panel1_MouseDown);
panel2.AllowDrop = true;
panel2.DragEnter += new DragEventHandler(panel2_DragEnter);
panel2.DragDrop += new DragEventHandler(panel2_DragDrop);
}
void panel1_MouseDown(object sender, MouseEventArgs e)
{
panel1.DoDragDrop(panel1, DragDropEffects.Move);
}
void panel2_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetData(typeof(Panel)) != null) e.Effect = DragDropEffects.Move;
}
void panel2_DragDrop(object sender, DragEventArgs e)
{
Panel p = sender as Panel;//Not needed in this case. Could just write panel2.
Panel dropped = (Panel)e.Data.GetData(typeof(Panel));
dropped.Location = p.PointToClient(new Point(e.X, e.Y));
p.Controls.Add(dropped);
}
Then drag panel1 onto panel2.
I think this problem should not be solved using drag&drop. Drag&drop is meant as a way for multiple applications to exchange data. If the data you are dragging is only meaningful for the current process, don't use drag&drop.
You can just use a field (for example, a field on the instance of the containing Form) to store all the data you need.
Just to say the obvious: Drag&drop is not a way to drag around controls. You need a lot of custom logic for that, anyway. It's not like the built-in features of dnd would help you here.
The AxAcroPDF swallows all key-related events as soon as it gets focus, including shortcuts, key presses, etc. I added a message filter, and it doesn't get any key-related messages either. It's a COM component, could that be relevant?
Is there any way to catch these before the control starts swallowing them?
Hans is correct, the Acrobat Reader spawns two child AcroRd32 processes which you have no direct access to from within your managed code.
I have experimented with this and you have three viable options:
You can create a global system hook, and then look for and filter out / respond to WM_SETFOCUS messages sent to your child AcroRd32 windows. You can accomplish some of this from within C# by using a wrapper library, such as the one here: http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx
You also need to identify the correct processes as there may be more than one instance of your application, or other instances of AcroRd32. This is the most deterministic solution, but because your application will now be filtering messages sent to every single window in existence, I generally don't recommend this approach because then your program could negatively affect system stability.
Find an alternate PDF viewing control. See this answer for a few commercial components: .net PDF Viewer control , or roll your own: http://www.codeproject.com/KB/applications/PDFViewerControl.aspx
Find an acceptable hack. Depending on how robust your application needs to be, code such as the following may be suitable (it was suitable for my case):
DateTime _lastRenav = DateTime.MinValue;
public Form1()
{
InitializeComponent();
listBox1.LostFocus += new EventHandler(listBox1_LostFocus);
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
axAcroPDF1.src = "sample.pdf"; //this will cause adobe to take away the focus
_lastRenav = DateTime.Now;
}
void listBox1_LostFocus(object sender, EventArgs e)
{
//restores focus if it were the result of a listbox navigation
if ((DateTime.Now - _lastRenav).TotalSeconds < 1)
listBox1.Focus();
}
I might finally have a ridiculously simple answer. So far in testing this is working.
Having suffered from this problem for quite some time and having built a complex system of each custom control recording which of them last had focus and using a timer to flip focus back (when acropdf grabbed it) I revisited this problem and read a great number of answers (looking for recent solutions). The information gleaned helped me with the idea.
The idea is to disable the (acropdf) control whilst it is loading as in the following example (code reduced for clarity)
AxAcroPDF_this.Enabled = False
AxAcroPDF_this.src = m_src
Then on a timer, after say 1 second.
AxAcroPDF_this.Enabled = True
Basically the idea is to tell Windows not to let users use the acropdf control until allowed, so asking Windows to prevent it from getting focus (because users are not allowed in there).
So far this is holding up, I will edit this if anything changes. If it doesn't work completely for you then maybe the idea points into a useful direction.
It is an out-of-process COM component, that's the problem. Completely in violation of Windows SDK requirements as laid out in SetParent(). Once its window gets the focus, the message loop in the acroread.exe process gets all the messages, your message filter cannot see any messages anymore.
Technically it is fixable by using SetWindowsHookEx() to inject a DLL into the process and monitor messages with WH_GETMESSAGE. But you can't write such a DLL in the C# language.
Major suck, I know. There never seems to be any lack of it with that program.
For some reason Tim's answer, disabling the AxAcroPDF control directly, didn't work in my case. The Leave event on the previously-selected Textbox would never fire, either.
What is working is nesting the AxAcroPDF control inside of a disabled GroupBox. Since the users of my application need to only see the PDF, not interact with it, the GroupBox's Enabled property is set to False in the designer.
I've seen two threads here about TDI & C#. Both of them didn't really answer the questions I have ...
Since TDIs are pretty much like a standard nowadays, I can hardly imagine, that I have to buy a special control (like AvalonDock or SandDock).
This must be possible with built in the tab-control(?) somehow! I don't need special features like dock- and draggable tabitems. Just open every form in a new tab. Thats it.
Like putting every forms content controls into user controls and by request (button, menu click ...) add a new tab and put the corresponding user control on it ... something like this.
How would you do it? This can't be THAT complicated (even for me) or am I missing something?!
thanks a lot!
Maybe Josh Smith's article on MVVM can give you an idea how to design such user interface. Example being built there is kinda tabbed document interface so you can use it as a starting block.
It's not that hard. It seems hard because there are a lot of different ways to do it.
Try this:
<TabControl x:Name="documentArea"/>
Handler for AddForm button:
private void AddFormClick(object sender, RoutedEventArgs e)
{
object form = GetNewForm();
documentArea.Items.Add(form);
}
That's it. You have to implement GetNewForm() in one of two ways. Have it return a user control that displays the form.
OR better yet, have it return your document that you want to display. Use a DataTemplate to select the controls to use for displaying this document. This method is going to be more complex to set up.