I have a very simple controls library for Windows Forms and I am getting problems to implement accessibility.
I have a very simple Form with a member that contains a list of controls of my library, and I have overriden the CreateAccessibilityInstance:
public partial class Form1 : Form
{
protected override AccessibleObject CreateAccessibilityInstance()
{
return new AccessibleForm(this);
}
public MyContainer MyContainer;
public Form1()
{
InitializeComponent();
MyContainer = new MyContainer();
MyContainer.Controls.Add(new MyButton());
}
}
The AccessibleForm class looks like:
public class AccessibleForm: Control.ControlAccessibleObject
{
private Form1 form1;
public AccessibleForm(Form1 owner):base(owner)
{
this.form1 = owner;
}
public override AccessibleObject GetChild(int index)
{
return this.form1.MyContainer.Controls[index].AccessibilityObject;
}
public override int GetChildCount()
{
return this.form1.MyContainer.Controls.Count() ;
}
}
MyContanier and MyButton classes inherits from BaseControl, they are very easy:
public class BaseControl : Control
{
protected override AccessibleObject CreateAccessibilityInstance()
{
return new AccessibleObject();
}
}
public class MyContainer:BaseControl
{
public List<BaseControl> Controls { get; set; }
public MyContainer()
{
this.Controls = new List<BaseControl>();
}
}
public class MyButton:BaseControl
{
}
The point is that when I run the UIVerify tool to see if my controls are generating the correct structure I can not see them:
Another point is, that if I modify the GetChild method from AccessibleForm class in this way:
public override AccessibleObject GetChild(int index)
{
return new AccessibleObject();
////return this.form1.MyContainer.Controls[index].AccessibilityObject;
}
I can see a node on the UIVerify:
But modifying the GetChild method to return a custom accessible object it shows me nothing.
Why are not my controls on the tree?
I do not know what I am missing.
Override Name,value,Role in AccessibleForm class
Related
My model is mainly made from the 2 classes below (I actually got another class which inherits from the abstract class but it doesnt matter I think):
public abstract class FeedForEvents: BaseObservableObject
{
public abstract void ReadFeed();
public List<Event> Events { get; set; }
public void AddEvent(Event aEvent)
{
Events.Add(aEvent);
OnPropertyChanged("Events");
}
}
public class Event : BaseObservableObject
{
public string MyProp
{
get
{
return _myProp;
}
set
{
_myprop= value;
OnPropertyChanged();
}
}
}
My form contains:
private BindingList<FeedForEvents> ListFeedsForEvents = new BindingList<FeedForEvents>();
private BindingList<Event> ListEvents
=> new BindingList<Event>(ListFeedsForEvents.SelectMany(m =>m.Events).ToList());
private BindingSource pagesBindingSource = new BindingSource();
public void RefreshGrid()
{
pagesBindingSource.DataSource = ListEvents;
this.grdEvents.DataSource = pagesBindingSource;
this.grdEvents.AutoGenerateColumns = true;
}
But even if my 2 objects correctly raised the PropertyChanged notficiation, the interface never show the objects updated (unless I manually refresh them by pressing a button to manually call RefreshGrid() ). Why?
I am maintaining one object(Parent) in my MainWindow class. That Parent Object is being passed to another object(objMyClass). Now If I update Parent Object in mainwindow, it is not reflecting it in objMyClass object. Below is the code.
using System.Windows;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public Parent objParent;
public MyClass objMyClass;
public MainWindow()
{
InitializeComponent();
objParent = new Parent();
objMyClass = new MyClass(objParent);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if ((bool)checkPWB.IsChecked)
objParent = new Child1();
else
objParent = new Child2();
objParent.Display();
objMyClass.par.Display();
}
}
public class MyClass
{
public Parent par;
public MyClass(Parent p)
{
par = p;
}
}
public class Parent
{
public virtual void Display()
{
MessageBox.Show("I am Parent");
}
}
public class Child1 : Parent
{
public override void Display()
{
MessageBox.Show("I am Child1");
}
}
public class Child2 : Parent
{
public override void Display()
{
MessageBox.Show("I am Child2");
}
}
}
When I click the button, I am creating a new object (Child1) and assigning to my parent object which doesn't reflect it in ObjectMyClass.
Any help on this is appreciated.
To refer to the same field you can use Func<Parent> that would return current value of the filed:
public class MyClass
{
private Func<Parent> getParent = null;
public Parent par => getParent();
public MyClass(Func<Parent> getParent)
{
this.getParent = getParent;
}
}
and construct your class as
objMyClass = new MyClass(() => objParent);
This way instead of having its own reference to Parent object that contains copy of the original value of the parameter (as in code in the question) this MyClass will always return current value of objParent field and indeed reflect changes to that field.
Alternatively you can just change par property directly instead of changing objParent.
I'm working on a project that has a variety of classes that derive from class View, where View provides some common methods and where the derived classes have fields that reference UI elements specific to that view. For example (in C#):
public abstract class View
{
public virtual void Initialize(){}
public virtual void Activate(){}
public virtual void Deactivate(){}
}
public class MainScreenView : View
{
private ImageView portraitImageView;
private ImageView landscapeImageView;
public MainScreenView(ImageView portrait, ImageView landscape)
{
portraitImageView = portrait;
landscapeImageView = landscape;
}
public override Initialize()
{
base.Initialize();
portraitImageView.Initialize(); // I would like to eliminate these calls!
landscapeImageView.Initialize();
}
public ImageView GetPortrait() { return portraitImageView; }
public ImageView GetLandscape() { return landscapeImageView; }
}
public class ImageView : View
{
private Image image;
public ImageView(Image image) { this.image = image; }
public override void Initialize() { base.Initialize(); image.Show(); }
public Image GetImage() { return image; }
}
In this example I have to call Initialize() on all the ImageViews when MainScreenView.Initialize is called. This feels error prone and inconvenient, because an Initialize() call has to be added every time a new sub-view is added to the MainScreenView composition. Therefore, I would like to eliminate the need for these calls in the derived classes, but I want to maintain the fields to the view-specific fields.
My idea is to add a collection of Views to the base class, which can then recursively be Initialized(), as follows:
public abstract class View
{
private List<View> subViews;
public virtual void Initialize()
{
foreach(View in subViews) { view.Initialize(); }
}
// This gets called before Initialize() is called.
public void AddSubViews(View[] views)
{
subViews = new List<View>();
subViews.AddRange(views);
}
}
public class MainScreenView : View
{
private ImageView portraitImageView;
private ImageView landscapeImageView;
public MainScreenView()
{
portraitImageView = ???;
landscapeImageView = ???;
}
// Even if View.subViews had been protected instead of private, this couldn't return an element from the list because the required index is unknown.
public ImageView GetPortrait() { return portraitImageView; }
public ImageView GetLandscape() { return landscapeImageView; }
}
public class ImageView : View
{
private Image image;
public ImageView() { this.image = ??? }
public override void Initialize() { base.Initialize(); image.Show(); }
public Image GetImage() { return image; } // Even if View.subViews had been protected instead of private, this couldn't return an element from the list because the required index is unknown.
}
However, because all the individual sub-views are now 'anonymous' (they are accessed by index instead of a field name), this won't work for me, unless I also add the sub-views through the derived class' constructor as I did in my first example, where I can't enforce that the objects passed to the contructor are the same objects that are in the list, or call AddSubViews from the derived class' constructor where the sub-views are manually added every time a new sub-view is added... which has the same issue as calling Initialize() on sub-views in the derived classes.
So my question is: is there a way to have all Initialization calls of sub-views being done in the View base class, while still being able to provide derived-class-specific elements without passing references to those elements to the derived class' constructor?
UPDATE: If you want to be sure all sub views are initialized (i.e. nobody forget to add them to base class list of sub views) you can use reflection approach. Here is main idea:
public interface IView // you don't need abstract class
{
void Initialize();
}
Use reflection to get all class fields which implement IView and was initialized:
public class View : IView
{
private IView portraitView;
private IView landscapeView;
// assign some values to sub-views
public virtual void Initialize()
{
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var subViews = from field in GetType().GetFields(flags)
let value = field.GetValue(this)
where value != null && value is IView
select (IView)value;
foreach (var subView in subViews)
subView.Initialize();
}
}
Simple as that. Now if anyone will add field of IView type to your class it will be initialized with other sub-views.
ORIGINAL ANSWER: Just add both views to base class subViews list:
public MainScreenView(ImageView portrait, ImageView landscape)
{
portraitImageView = portrait;
landscapeImageView = landscape;
AddSubViews(new View [] { portrait, landscape });
}
Also keep in mind that you are re-creating subViews list each time when you are trying to add new views:
public void AddSubViews(View[] views)
{
subViews = new List<View>(); // here
subViews.AddRange(views);
}
I believe it's better to create subViews list only once during class field initialization:
private readonly List<View> subViews = new List<View>();
public void AddSubViews(params View[] views) // you can use params here
{
subViews.AddRange(views);
}
Now you simply can call
AddSubViews(portrait, landscape);
You can use the following pattern:
public abstract class View
{
private IEnumerable<View> SubViews { get; }
protected View(params View[] subViews)
{
SubViews = subViews;
}
public void Initialize()
{
OnInitialize();
foreach (var view in SubViews)
{
view.Initialize();
}
}
protected abstract void OnInitialize();
}
Now you concrete views will look like:
public class MainScreenView : View
{
private readonly ImageView portraitImageView;
private readonly ImageView landscapeImageView;
public MainScreenView(ImageView portrait, ImageView landscape)
: base(portrait, landscape)
{
portraitImageView = portrait;
landscapeImageView = landscape;
}
protected override void OnInitialize() { }
public ImageView GetPortrait() { return portraitImageView; }
public ImageView GetLandscape() { return landscapeImageView; }
}
public class ImageView : View
{
private readonly Image image;
public ImageView(Image image)
: base()
{
this.image = image;
}
protected override void OnInitialize() { image.Show(); }
public string GetImage() { return image; }
}
And finally,
var main = new MainScreenView(new ImageView(portraitImage), new ImageView(landScapeImage));
main.Initialize();
will initialize correctly all views.
public partial class TestConrol : UserControl
{
public TestConrol()
{
InitializeComponent();
}
public override string ToString()
{
return "asd";
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
TestConrol tc1 = new TestConrol();
comboBox1.Items.Add(tc1);
TestConrol tc2 = new TestConrol();
comboBox1.Items.Add(tc2);
}
}
When form loaded, I see combobox has two items with empty names, instead of "asd" :/
But this work if I override ToString() in common class, not derived from anything:
public class TestClass
{
public override string ToString()
{
return "bla bla bla";
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
TestClass tcl = new TestClass();
comboBox1.Items.Add(tcl);
}
}
After that I see in combobox "bla bla bla"
Create a property in you control and map the DisplayMember of the combobox to that property, it should work.
I tried to understand the source code(!). This is not a simple call to ToString().
There's an internal class System.Windows.Forms.Formatter doing some stuff. It eventually creates a converter. This is roughly equivalent to saying:
var conv = System.ComponentModel.TypeDescriptor.GetConverter(tc1.GetType());
where tc1 is the TestContol from your question. Now, had we used the TestClass tcl which doesn't implement any interfaces, this would have given us a converter which would eventually call ToString().
But in this example we use tc1, and it is a System.ComponentModel.IComponent. Our conv therefore becomes a System.ComponentModel.ComponentConverter. It uses the Site of the IComponent. When we say:
string result = conv.ConvertTo(tc1, typeof(string));
and the Site is null, we get the empty string "" you saw in your combo box. Had there been a Site it would have used its Name instead.
To demonstrate that, put the following into your TestControl instance constructor:
public TestConrol()
{
InitializeComponent();
Site = new DummySite(); // note: Site is public, so you can also
// write to it from outside the class.
// It is also virtual, so you can override
// its getter and setter.
}
where DummySite is something like:
class DummySite : ISite
{
public IComponent Component
{
get { throw new NotImplementedException(); }
}
public IContainer Container
{
get { throw new NotImplementedException(); }
}
public bool DesignMode
{
get { throw new NotImplementedException(); }
}
public string Name
{
get
{
return "asd"; // HERE'S YOUR TEXT
}
set
{
throw new NotImplementedException();
}
}
public object GetService(Type serviceType)
{
return null;
}
}
Use comboBox1.Items.Add(tc1.ToString()); instead of comboBox1.Items.Add(tcl);
This worked for me:
comboBox1.FormattingEnabled = false
In your UserControl, add a property, and call it FriendlyName for example, as such
namespace project
{
public partial class CustomUserControl : UserControl
{
public CustomUserControl()
{
InitializeComponent();
}
public String FriendlyName { get => "Custom name"; }
}
}
And then set the DisplayMember property of your ComboBox to "FriendlyName", as such
myComboBox.DisplayMember = "FriendlyName";
And to me, this was a very clean solution and gut tells me it is the intended way to do it.
I'm deriving a class from a parameterless-constructor class like this:
public class Base
{
public Base(Panel panel1)
{
}
}
public class Derived : Base
{
public Derived() : base(new Panel())
{
//How do I use panel1 here?
}
}
How can I refer to panel1 in Derived?
(Simple workarounds welcome.)
Adil's answer assumes that you can modify Base. If you can't, you can do this:
public class Derived : Base
{
private Panel _panel;
public Derived() : this(new Panel()) {}
private Derived(Panel panel1) : base(panel1)
{
_panel = panel1;
}
}
You need to define Panel in Base, you can use protected instead of public as well. Read more aboud access speicifiers here
public class Base
{
public Panel panel {get; set;};
public Base(Panel panel1)
{
panel = panel1;
}
}
public class Derived : Base
{
public Derived() : base(new Panel())
{
// this.panel
}
}
public class Base
{
// Protected to ensure that only the derived class can access the _panel attribute
protected Panel _panel;
public Base(Panel panel1)
{
_panel = panel1;
}
}
public class Derived : Base
{
public Derived() : base(new Panel())
{
// refer this way: base.panel
}
}
Further if you want to provide only a get and not a set for the derived classes you can do this:
public class Base
{
// Protected to ensure that only the derived class can access the _panel attribute
private Panel _panel;
public Base(Panel panel1)
{
_panel = panel1;
}
protected Panel Panel
{ get { return _panel; } }
}
public class Derived : Base
{
public Derived() : base(new Panel())
{
// refer this way: base.Panel (can only get)
}
}
Two ways:
public class Derived : Base
{
Panel aPanel;
public Derived() : this(new Panel()) {}
public Derived(Panel panel) : base(aPanel)
{
//Use aPanel Here.
}
}
OR
public class Base
{
protected Panel aPanel;
public Base(Panel panel1)
{
aPanel = panel1
}
}