How do I make user controls for both ListView and ListViewItem work with each other? - wpf

I have all the styling, triggers, etc. down for ListView and ListViewItem, and I want to turn them into user controls. How do I make sure that these two "match up" with each other, so that MyListView accepts MyListViewItems as content? Also, considering that I must end the ListView tag by the end of the user control XAML file, I am not sure how I would add items to it.

If you want them to be reusable with different data sets, especially through binding, you should stay away from UserControls and just make custom controls derived from the original types. In that case you create a standalone MyListView.cs and MyListViewItem.cs and all of the XAML for the controls goes into default Styles (usually also containing a ControlTemplate) in Themes/Generic.xaml. You can see an example of this setup by just adding a WPF Custom Control to your WPF project from Add New Item.
Once you've created the .cs files for your custom controls you just need to override a few methods from the base ItemsControl to use MyListViewItem as the item container control. The ListView would end up like this:
public class MyListView : ListView
{
static MyListView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyListView), new FrameworkPropertyMetadata(typeof(MyListView)));
}
protected override DependencyObject GetContainerForItemOverride()
{
return new MyListViewItem();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is MyListViewItem;
}
}
You can now use your custom MyListView exactly as you would a normal ListView, including binding to ItemsSource.

Inheritance should take care of that for you. In other words, if you have two user controls, the first one with a basic element of ListView (not UserControl) and the other of ListViewItem (again, not UserControl), and you make sure they extend ListView and ListViewItem respectively in the .cs code, the following should work equally:
ListView lv = new ListView();
lv.Items.Add(new ListViewItem());
or
MyListView mlv = new MyListView();
mlv.Items.Add(new myListViewItem()); //If your myListView extends ListView, and myListViewItem extends ListViewItem in your user control files, of course
In case you are looking for a XAML solution, you should import your namespace at the top
xmlns:myControls="WhateverYourNamespaceAndAssemblyAre"
and on you page/window/whatever
<myControls:myListView>
<myControls:myListViewItem/>
<myControls:myListViewItem/>
</myControls:myListView>

Related

XAML control to inherit from templates

What controls are there to inherit from that has the property of Children and supports templating when building a custom usercontrol.
Currently I know about Panel, but it does not support properties and methods like DefaultStyleKey and GetTemplateChild();
Is there an interface that I can inherit from for templates such as:
public class Scroller : Panel, ITemplates //Something like ITemplates
{
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
container = GetTemplateChild("container") as StackPanel; //I want to be able to do this
this.Children; //And also be able to use this
}
}
You want ItemsControl. It has an Items property and its template is very flexible as demonstrated by the fact that TabControl, ListBox, ComboBox, etc all derive from it.

Getting WPF Templated items from Control and Data templates

How do I get a named control from a control that is bound to a control template or data template?
I have tried FindName it does not work.
I prefer not to use the VisualTreeHelper as you have to traverse through each parent child item individually.
It depends when you do it. If you do it in the constructor it wont work as the element only exists after the template has been applied.
This is the standard way to do it if you create the control:
public override void OnApplyTemplate() {
//i call the base first
base.OnApplyTemplate();
//then go looking for the newly created elements
TextBox textBox = this.Template.FindName("PART_TextBox", this) as TextBox;
}

How can I determine the type of the items that get added to a TabControl?

I've created a CloseableTabItem control that derives from TabItem.
Now I'd like to specify that a given TabControl should add new items using CloseableTabItem instead of TabItem.
Is this possible? How?
public class CloseableItemsTabControl : TabControl
{
protected override DependencyObject GetContainerForItemOverride()
{
return new CloseableTabItem();
}
}
You'll probably need to make your own ClosableTabControl that extends TabControl in order to override the base functionality.
However, you can also probably just add your tabs manually, feeding it your ClosableTabItems instead of regular TabItems. It would be safe to assume this is possible since most collection-based controls are able to be programatically populated this way.

In WPF, is it possible to have a combo box control, that looks like a RadioButton?

I have a whole bunch of code that is dependent on the ComboBox type, and I want to be able to use it on a new UI, but the UI that I want to use it for needs to look like a RadioButton for usability reasons. Is it possible to have a ComboBox control look like a set of RadioButtons?
My suggestion would be to use an ItemsControl with a DataTemplate that would render RadioButtons. To the ItemsControl you'd bind the same thing you're binding to the ComboBox.
One caveat is that you need to set the GroupName of the radio buttons to something that would be the same to the group, so they can be mutually exclusive. Otherwise, if you don't do anything, you'll be able to select more than one RadioButton simultaneously.
You could build a new UserControl that has many of the same methods that the ComboBox class does, but adapt it so that it creates multiple radio boxes instead.
Your question is kinda vague though.
IE create an Items collection on your user control, and when something is added, draw a radio box and resize your control, instead of what a combo box does and just adds a string to the list.
Then all you have to do is find and replace all your references to ComboBox with RadioIFiedComboBox.
Heres some comparison:
ComboBox cb = new ComboBox();
cb.Items.Add("blah");
or
RadioIFiedComboBox cb = new RadioIFiedComboBox();
cb.Items.Add("blah");
and
public class RadioIFiedComboBox : UserControl {
public ObservableCollection<object> Items = new ObservableCollection<object>();
public RadioIFiedComboBox() {
Items.CollectionChanged += new NotifyCollectionChangedEventHandler(YourCollectionChanged);
}
private void YourCollectionChanged(){
//do something here to redraw your controls
}
}
The code above is just an example, you'd have to create all the methods you use in the ComboBox class and create similar functionality.

Is there a way to logically group controls in WPF

Here's the scenario
I have a Grid with some TextBlock controls, each in a separate cell in the grid. Logically I want to be able to set the Visibility on them bound to a property in my ViewModel. But since they're each in a separate cell in the grid, I have to set each TextBlock's Visibility property.
Is there a way of having a non-visual group on which I can set common properties of its children? Or am I dreaming?
There is no non-visual group that would make this possible.
Setting the Visibility properties, directly or in a common Style shared by all of the TextBlocks, is probably the simplest solution.
Another option is to bind the visibility property of each item in your group of items to one single item, that way in your code behind you are only ever having to set the visibility of one item.
If possible I mostly place them in a GroupBox and set the groupbox BorderThickness to 0. That way all controls are grouped, you don't see that it's a groupbox and you can set the visibility with one property..
<Style TargetType="{x:Type GroupBox}"
x:Key="HiddenGroupBox">
<Setter Property="BorderThickness"
Value="0" />
I hope you have defined all of your cell UI elements inside a DataTemplate. You can do a small trick at the ViewModel level to achieve what you are looking for.
Have Singleton class at the ViewModel, which should have the Visibility or an equivalent property which you wanted to bind to every TextBlock.
The Singleton class should implement INotifypropertyChanged to get the change notification to the UI
Bind the Singleton property in the XAML and control this property from anywhere in your application.
< TextBlock Visibility="{Binding Source={x:Static local:Singleton.Instance},Path=Visibility}"
And a simple Singleton class can be implemented as
public class Singleton :INotifyPropertyChanged
{
private Singleton() { }
public static Singleton Instance
{
get
{
if (instance == null){ instance = new Singleton(); }
return instance;
}
}
private Visibility _visibility;
public Visibility Visibility
{
get { return _visibility; }
set
{
_visibility = value;
PropertyChanged( this, new PropertyChangedEventArgs("Visibility") );
}
}
public event PropertyChangedEventHandler PropertyChanged;
private static Singleton instance;
}
Now you can control Singleton.Instance.Visibility = Visibility.Collapsed anywhere from your code behind
It may be possible to make a custom control that redirects all its add/remove children methods to its own parent, while still keeping a record of its contents so it can apply its own property styles. Would be tricky though.
I realise that this a very ancient question, but there will no doubt people finding this thread after searching for something related. Therefore I offer the following very simple solution:
Place all of the controls in question into a new grid that sits within the existing grid; spans the appropriate cells and replicates them within it's own structure. Then you can change the visibility of the new grid, and with it the controls inside.

Resources