How can I serialize wpf user control with xaml and code behind - c#

I want to serialize wpf user control xaml and codebehind. XamlWriter.Save() only serialize's xaml so what can I do in this situation? My situtation is I have a usercontrol which include custom methods, subscribed events (ex: button click) When I deserialize usercontrol (for create usercontrol at runtime) I want to run that events and methods. Sorry my english isn't very good.

Just an idea, you can use MEF to built up a plugin structure for your user control. You want to create a user control on the fly but the event handler still should be hardcoded somewhere else in your project; with the plugin structure, you can just collect the plugin and reuse it; the events can be handled by a command something. Maybe giving a scenario and we can figure out more detail.
Plus, ISerializable provides a way for custom binary serialization for field, not for methods or events. Here is a related question:
What is the point of the ISerializable interface?
; on the other hand, you can still try some pattern like how the web control save its view state; for example
two virtual methods:
public virtual byte[] SaveState(); // it saves the states for your custom control
public virtual void LoadState(byte[] state) // it restore your state back to the control.
The custom code should be like:
byte[] state = controlA.SaveState(); // this method saves its own state.
YourControl controlB = new YourControl();
controlB.LoadState(state); // this method load the save state from A to B itself.
For the event, every event has a handler name, you can also serialize its handler name to the state and find it back by the saved name from its naming container alike. I don't have any experience to save the method.
If you still want to save and load state including fields, events and method, maybe serialization is not the proper way you are looking for I think.

Related

ViewModel calling a method of a user control (web browser)

I am trying to program in MVVM and I have the following use case:
A TextBox's text is bound to a property in the VM
A Button is command bound to a relay command
When the user presses the Button, the web browser's Navigate(url) method is called with the URL being the text in the TextBox
Above is the use case I want to create, but 1 and 2 is possible using the MVVM design pattern, but I could not find an adequate way to invoke the browser's Navigate() method. First of all, is it possible to call a method of a control from VM (please let me know if there is a way)? And in the above use case, what would be the appropriate way to structure the program if it is not possible?
Thanks
You could do the following:
Add a property MyUrl to your ViewModel
Bind MyUrl to your WebBrower's Source property
Make sure the property implements INotifyPropertyChanged. Then your Xaml:
<WebBrowser Source="{Binding MyUrl}" />
What if you REALLY wanted to call a UI method from the ViewModel?
If you ever do run into a situation where you absolutely need to call a method on a UI control for instance, you can hook up events on the ViewModel and then your UI registers to this event and does something UI specific...
VM code...
//... some VM logic
EpicNavigateEvent(url) // raise event, allowing UI to handle how
In your code-behind on your view (this is the part where some MVVM purests freak), you could register the event:
myVm.Navigate += doSomeNavigation;
...
public void doSomeNavigation(string url)
{
// call Navigate
}
I've successfully used this approach for applications where we have a single ViewModel layer and multiple technologies hooked up the views (WinForms, WPF and Asp.Net).
If you're looking for something more elegant, have a look at the User Interaction Patterns on MSDN.
The concept is the same though: Call something on the VM and the View is handles it appropriately.
Common scenarios for this type of approach is want to show a message to the user from the VM. Your VM should raise an event saying: ShowMyMessage("You're awesome"), then your UI is notified and handles it: MessageBox.Show(msg) or whatever.
As long as you stick to there rules you should be golden:
ViewModels should NOT be concerned about UI code
Views must ONLY handle the presentation of the data provided by your ViewModels.
Don't overcomplicate it. KISS...

Correct UserControl Usage?

I just started breaking up my GUI application into UserControls. I have a TabControl with a bunch of TagePages. Obviously my MainForm.cs file was filled up with tons of events and controls etc and it got very messy quick.
So a previous question gained me the insight of how to create a UserControl. I intend on creating a UserControl for each TabPage and I was wondering how I can interact with Components on the main form or other UserControls.
Here is an example of a TabPage that I have made using a UserControl, which needs to Enable or Disable a button depending which TabPage is currently selected. Is this proper usage or is there a better way?
public partial class TabDetails : UserControl
{
private RequestForm fRequestForm;
public TabDetails()
{
InitializeComponent();
}
public void CustomInitialization(RequestForm pRequestForm)
{
fRequestForm = pRequestForm;
pRequestForm.TabControl_Main.SelectedIndexChanged += SelectedTabIndexChanged;
}
private void SelectedTabIndexChanged(object pSender, EventArgs pEvents)
{
fRequestForm.Button_SubmitRequest.Enabled = fRequestForm.TabControl_Main.SelectedTab != fRequestForm.Tab_Details;
}
}
In the MainForm.cs constructor I call:
this.tab_Details1.CustomInitialization(this);
This doesn't look like a good use of a user control. The user control should not decide how things in the form should behave when something is changed in the user control. A user control should be unaware of its container and should operate in any container.
The user control should notify the form that something has changed without telling what's the internal implementation and the form should decide what to do.
Example:
A user control named "NameUserControl" consists of TitleComboBox, FirstNameTextBox and LastNameTextBox. The user control wants to notify when one of the values has changed.
Wrong Way:
Create events:
TitleComboBox - SelectedIndexChanged.
FirstNameTextBox, LastNameTextBox - TextChanged.
The problems here:
You expose the internal controls behavior. What will happen if you want to change the TitleComboBox to TextBox? You'll have to change the event name and implementation.
You expose the fact that you use exactly 3 different controls. What will happen if you want to use the same text box for first and last name? You'll have to delete one event and change the name of the other.
Good Way:
Create only a single event: NameChanged and expose 1 property of FullName or three different properties for the values.
Either way the form subscribe to the event and decide what to do next.
Another thing to think about: the more you add more functionality to your user control, you either make it less reusable or you make its code more complex. For example, if you add validation inside the user control, you'll find one day that you need it without validation, so you'll add a property "bool ValidateData" or it will be so complicated that you'll need to build another control. One way to solve that is to build very small user controls, but combine them in one or more bigger user controls that fit all your current needs.

Is there a dynamic-creation-friendly LinkLabel Alternative?

I'm trying to dynamically create a link from a Windows Form to our website when certain conditions are met (it's a warning message with further information in our online manual).
Currently I'm finding LinkLabel quite unwieldy to use in this situation: having to set up LinkClicked handlers on the fly for a straightforward hyperlink seems inelegant.
Is there a wrapper or alternative that fulfills the following requirements?:
Inherits from System.Windows.Forms.Control (so I can use it in a TableLayoutPanel)
Has reasonably low setup (no strange LinkClicked function pre-visit checking, for example)
Isn't bound to a specific browser
What is your problem with the LinkClicked event handler? You would have to do the same for almost any control in order to do anything useful.
Anyway, it would be trivial to implement yourself - create a class that inherits from LinkLabel, add a string URL property (you may need an attribute to make this show in the designer properties panel if you want to set it that way) and provide an event handler that opens the browser with that URL.
Then you can just add the control in the designer (or at runtime), set the URL property and it will work without having to set event handlers.
Did you use the LinkClicked event instead of OnClick? Then you can use this in the event handler:
(sender as LinkLabel).LinkVisited = true;
System.Diagnostics.Process.Start("http://example.com");
It's not bound a specific browser - opens in the user's default browser. The setup is low - just instantiate the LinkLabel, add an event hookup to LinkClicked (which is one two-line method) and add it to the page. What's unwieldy about this approach?
In the end I used LinkLabel.Links.Add to modify the link destination dynamically..

Creating a class for storing extra information and linking it to a host class

So I have been trying to figure out the best way to go about this but always end up hitting a wall somewhere.
Basically, my problem is this: I have a layer that can draw items of the type UIElement. In my case, I need to be able to draw UIElements of two types, Image and Shape. They are both inherited from UIElement.
Now I want to create a class of my own, lets call the class a LayerItem. The LayerItem contains some additional information about the specific item, such as the name.
My first solution was to inherit the LayerItem from the Image-class and add the new fields. This way I was able to also catch all the events that the Image-object received (for example MouseOver) and then cast the object to LayerItem for the retrieval of the extra related information. Showing the image was accomplished by setting the object's Source-property.
This approach, however, does not work if the objects can also be shapes, since shapes do not have the Source-property.
Basically what I am looking for is "the right way" to accomplish this, in a way that allows me to use the events directly. Only solution I can currently come up with is to have a dictionary mapping the UIElements to the LayerItems, then fetching the LayerItem from there by the use of the UIElement whose event was raised. So, are there some better, perhaps more sophisticated ways of accomplishing this?
EDIT:
Thanks for the reply, but I'm not sure that's exactly what I am looking for. Let me try to clarify. Basically, I have a layer that I can draw different things on (Images or Shapes) by adding the graphic in question onto the layer and giving it coordinates.
The idea is that the user can click on the layer and choose from a list of things what kind of a graphic he/she would like to use to represent the added item. The extra information about the item, such as id and name, are stored in a database and I need a way to link this information to the graphical item.
So all of this would be handled by code, the items are created and deleted dynamically. This is also where the events come in. To be able to recognize which item the user clicked (to show the extra information, allow drag-n-drop etc), I think the events produced by the UIElement are the easiest to use.
And about providing code as an example, well that's slightly hard because it depends a lot on the implementation :) But I surely can try and put something up if my explanation still isn't clear enough!
I would start by making a LayerItem descendant of UIElement, and then make all other needed classes descendants of LayerItem. Final hierarchy would look like this:
UIElement
LayerItem
ImageLayerItem
ShapeLayerItem
etc.
And, if you want LayerItem to report any events from child-classes, then just have the event in LayerItem and let child-classes raise that event on their own events, like this:
class LayerItem
{
public string Name { get; set; }
public event EventHandler ItemEvent;
protected virtual void OnItemEvent(EventArgs e)
{
if (this.ItemEvent != null)
this.ItemEvent(this, e);
}
}
class ImageLayerItem : LayerItem
{
private Image _image;
public ImageLayerItem()
{
//here create Image element and think of rendering it.
_image = new Image();
//attach event handlers.
_image.Click += ... //don't forget to call LayerItem.OnItemEvent() inside the event handler.
}
}
Also:
I would recommend having a special event handler type with corresponding special event arguments type in the LayerItem instead of just EventHandler and EventArgs. A good example would be LayerItemEventArgs which contains the name of event which was raised by one of the child classes (like ImageLayerItem) and its parameters. This way you can handle all the events by handling only the LayerItem.ItemEvent event; or you could just handle the events of child classes as a classical approach.
I hope this helps to be the head start where to go.
Seems like you could use attached properties for the extra information you want to store which your Layer needs.
A good example how this can be used is on the msdn page.
<DockPanel>
<CheckBox DockPanel.Dock="Top">Hello</CheckBox>
</DockPanel>
Checkbox doesn't define the Dock property, DockPanel does. Any element can now set the Dock property.

Implementing MVC/MVP Design for TabControl ..design question

I have a an Winform application with 2 forms.
In one form I have a Tab Control with 3 Tabs and navigation buttons to switch between tabs.
On the first tab the user selects a file and on navigating to next tab i want to do some
processing on the file selected in the first tab,and show the result in the 3rd tab.
The other form just invokes this form(start app.)
How can i do this using MVC/MVP ?
Currently i have created nested forms.
Starting application form creates instance of tab form and on SelectedIndexChanged on
the tab control and matching the selected tab property I'm doing the processing in the starting application form.and On closing on the tab form setting the result in the
starting application form.(which isn't ideal).
Edit : Also each tab contains a User Control which i have to initialize on tab change (refereeing to the data selected in the previous tab.)
Simple example is selecting a .zip file in the first tab , clicking next
will show the list of files within the zip file and in the third tab do processing with
the file selected in the 2nd tab.(there are better ways to do the same..just for sake of example.)
EDIT 2 : Basically I'm confused on how to get values from first tab via controller, do processing, and pass it to the next tab( via controller) and set the user control properties on the 2nd tab (via controller).Also the Tab titles are removed ..please see ..so the Tab form looks more like a wizard form. that's why i was using the SelectedIndexChanged property.
Basically i need to separate view and processing logic from the Winform.
Thanks All.
Odd choices for a UI. Anyhoo, there is no reason whatsoever to wait for SelectedIndexChanged to process the file. You might as well do it as soon as the file is selected. It will work better, the tab control becomes more responsive. If you wait until the event then the control will be frozen for a while as your UI thread is busy iterating the .zip file. The user will not consider this desirable.
Makes the MVC implementation a lot simpler too, whatever it might look like. Extra bonus is that you now no longer depend on the TabControl and can use whatever controls are best for the job.
Your Model will deal with your zip file in this case, e.g. methods like Print(), Extract() etc. and events like PrintCompleted and ExtractCompleted etc.
Your IView will expose methods and events that abstract your interaction with the UI behind an interface. So perhaps some methods such as DisplayFolderContents() and events like FileSelected() etc.
Your presenter will hook up to the Model and IView events and control which methods are called on each etc. The Form that you have a TabControl on is just an implemenation of the IView interface. You could have a different view just by injecting an implementation of IView into the Presenter, including a Mock IView for testing.
Values can be passed around the MVP pattern through the EventArgs you use.
/// <summary>
/// The event args for a selected file.
/// </summary>
public class FileSelectedEventArgs : EventArgs
{
public string FileName { get; private set; }
public FileSelectedEventArgs(string fileName)
{
this.FileName = fileName;
}
}
When the user selects a file, the FileSelected event is raised in your View, with the FileName available in the FileSelectedEventArgs. The Presenter listens for this event, and calls a method on the Model - maybe ExtractFile(string fileName), passing in the fileName from the FileSelectedEventArgs from the View.
The Presenter then listens to the ExtractCompleted event to be fired from the Model (which also has whatever custom eventargs you want) and calls the appropriate method on your View, passing in the parameters from the Model. The method in the View can do whatever you want in terms of displaying the data in a TabControl or in another way.
This is just one way of doing it anyway.

Categories