I have read multiple posts on the subject but still cannot manage to make it work.
I want 2 user controls slidertype1 and slidertype2 which should inherit from slidercommontype, all are in same namespacecommon, can someone knows the syntax for this simple use case ?
Inspiring from http://jamescrisp.org/2008/05/26/wpf-control-inheritance-with-generics/
I tried:
<namespacecommon:slidercommontype x:Class="namespacecommon.slidertype1">
but I got namespacecommon:slidercommontyp doesn't exist in xml namespace.
As long as the base class doesn't have a XAML file associated with it, it's pretty easy. Trying to incorporate the visual aspect of the user control using XAML is not really a supported scenario.
Having said that, just create your class SliderCommonType (although I would call it SliderBase or something.)
namespace MyControls {
public class SliderBase : UserControl {
}
}
Then create your two controls based on it. I'll show one example and the other should be obvious.
<Local:SliderBase x:Class="MyControls.SliderType1"
xmlns:Local="clr-namespace:MyControls">
</Local:SliderBase>
And the code-behind would look like this:
namespace MyControls {
public class SliderType1 : SliderBase {
}
}
The key point being that your XAML file has to reference the base class which requires changing the <UserControl> element to <Local:SliderBase> which in turn requires a XAML namespace import.
When you add a UserControl using the default template, you can just change the code it creates to reflect the above changes. It's much easier than trying to create it from scratch.
One last thing to note - you will need your application to compile successfully before you can use the visual designer on your derived controls. This is because the designer needs to be able to instantiate SliderBase at design-time.
Related
In winform, we can inherit easily. But in WPF, we can't inherit class which contains XAML. So whenever I need to generalize some window's attribute, I create a base class without XAML. For example, I want to make all windows start up at center screen. I use code behind in the base class (this class doesn't contain XAML)
namespace VBDAdvertisement
{
public class BaseWindow:Window
{
public BaseWindow()
{
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
}
}
}
That is just for a simple task. In my opinion, for more complex task, using code behind line by line is not a good idea. So I wonder if there is a better way to inherit window in WPF (something closer to winform inheritance) ?
Since UserControls in WPF have to have parameterless constructors, what is the correct way for supplying them with fairly complex data that is needed "near" the time of construction. I have tried using dependency properties for this, but am running into issues with the Visual Studio designer balking at attempts to pass stuff like a Dictionary<string,MyObject> into an IDictionary<string,MyObject> typed dependency property. At some point it must want an exact compile time type match, or the XAML doesn't come up in the designer, although the application executes just fine.
Basically, I want a good way to pass in stuff that I would normally pass into a constructor into a User Control. What's the best way?
Update:
The user control in question will always be created from XAML, so having a non-parameterless construction in addition to the parameterless one is not an option.
Update 2:
An interesting idea would be to have something accessible from the parameterless constructor that I can get my initialization data from. Something like perhaps asking the question: Which of my already initialized ancestors implements an IMyDataProvider interface? This could be similar to how the relative source to ancestor type bindings work, except done programatically from the user control constructor.
If the only problem you are having is passing in derived types, you can pass in instead a simple concrete container class containing your complex types as properties. For example:
public class InitializationData
{
public IDictionary<TKey, TValue> Dictionary { get; set; }
}
This level of indirection will overcome the limitations of the Visual Studio designer.
A couple of options.
1, You can have more than one constructor, a parameterless one for when your control is created via XAML and another that takes a set of parameters for when you create it directly via code. If you definitely don't want to create your instance via code then...
2, Add a public property that only has a setter and is defined with the exact dictionary type you want to pass in and use as the data for initializing the control. The property only needs to be called once. You can have other properties that are getters/setters that expose that initialized data in order more generic types.
I'm trying to improve on a Winforms project where datatable rows are stored in the Tag property of ListViewItems. When the datatable is refactored to List<T> (or actually classes containing lists) it would help immensely if I could make the Tag property generic by using a subclass of ListView.
In the best of worlds, I'd want the Tag property to be replaced by a public T Tag{get; set;} that wraps base.Tag and casts it.
Second best would be Obsoleting Tag and providing a new property like TypedTag working like above.
I think this would involve subclassing or composite aggregation of at least ListView, ListViewItemCollection, SelectedListViewItemCollection and ListViewItem, and I'm not sure how to do it.
In short:
ListView<Employee> lvwEmployees;
should result in this being possible:
Employee selected = lvwEmployees.SelectedItems[0].TypedTag;
And give a compilation error for this:
DataRow selected = lvwEmployees.SelectedItems[0].TypedTag;
Is it possible? Is it already done?
Project is dotnet 2.0 but I think I'll try to have it upgraded if it helps this matter.
EDIT: It turns out that the owner constructor argument is all a certain collection needs to hook up to the inner collection. Hence the following works:
ListView a = new ListView();
a.Items.Add("Hello");
Assert.AreEqual(1, new ListView.ListViewItemCollection(a).Count);
This makes it rather easy to create a generic tagged ListView. I'll post a complete solution later. :)
EDIT2: Here's the solution:
http://thecarlr.blogspot.com/2010/11/generic-listview.html
EDIT3: For designer support, just add a non generic subclass and use that.
Example: If you intended to use ListView<Employee> in the form, create a ListViewEmployee : ListView<Employee> in another file, and use ListViewEmployee in the form.
The easiest way to add one of theese listviews would be to add a normal listview to the form, and then change it's type in the source files. (And if you don't know where it's declared or instantiated, find out or use the normal listview instead.)
You made the wrong class generic. SelectedItems[0] is a ListViewItem, not a ListView.
There isn't anything you can do to change the type of the Items and SelectedItems properties. You can certainly derive your own class from ListViewItem and just add the property you want to store. No need for another Tag property. You'll have no trouble adding them but you'll need to cast back to your derived class when you retrieve them back from the Selected/Items collection.
In general, avoid this kind of code by using the ListView only as a view of your model. The ListViewItem.Index should then always be good to get a typesafe reference back from your model.
Here's the solution:
http://thecarlr.blogspot.com/2010/11/generic-listview.html
Enjoy :)
/Carl
VS Designer simply cannot handle abstract or generic controls (not for want of asking).
One way around that limitation is to write a type safe wrapper around a standard ListView.
Something like this:
public class TypedListView<T> where T : class
{
public TypedObjectListView(ListView lv) {
this.lv = lv;
}
private ListView lv;
public virtual T SelectedObject {
get { return (T)this.lv.SelectedItems[0].Tag; }
}
// Lots more methods/properties
}
You create a normal ListView in Designer, and then when you wanted to access it, you create and use your adapter instead. Like this:
var typedListView = new TypedListView<Employee>(this.listView1);
Employee selectedEmployee = typedListView.SelectedObject;
You would need to provide a typed version of every ListView properties or method you wanted to use.
The ObjectListView project takes this approach to create a TypedObjectListView which does exactly what are you asking for.
I'm tryihg to bind a combobox item source to a static resource. I'm oversimplfying my example so that it's easy to understand what i'm doing.
So I have created a class
public class A : ObservableCollection<string>
{
public A()
{
IKBDomainContext Context = new IKBDomainContext();
Context.Load(Context.GetIBOptionsQuery("2C6C1Q"), p =>
{
foreach (var item in SkinContext.IKBOptions)
{
this.Add(item);
}
}, null);
}
}
So the class has a constructor that populates itself using a domaincontext that gets data from a persisted database. I'm only doing reads on this list so dont have to worry about persisting back.
in xaml i add a reference to the namespace of this class then I add it as a usercontrol.resources to the page control.
<UserControl.Resources>
<This:A x:Key="A"/>
</UserControl.Resources>
and then i use it this staticresource to bind it to my combobox items source.in reality i have to use a datatemplate to display this object properly but i wont add that here.
<Combobox ItemsSource="{StaticResource A}"/>
Now when I'm in the designer I get the error:
Cannot Create an Instance of "A".
If i compile and run the code, it runs just fine. This seems to only affect the editing of the xaml page.
What am I doing wrong?
When running in the designer the full application runtime is not available. However the designer doesn't just magically know how to mock the UI of a UserControl. Its Xaml is parsed and the objects described there are instantiated.
Its up to you to code your classes to cope with existence in a designer. You can use the static proeprty DesignerProperties.IsInDesignTool to determine if your code is currently being used in a designer tool or not.
If in a designer you could deliver a set of test data rather than attempt to access a data service.
My problem is same as described above and i alse used DesignerProperties.IsInDesignTool
but i can't open usercontrol in visual studio for designing purpose
I have defined a textbox with x:Name="txtMyTextBox" inside UserControl called MyView. I've noticed that I can do the following:
MyView myView = new MyView();
myView.txtMyTextBox.Text = "something";
Why txtMyTextBox is accessible that way? Is it public or internal field? Can I make it private?
The Silverlight XAML designer creates fields for named elements so that you can access them from the code behind. You can see the generated file if you go into the code behind and choose InitializeComponent from the method selection drop down at the top. It's kept in a partial file. In the past, designer generated fields have been scoped as private, but for some reason I cannot fathom, the current crop of XAML designers (VS2010, Blend) creates it as internal.
You can change the visibility of the field that gets generated by using the x:FieldModifier attribute but you probably don't need to worry about it. If you need to, you should expose a public property from your user control that wraps access to it instead.