I've ran into an issue I'm hoping someone can help me solve. I've run into a case where my nodes contain a set of child nodes with visibility set to false. I'm hoping that I can disable the toggle arrow beside the TreeViewItem if all it's children are invisibile. Is this possible? Here's an example:
<TreeView Margin="10,10,0,13" Name="TreeView1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="194" Height="200">
<TreeViewItem Header="Cold Drinks">
<TreeViewItem Header="Coke" Visibility="False"></TreeViewItem>
<TreeViewItem Header="Pepsi" Visibility="False"></TreeViewItem>
</TreeViewItem>
</TreeView>
How would i get the Cold Drinks TreeViewItem to hide the toggle arrow?
If you see the deafult controlTemplate of TreeViewItem, you will see that visibility of Toggle button is bound to ItemsControl.HasItems. Trigger look like this -
<Trigger Property="ItemsControl.HasItems">
<Setter TargetName="Expander" Property="UIElement.Visibility" Value="{x:Static Visibility.Hidden}" />
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
So, as a workaround, you can create your own Custom Control derived from TabItem and bind your HasItems with your own CLR property which will loop through all your childItems(TreeViewItems) and will return True if any of the Item is visible or False if all items are hidden/collapsed state. That way your toggle button will automatically will hide as per Trigger.
In case you want to know how to create Custom control and bind it to your CLR property, you can refer to this -
WPF TreeView databinding to hide/show expand/collapse icon
This is somewhat same what you has been looking for. Hope this helps..
Both internally (i.e. for keyboard navigation) and in its default template the TreeViewItem is relying on its HasItems property to know if it has children or not. You will likely need to set the ItemsSource of the TreeViewItem to a list and filter out the collapsed items.
Related
I need a control which extremelly looks like combobox from win run window.
My question is is it a standart combobox control with specific settings or I have to create a custom control in order to achieve this appearance and behavior ?
I'm interested in appearance and behaviour next to the third image - like filtered suggestions which shown as listbox in a popup after pressing a key.
standart combobox
combobox open
the most interresting - like filtered suggestions
UPDATED!
Is it a standard combobox control ?
As you can see in the attached gif below when I start inputting something combobox looks like a textbox with popup window under it which contains filtered items. Like a sort of mix between textbox, combobox and popup window with listbox
This is already built into the ComboBox. Here is an example:
<ComboBox
IsEditable="True" //This enables to enter values that don't belong to the ItemsSource collection
IsTextSearchEnabled="True" //this allows you to have "suggestions" when you enter text
IsTextSearchCaseSensitive="False"
StaysOpenOnEdit="True"
Text="{Binding NameOnViewModel}"
TextSearch.TextPath="NameOnChildItems" //this is the property on which combobox will filter the items
ItemsSource="{Binding Items}" //collection of your items to search on
ItemTemplate="{StaticResource DataTemplate}" />//this can be replaced with DisplayMemeberPath="PropertyName"
Note:
This example was taken from this SO post.
EDIT
In case you want the popup to open when you are typing in the values then this could be of help:
</ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">//you can also use a different event if this one doesn't suit your needs.
<Setter Property="IsDropDownOpen" Value="true" />
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
EDIT 2
For filtering of the VISIBLE objects in the drop down list of your combobox then use the key down event and filter it in the event handler like so:
private void cmbKeyDown(object sender, KeyEventArgs e)
{
string temp = ((ComboBox)sender).Text;
var newList = MyList.Where(x => x.Name.Contains(temp));
MyList = newList.ToList();
}
I want use a scrollbar like ComboBox in my DropDown button, the structure actually is this:
<Controls:DropDownButton Content="Nazioni" Width="120" Margin="0, 0, 20, 0"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.CanContentScroll="True"
ItemsSource="{Binding Countries}"
ItemTemplate="{StaticResource CombinedTemplate}"/>
but I don't see any ScrollViewer as you can see in the image below:
The drop-down of the DropDownButton already contains a ScrollViewer (it is named "SubMenuScrollViewer"), so scrolling through its items is supported out-of-the-box. The thing is, that particular ScrollViewer is styled differently than a default ScrollViewer - assuming we're talking about vertical scrolling, it has two buttons above and below the list, responsible for scrolling up and down respectively, as shown below:
So your best bet is to make that particular ScrollViewer use the default style rather than a custom one. By inspecting the MahApps.Metro source code we can see that the ScrollViewer in question is wired to use a dynamic resource with a key value of {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}. So what you need to do is to supply a default style with that key for that control:
<Controls:DropDownButton (...)>
<Controls:DropDownButton.Resources>
<Style x:Key="{ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}"
TargetType="{x:Type ScrollViewer}"
BasedOn="{StaticResource {x:Type ScrollViewer}}" />
</Controls.DropDownButton.Resources>
</Controls.DropDownButton>
This way the ScrollViewer within the drop-down will be styled with a default style shipped with MahApps.Metro.
To be certain that scrolling will behave as expected, you cannot rely on WPF to place a ScrollViewer where it should be.
As any content can be place on the dropdown, your best option is to drop a ScrollViewer straight onto the component.
This way, you can explicitly name it, and have access to its properties.
If you bind your list of countries to the lstContent box, you do away with all the messing.
<extToolkit:DropDownButton Content="Click Me" Margin="15" >
<extToolkit:DropDownButton.DropDownContent>
<ScrollViewer>
<ListBox Name="lstContent" ItemsSource="{Binding Countries}" ItemTemplate="{StaticResource CombinedTemplate}"/>
</ScrollViewer>
</extToolkit:DropDownButton.DropDownContent>
</extToolkit:DropDownButton>
I have a DataTemplate which contains a TextBox. The DataTemplate is bound to the ContentTemplate property of a Style for the DevExpress FlyoutControl. The Flyout Control itself is within the ControlTemplate of another TextBox.
When the TextBox with the FlyoutControl is focused, I want to redirect focus to the first TextBox in the FlyoutControl's ContentTemplate (from the DataTemplate). Setting FocusManager.FocusedElement={Binding RelativeSource={RelativeSource Self}} on the TextBox I want focused accomplishes this the first time, but once the Flyout has loaded it no longer works.
I have tried every suggestion I can find and nothing so far has worked. I can get the TextBox I want to reference in code and call Focus(), but it always returns false. At best, when I try to focus it in code, the Flyout is focused instead, but never the TextBox within the Flyout.
Here is what each relevant part looks like (irrelevant code omitted):
<DataTemplate x:Key="FlyoutTemplate">
<Grid>
<dxe:TextEdit x:Name="TextThatWantsFocus"
FocusManager.FocusedElement={Binding RelativeSource={RelativeSource Self}}" />
</Grid>
</DataTemplate>
...
<Style x:Key="FlyoutStyle" TargetType="dxe:FlyoutControl">
<Setter Property="ContentTemplate" Value="{StaticResource FlyoutTemplate}"/>
</Style>
...
<dxe:TextEdit>
<dxe:TextEdit.Template>
<ControlTemplate>
<StackPanel>
<dxe:TextEdit x:Name="InnerTextEdit" />
<dxe:FlyoutControl Style="{StaticResource FlyoutStyle}"/>
</StackPanel>
</ControlTemplate>
</dxe:TextEdit.Template>
</dxe:TextEdit>
The flyout is being opened in code. It is here that I also would like to focus the TextBox (TextThatWantsFocus). However, nothing I have tried will give it focus (except for FocusManager handling it the first time), including the typical SO answer involving triggers. Any ideas would be greatly appreciated.
I took DmitryG's advice and submitted a DevExpress support ticket, and they were able to provide a solution.
The issue was resolved by handling the Loaded event of the TextEdit I want focused and using the dispatcher to focus it:
private void TextThatWantsFocus_Loaded(object obj, RoutedEventArgs e)
{
var text = obj as FrameworkElement;
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(delegate()
{ text.Focus(); }));
}
I suggest you using the FocusBehavior from DevExpress MVVM Framework:
<DataTemplate x:Key="FlyoutTemplate">
<Grid>
<dxe:TextEdit>
<dxmvvm:Interaction.Behaviors>
<local:FocusBehavior/>
</dxmvvm:Interaction.Behaviors>
</dxe:TextEdit>
</Grid>
</DataTemplate>
I'm starting a new project in WPF and am now looking into using Prism. For now I'm simply trying to set up the navigation of the application using Prism. Unfortunately, my lack of experience with the framework makes it a bit difficult to get started.
To be more precise about my first challenge I have an application with a "navigation/menu" region and a "main" region.
In "navigation/menu" region, I have several checkboxes, in this case we have four of them, which represents a sequential navigation. I.E. we've selected View 2 and View 4.
So, when the user click Start, in "main" region must appear each view selected in that order. Check the below image, View 2 is first. Then when the user press next, must show View 4.
I mean on a more structural level..
if I could only get through the first steps..
Prism support TabControl Region Adapter, navigation can be done using standard requestNavigation method.
You need add all your tab content using Region.Add method to the region in your module's init phase.
view:
<TabControl prism:RegionManger.RegionName="tabRegion" />
C# code:
IRegionManager manager;
manager.Regions["tabRegion"].Views.Add(Container.Resolve(typeof(YourViewType)));
In your viewModel, you should write you navigation command:
public void NextView() {
regionManager.RequestNavigation("tabRegion", new Uri("YourViewType", UriKind.Relative));
}
bind to your "next" button:
<Button Command="{Binding NextViewCommand}" />
If you want to control whether user can navigate to next page, you can implement INavigationAware interface.
If you don't want lost data between navigation, you can make your view model has ContainerMangedLifeCycle or implement IsNavigationTarget method to return true.
Sorry for untested code sample, but you should get the point.
Create a class named ViewVM with a property IsSelected. Must implement INotifyPropertyChanged.
Add an ObservableCollection<View> named Views to your datacontext. Populate it with new instances of ViewVM.
Put an ItemsControl in your Window, with ItemsSource set to Views. The DataTemplate for the ItemsControl items should contain a CheckBox (with IsChecked bound to IsSelected) and a Label.
Add a TabControl to your Window, with ItemSource set to Views. Add a Style for TabItem such that TabItems are only visible if IsSelected is true.
Following the above steps will give you a window containing a list of views with checkboxes, as you requested, and a TabControl displaying only the selected views. Below is the XAML (I have tested this):
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=Views}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsSelected}"></CheckBox>
<TextBlock Text="{Binding Path=Title}"></TextBlock>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TabControl ItemsSource="{Binding Path=Views}">
<TabControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Path=Title}"></TextBlock>
</Grid>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.Resources>
<Style TargetType="TabItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected}" Value="False">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TabControl.Resources>
</TabControl>
</StackPanel>
This addresses the structural/design aspect and should give you a good start to creating your solution - you'll also need to create a custom control to use instead of the TabControl. Instead of having tabs, your custom control should contain Next and Previous buttons to navigate between views.
when I remove an item that is currently selected from the TreeView automatically the parent gets selected. I would like to change this behavior so the previous or the next child gets selected. I really don't know where to start ...
Any idea on how to accomplish this would be great!
Thanks.
You can set the SelectedItem by introducing a property such as IsSelected in your tree view node's datacontext class or model.
Assuming that you are binding a hierarchy of TreeViewItemModel class to the TreeView, you need to do the following
Add writeable IsSelected propertyb in TreeViewItemModel. Remember to raise property changed notification in the Setter of IsSelected.
Introduce this in the TreeView resources ...
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</TreeView.Resources>
After you delete a node, set the next or previous tree view child's TreeViewItemModel objects IsSelected as true.
Let me know if this helps.
TreeView has Items property, which is of type ItemCollection. This type has some good events, like CollectionChanged or CurrentChanged. may be you should to spade this way?