I want to run through a series of steps that comprise a complete test. Some of these steps are automatic (so informational) and others require user interaction. Test steps are not known at compile time, they are using MEF to be loaded.
Currently I have something like
public abstract class TestRunnerBase
{
public abstract void Run();
}
With a list of steps like this:
List<TestRunnerBase> Steps = new List<TestRunnerBase>();
So all data representing a test serializable and that works okay so far. However what I really need is for a user to load a test from XML, it then walks them through the options displaying information on screen and gathering results.
But trying to work out how to create a control for data that is unknown at compile time has ended up with me getting a bit stuck on the best approach.
I am thinking to do this I would have a list of custom controls (1 a step) and the GUI would display the first step, wait for that control to be complete (I was thinking here that a raised event might work?) and then display the next if available and so on until the test is complete.
So is it possible to do this in WPF? Can you create a stack of controls in WPF that can each raise the same event to the parent container or is there a better way to do it?
But if I also use the abstract class I can't then derive a control from it also as no multiple inheritance in C# of course.
I would use MVVM and create a viewmodel that understood how to navigate the list of steps, providing a wizard type structure (prev/next) and exposing the current step.
I assume that while you have different kinds of potentially unknown steps that you have a concrete set of input options (bool, text, date, int, etc) then you could use a abstract property on your TestRunnerBase that identifies what kind of input is required (or none) using an enum that must be overriden.
Then you could use datatemplates and/or data triggers to control what is shown for each step of the test. The main viewmodel could check that conditions are right for going to the next step (perhaps a validate on your test).
Some psuedo code to get you thinking:
public enum TestInput
{
None,
Bool,
Text
}
public abstract class TestRunnerBase
{
public abstract TestInput TestInput { get; }
public bool BoolInput { get; set; }
public string TextInput { get; set; }
public abstract bool CanRun()
public abstract void Run();
}
public class MainViewModel
{
List<TestRunnerBase> Steps = new List<TestRunnerBase>();
public TestRunnerBase CurrentStep {get;set;};
public MainViewModel()
{
//loads the Steps
CurrentStep = Steps
}
public Command RunStepCommand
{
if (CurrentStep.CanRun())
{
CurrentStep.Run();
CurrentStep = Steps.Next(); //you get the idea
}
}
}
For your XAML you would bind a ContentPresenter to CurrentStep and use a datatemplate (and maybe data triggers) to control what is visible to the user (and of course bound to the UI).
In WPF you can dynamically create controls using XAML. Simply create a XAML snippet with the layout you want (either programatically or by hand) and use XamlReader.Parse to create the entire tree from the snippet. The returned object can then be inserted somewhere in the visual tree of your window.
To generate events from the visual tree generated by XamlReader you can use routed events.
Related
I'm searching for a way to write less sameish looking code and I'm not sure if there is a solution for this. So far I tried using Visual Studio Snippets, but that was not as helpful as needed. I would love to have C-Style Macros for this, or even better using C# language features.
Here is what I'm currently working on and the problem I have with it:
I'm writing full feature tests for an embedded device with a Web-UI in C#. I'm using Selenium to interact with the UI and have written some small classes to interact with custom input elements. The UI has many pages on which different controls are visible and naturally I created a class for each page and added all the input element classes for each controllable element.
This looks something like this (input element would be the Switch and ValueInput class):
public class SomePage : Page
{
protected const string id = "page_id";
#region ContentControls
protected Switch time_limit_enable;
protected ValueInput time_limit;
// and more ...
#endregion
internal SomePage() : base(id) { }
protected override void Init()
{
time_limit_enable = new Switch("time_limit_enable_id");
time_limit = new ValueInput("time_limit_id");
// and more ...
}
#region GetterSetter
public bool TimeLimitEnable
{
get => time_limit_enable.State;
set
{
if (time_limit_enable.State != value)
time_limit_enable.Toggle();
}
}
public string TimeLimit
{
get => time_limit.Text;
set => time_limit.Text = value;
}
// and more ...
#endregion
}
While this example page is small, the real pages have a lot more elements often of the same type (Switch, ValueInput, and more). The only thing that I want to specify is the element class, the id of the element, and the name. Some element classes have a template parameter as well. So basically the construction of the element. Is there some way to automate everything else?
Meaning:
creating a protected element
Initializing it in the Init() function
Adding a property getter and setter, named like the element in CamelCase. This property template would be different for different element classes.
Possible solutions:
Make the element class directly public readonly. Sounds ok, but then I would expose the different interfaces to the test side. I like that every property can be read and read directly with =. I could implement this in each element class though.
I could write a Code generator to do this, but that would be overkill. I'm probably looking at this from the wrong angle.
I could hack C-Style macros in c#, but that's just wrong.
I feel a little bit lost in the weeds. The solution is probably straightforward and obvious.
Given a basic C# library, how do I implement functions of this library into my WPF application to handle appropriately the concepts of Binding and Commands?
I mean, need I write some own wrappers for these library classes in order to implement interfaces such as ICommand or should this be done directly in the library itself?
Some code to get my question more comprehensible:
From the library:
public class Item
{
public string Name { get; set; }
public void DoSomething() { throw new NotImplementedException; }
}
I want to implement the function DoSomething() in my XAML markup without any line of code in that .cs file since that is, from what I've read, the best practice.
(Assuming that an instance of Item is bound to the control)
<Button Command="{Binding DoSomething}"/>
Well, in order to do so, I need to implement the interface ICommand and create a command, but that is, as stated above, unclear to me since I'm using a library here.
Should I write my own Wrapper for the Item class of the API and implement the ICommand interface or is there any other way to archieve this? I've written the library by myself so changes are possible. I'm just not entirely sure about changing the library because if I do so, it is (possibly) bound to WPF.
Hi there if anything your ViewModel should handle any requests on your Model that's it's sole purpose, to get these things to work you need ICommand and if you want some more info here is link with a tutorial on RoutedCommands. If you have your Model and ViewModel defined then you can easily assign tasks to the particular Model through its VM.
P.S. I think you could treat your library as a Model and write a "wrapper" ViewModel to handle operations on it. HTH
UPDATE
Consider following:
class libClass
{
void method()
{
//do something here
}
}
code above would be your model and if you want it to be more readable you could do it this way
class libModel
{
private libClass _libClass;
public libClass LibClass { get; set; }
}
Note
You could implement INotfiyPropertyChanged in your Model to handle any changes if needed of course.
now in your VM how you use the Model
class ViewModel
{
private libModel _libModel;
public libModel LibModel { get; set; }
//after you set up your RoutedCommands
//I declare method within my VM to handle the RoutedCommands don't know
//if it works when you use Property Method
void VMMethod()
{
//use VM's property to invoke desired method from your lib
}
}
and voila! ready "wrapper" for your class with implementation in your VM.
Tip
If you want to know how to do the RoutedCommands here is a link to a tutorial.
I've got a WPF MVVM application. One of my views has a user control that needs to be customizable for each installation. It's basically a sketch of the customers installation with some labels etc. bound to a viewmodel.
Now my problem is that this user control is different on each site/installation. One approach is to load the xaml from a file/database runtime using a xaml reader. This works but since my viewmodel is generic I have to bind to methods instead of properties and I can't load a xaml with objectdataprovider.
Currently I'm trying to see if MEF can be used so that I can create the user control as a plug-in. So what I'm looking for now is this:
how can I define a user control with view/view model that exports a contract for MEF
How can my parent view (in my wpf app) load the imported user control
Any tips are appreciated, or maybe someone has a different approach?
I suggest you look into Prism in combination with MEF. It has a notion of Modules (plug-ins in your case) and Regions (mechanism of dynamically loading views).
You will be able to export a view using a simple attribute:
[ViewExport(RegionName = RegionNames.MyRegion)]
public partial class MyView : UserControl {
public MyView() {
this.InitializeComponent();
}
[Import]
public MyViewModel ViewModel {
set { DataContext = value; }
}
}
[Export]
public class MyViewModel : ViewModelBase
[
...
}
And in your main application XAML you will be able to import the plugin's views like this:
<ContentControl Regions:RegionManager.RegionName="{x:Static Infrastructure:RegionNames.MyRegion}"/>
One thing I'd consider is the design where you need to install a custom View for each installation. Instead, I'd look to make that View more generic. This will make your design more simple in the long run. Plus, you are setting up for a maintenance nightmare with a different installation for every installed base.
It's a little difficult to tell from your description, but it sounds like the View is a collection of some kind of an object (some kind of drawing with a label or something). Therefore, I'd treat it as such.
I'd create a base abstract class that describes what every object that your View could show. Since I don't have more information, I'll call this thing a "DrawingObject" for lack of a better term. This class would hold all information common to all objects in your View. Note that ObservableItem is a class that implements INotifyPropertyChanged, and SetProperty sets the value in that base class and raises PropertyChanged.
abstract class DrawingObject : ObservableItem
{
Point mPosition;
public Point Position
{
get { return mPosition; }
set { SetProperty("Position", ref mPosition, value); }
}
String mLabelText;
public String LabelText
{
get { return mLabelText; }
set { SetProperty("LabelText", ref mLabelText, value); }
}
}
Then, derive more custom objects from that base class:
class Counter : DrawingObject
{
public Counter() : base()
{
}
}
Your ViewModel would then just have a collection of these objects, using the base class. The set may be private, because you will probably get the objects from someplace in the constructor (i.e. the database, or a flat file, or...)
class ViewModel : ObservableItem
{
public ViewModel() : base()
{
// Call something to populate DrawingObjects property
PopulateDrawingObjects();
}
ObservableCollection<DrawingObject> mDrawingObjects =
new ObservableCollection<DrawingObject>();
public ObservableCollection<DrawingObject> DrawingObjects
{
get { return mDrawingObjects; }
private set { mDrawingObjects = value; }
}
}
Then, your View would bind to this collection and draw them appropriately (I'll leave that as an exercise for the implementer).
One extension that I didn't show is that the DrawingObject may need to implement the appropriate serialization functionality.
Obviously, this is a rough sketch of the design, and may have a couple of errors (I did it from my head), but hopefully it's enough to go on.
When thinking of the SRP, I find that an application that I'm writing is getting out of hand for our main interface/form. I'd like to change it before we get too far into the project.
What are some techniques for making a large interface that has a "drawing surface" with toolbars, menus etc? I'd also like it to be easy for this form to be testable. Should there be other classes that know how to control the MainForm such as a ChangedStateTracker (to monitor dirty state), DocumentCreator or something along those lines to "File > New" a new document?
The problem that I'm running into is there are so many methods inside the MainForm.cs and it's really starting to get ugly to maintain.
This can be marked CW if necessary. Any other hints/tips would be greatly appreciated.
If this is an option, I would create a set of user controls that together produce the entire form.
These separate user controls can then have their own responsibility and can be tested separately.
For the logic itself, create classes.
You can create classes like CreateDocumentCommand that implement some functionality. When e.g. the new document button/menu item is clicked, create an instance of this class and execute it.
public interface ICommand
{
bool CanExecute { get; }
void Execute();
}
public class SaveDocumentCommand : ICommand
{
public bool CanExecute
{
get
{
return MainForm.Instance.CurrentDocument.IsDirty;
}
}
public void Execute()
{
// Save your document here.
}
}
This by the way is how WPF does it.
Jeremy Miller has written about this a few times - these should get you started:
http://codebetter.com/blogs/jeremy.miller/articles/129546.aspx
http://www.jeremydmiller.com/ppatterns/default.aspx
We are investigating how to create data entry views from a dynamic list of pre-defined field definitions. By "pre-defined", I mean that there are only 8 basic field types. The Silverlight Toolkit's DataForm control is almost what want, but it targets object properties (not a list of custom definitions).
Is there an existing project to make this easy? Please comment on my design idea (below). I have only ~2 weeks Silverlight experience.
Basic design idea:
I am thinking of defining custom data field types. An IEnumerable<BaseDataField> will be received by the UI, enumerated, and controls will be created based on the type of each field. Each field will create a label with the description and BooleanDataField will create a CheckBox, LookupDataField will create a ComboBox, etc.
Pseudo code to clarify the idea:
public abstract class BaseDataField {
public string FieldCode { get; private set; }
public string FieldDescription { get { return FieldDefinitions.Instance.FieldDescription(FieldCode); } }
...
}
public class StringDataField : BaseDataField
public class BooleanDataField : BaseDataField
public class CurrencyDataField : BaseDataField
public class IntegerDataField : BaseDataField
public class NumericDataField : BaseDataField
public class DateTimeDataField : BaseDataField
public class LookupDataField : BaseDataField
public class SpecialDataField : BaseDataField
This will be extended to make the fields bindable; allow specifying custom controls for each type; and have validation feedback.
Can it be easily done in Silverlight or should we create a custom control?
Note: This programme will be a web UI for an existing, multi-tier LOB platform. All data is serialised from a JSON-based REST service.
Thanks!
I would highly recommend incorporating the DataForm class into your solution and it is indeed capable of handling custom controls. I've been chasing this goal of an ideal minimal-xaml data form for years and I have finally settled on what I think is a great combination of the built-in functionality of DataForm and custom fields derived from DataField. For example, I just extended DataField so that when no Content property is specified, it automatically uses a TextBox which minimized my XAML big time. I also added support for the DisplayFormatAttribute which DataForm doesn't seem to support natively.
Anyhow, what you could do first is create a bunch of subclasses like you describe above and derive from DataField. Then in the OnApplyTemplate method, create an element to represent the data. For example:
class BooleanDataField : DataField {
protected override void OnApplyTemplate() {
if (this.Content == null) {
var check = new CheckBox();
check.SetBinding(CheckBox.IsCheckedProperty,
new Binding(this.PropertyPath));
this.Content = check;
}
base.OnApplyTemplate();
}
}
As for how to get your field metadata loaded by DataForm, you have a few options. You could handle the AutoGeneratingField event and look up the appropriate field to use on the fly or you can disable auto field generation and just load it up with your own.
We started with DataForm, but ended up overriding everything that makes it useful and still had some problems. I learned a great deal from the attempt and eventually built a custom control for the job. Unfortunately this solution is not very extensible...