How to use a RibbonGallery with a RibbonComboBox - wpf

So I wanted to add a RibbonCombobox to my Ribbon in WPF. For some reason, RibbonCombobox does not have a selectionchanged event. I read that you should use a RibbonGallery for selection change event so I implemented this
<RibbonComboBox Label="Equations" x:Name="EquationListComboToolbar" ItemsSource="{Binding}">
<RibbonGallery x:Name="EquationListComboboxGallery" SelectedValue="{Binding XPath=.}" />
</RibbonComboBox>
Behind the scene the binding is done like this.
EquationListComboToolbar.DataContext = ViewModel.EquationNames;
this.Bind(ViewModel, vm => vm.SelectedEquation, v => v.EquationListComboboxGallery.SelectedItem).DisposeWith(cleanup);
Observable.FromEventPattern(EquationListComboboxGallery, nameof(EquationListComboboxGallery.SelectionChanged)).Subscribe(e => ViewModel.SelectEquation(EquationListComboboxGallery.SelectedItem?.ToString()));
At runtime I get the following error
"An unhandled exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll
Items collection must be empty before using ItemsSource." When the app initalizez. I know it's something about the Gallery but I can't figure out what is the problem and how can I achieve this.
As I was suggested, I already tried the answer that was suggested
<RibbonComboBox Label="Equations" x:Name="EquationListComboToolbar" ItemsSource="{Binding}">
<RibbonComboBox.ItemTemplate>
<DataTemplate>
<RibbonGallery x:Name="EquationListComboboxGallery" SelectedValue="{Binding XPath=.}" />
</DataTemplate>
</RibbonComboBox.ItemTemplate>
</RibbonComboBox>
Doing this, will make by binding imposible

Ah, yes. The Microsoft ribbon library is lots of fun. Luckily I've been down this road before. Here's a working example of a RibbonComboBox from one of my applications, complete with RibbonGallery:
<RibbonComboBox DropDownHeight="400">
<RibbonGallery MaxColumnCount="1" ScrollViewer.VerticalScrollBarVisibility="Auto" SelectedItem="{Binding MySelectedItemProperty}">
<RibbonGalleryCategory ItemsSource="{Binding MyItemsSourceProperty}"/>
</RibbonGallery>
</RibbonComboBox>
I'm not entirely sure this is the only way to do things, but I know this way works. Note that I set ItemsSource on the RibbonGalleryCategory, not the RibbonComboBox itself. It might be possible to use the RibbonGallery without a RibbonGalleryCategory, in which case you would set ItemsSource on RibbonGallery, but I've not tested this.
Note you also have the ability to add multiple galleries categories to a single RibbonComboBox like so:
<RibbonComboBox DropDownHeight="400">
<RibbonGallery MaxColumnCount="1" ScrollViewer.VerticalScrollBarVisibility="Auto" SelectedItem="{Binding MySelectedItemProperty}">
<RibbonGalleryCategory ItemsSource="{Binding MyFirstItemsSourceProperty}"/>
<Separator/>
<RibbonGalleryCategory ItemsSource="{Binding MySecondItemsSourceProperty}"/>
</RibbonGallery>
</RibbonComboBox>
The above lets you show multiple lists in the same drop down and allows the user to select a single item from any list. Functionality like this is probably why RibbonGalleryCategory exists in the first place.

Related

Difference between preview and running program

Sorry for my bad headline but I couldn't figure out a better one. Heck, I don't even know how to properly ask my question. But here it comes.
I have a custom control in WPF, let's call it Cell. This control does have a few dependency properties, one Text to show in the Cell and a few "decorative" properties for background color, foreground color and so on. If I use this Cell control stand-alone, everything works fine so far.
Then I have another custom control inheriting from ItemsControl, let's call it Field. This control should show a text and some Cells. it has some "decorative" properties for the text part as well. The information about showing Cells is given to the control by a DataTemplate, something like
<DataTemplate x:Key="CellTemplate"
DataType="...">
<ns:Cell Text="{Binding Text}"
Background="{Binding ...}" />
</DataTemplate>
...
<ns:Field ItemsSource="{Binding Cells}"
ItemTemplate="{StaticResource CellTemplate}" />
If I use this Field control stand-alone, everything works fine so far.
Now I want to show several Field controls at once. So I put an ItemsControl on my window and gave an ItemTemplate again, something like:
<DataTemplate x:Key="CellTemplate"
DataType="...">
<ns:Cell Text="{Binding Text}"
Background="{Binding ...}" />
</DataTemplate>
<DataTemplate x:Key="FieldTemplate"
DataType="...">
<ns:Field ItemsSource="{Binding Cells}"
ItemTemplate="{StaticResource CellTemplate}"
FieldText="{Binding Text}"
TextBackground="{Binding ...}" />
</DataTemplate>
<ItemsControl ItemsSource="{Binding Fields}"
ItemTemplate="{StaticResource FieldTemplate}" />
As long as I preview my WPF window everything works fine so far. Changing the values of some "decorative" properties at Cell level or at Field level is immediately shown in the preview.
But if I run my program it seems that all "decorative" properties at Cell level are ignored. I can see all my Fields with their respective texts and I can see every Cell in every Field with their respective texts. But all Cells are plain white. All set colors are not shown.
Snoop tells me, that every color is set to Transparent by the ParentTemplate.
Visual Studio doesn't show me any exceptions or any binding errors. So I'm kind of stuck at where or how I can find the error and fix it.
So I wanted to ask you, if you may have a hint for me.
Does this contruction with a DataTemplate containing a DataTemplate and both DataTemplates bind to it's DataContext work?
Or does it have something to do with maybe re-using Brush objects that shouldn't be re-used?
But why is it working in the preview?

Automatic template selection in WPF not working with interface

I have a TreeView bound to a list of Tileset. Tileset contains TileGroup, TileGroup contains both Tile and TileRun instances. Both Tile and TileRun implement ITile, but eventually there will be many more types implementing ITile
I have the following XAML:
<TreeView
Grid.Row="0"
Grid.Column="0"
BorderThickness="0"
ItemsSource="{Binding Path=Tilesets}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Tileset}" ItemsSource="{Binding Path=TileGroups}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:TileGroup}" ItemsSource="{Binding Path=Tiles}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type tiles:ITile}">
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
Tileset and TileGroup choose the correct DataTemplate but ITile does not, no template is selected, the tree just displays the data type.
However, if I add a DataTemplate for both Tile and TileRun explicitly, everything works great.I don't want to do that though, as there will eventually be many more classes implementing ITile.
I am aware that I could handle this using a DataTemplateSelector, but I'd like a pure XAML solution if possible.
Am I doing something wrong here, or does WPF just not support this type of automatic template selection based on interfaces?
Am I doing something wrong here, or does WPF just not support this type of automatic template selection based on interfaces?
You are not doing something wrong. This kind of data binding support for interfaces is simply not supported. Please refer to Beatriz Costa's (MSFT) answer in the following thread on the MSDN forums for more information about why.
Data templates and interfaces: https://social.msdn.microsoft.com/Forums/vstudio/en-US/1e774a24-0deb-4acd-a719-32abd847041d/data-templates-and-interfaces?forum=wpf
"The data binding team discussed adding support for interfaces a while ago but ended up not implementing it because we could not come up with a good design for it. The problem was that interfaces don't have a hierarchy like object types do. Consider the scenario where your data source implements both IMyInterface1 and IMyInterface2 and you have DataTemplates for both of those interfaces in the resources: which DataTemplate do you think we should pick up?
When doing implicit data templating for object types, we first try to find a DataTemplate for the exact type, then for its parent, grandparent and so on. There is very well defined order of types for us to apply. When we talked about adding support for interfaces, we considered using reflection to find out all interfaces and adding them to the end of the list of types. The problem we encountered was defining the order of the interfaces when the type implements multiple interfaces."
So you will either have to define a DataTemplate for both Tile and TileRun explicitly or use a DataTemplateSelector.

How to bind to multiple sources without codebehind or using SelectedValue

While trying to convert usual wpf fields to the custom fields that the program I need to modify, I came across an issue of having 2 different data sources.
1) The data source that retrieves/inserts data to fill this combobox (DataSource)
2) The data source that takes care of other UI elements (DSP)
As when certain items are selected from the combobox, not only does it get stored with the other information in the form, but it may show/hide another UI element.
I am trying to convert:
<ComboBox Name="tempComboBox"
ItemsSource="{Binding Source={StaticResource DataSource}, Path=Value.Properties[temp].MetaData.Lookups}"
DisplayMemberPath="Description"
SelectedValuePath="Value"
SelectedValue="{Binding Source={StaticResource DSP}, Path=Value, ValidatesOnDataErrors=True}"
Style="{StaticResource tempComboStyle}"/>
Into something like this:
<ctrls:Fields Name="tempComboBox"
FieldName="temp"
DataContext="{Binding Source={StaticResource DataSource}, Path=Value, ValidatesOnDataErrors=True}"
Style="{StaticResource tempComboStyle}"/>
However, this WILL NOT work as it only stores the data, but does not hide/show elements when the specific item is selected.
I have tried multi binding, which does not work. Surrounding the combobox tags with the ctrls:Fields tag, again doesn't work. And combining the DataContext property with both SelectedValue and ItemSource, none of which work.
I do not have any way of getting to the code behind of this form either, it must be strictly done through XAML.
Thank you for any help!

Bind to selected rows in GridControl

I would like to get a list of the objects selected in GridControl (DevExpress)
Would you know how I could do so?
<dxg:GridControl ItemsSource="{Binding Cars}">
Found the way to do this.
Way 1
If having DevExpress 15.5 (which I don't), simply use the SelectedItem property: https://documentation.devexpress.com/#WPF/DevExpressXpfGridDataControlBase_SelectedItemstopic
Way 2
Create a behavior to hook the TableView inside the GridControl if you have:
<dxg:GridControl ItemsSource="{Binding Cars}">
<dxg:GridControl.View>
<Controls:TableView >
<i:Interaction.Behaviors>
<view:CollectionObserverBehavior SelectedItems="{Binding SelectedCars}" />
</i:Interaction.Behaviors>
</Controls:TableView>
Behavior details in the good article here: http://social.technet.microsoft.com/wiki/contents/articles/22871.wpfmvvm-binding-to-read-only-properties-using-behaviors.aspx

Best way to create a list of selectable and deletable items in Windows Phone 7

I want to solve a seemingly simple task. I want to create a list of text entries where each entry is selectable (and causes navigation to another page) and when the user holds his finger over an item I want a context menu with a single option to delete that item. This is very common pattern in WP applications. For example the browser does this with favourites.
Right now I have a listbox with a textblock in the item template and I start the navigation in the SelectionChanged event:
<ListBox Name="lbSnippets" SelectionChanged="lbSnippets_SelectionChanged">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"></TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
I can think of several ways to solve the hold problem but none of them sits well with me. For example I may handle the Hold event on the TextBlock but then I will have to dig for the item related to this TextBlock. Something tells me that there should be a better way to do this as it is so common. What is the right way to solve this task?
The Silverlight toolkit for WP7 includes a ContextMenu control.
You can install the toolkit via nuget: PM> Install-Package SilverlightToolkitWP
Then you an add ContextMenus to basically any control:
<DataTemplate>
<TextBlock Text="{Binding}">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="Delete"
Command="{Binding YourDeleteCommand}"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</TextBlock>
</DataTemplate>
Where toolkit is an xml namespace:
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
You can start learning about the ContextMenu control from this article:
WP7 ContextMenu in depth | Part1: key concepts and API

Resources