RibbonGroupsPanel ... accepts only IProvideStarLayoutInfo instances? - wpf

I am trying to use a RibbonGallery in my application, but I get this error at runtime, when the tab which contains the gallery is loaded:
"RibbonGroupsPanel RegisterStarLayoutProvider and
UnregisterStarLayoutProvider accepts only IProvideStarLayoutInfo
instances. Parameter name: starLayoutInfoProvider"
Any idea what isn't right?
Here's the code:
<ribbon:RibbonGallery MaxColumnCount="1">
<ribbon:RibbonGalleryCategory>
<ribbon:RibbonGalleryItem Content="Green" Foreground="Green" />
<ribbon:RibbonGalleryItem Content="Blue" Foreground="Blue" />
<ribbon:RibbonGalleryItem Content="Orange" Foreground="Orange" />
</ribbon:RibbonGalleryCategory>
</ribbon:RibbonGallery>

The RibbonGallery control must be placed within a control that can take advantage of the RibbonGallery, like a RibbonSplitButton or a RibbonComboBox. Here is an example of using a gallery in a RibbonComboBox:
<ribbon:RibbonComboBox Label="1"
SmallImageSource="Images/RightArrowShort_Green16.png"
SelectionBoxWidth="62"
VerticalAlignment="Center"
IsEditable="True" >
<ribbon:RibbonGallery SelectedValue="Green"
SelectedValuePath="Content"
MaxColumnCount="1">
<ribbon:RibbonGalleryCategory>
<ribbon:RibbonGalleryItem Content="Green" Foreground="Green" />
<ribbon:RibbonGalleryItem Content="Blue" Foreground="Blue" />
<ribbon:RibbonGalleryItem Content="Orange" Foreground="Orange" />
</ribbon:RibbonGalleryCategory>
</ribbon:RibbonGallery>
</ribbon:RibbonComboBox>
XAML copied from http://msdn.microsoft.com/en-us/library/microsoft.windows.controls.ribbon.ribbongallery.aspx.
If a control is derived from RibbonMenuButton then it can contain a RibbonGallery because of the HasRibbon property.

The RibbonMenuItemsPanel-class of the System.Windows.Controls.Ribbon.Primitives allows to place a RibbonGallery in a RibbonGroup. This class implements the ISupportStarLayout-interface.
Define the primitives-Namespace in the Window-element (could also be RibbonWindow):
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell"
xmlns:primitives="clr-namespace:System.Windows.Controls.Ribbon.Primitives;assembly=System.Windows.Controls.Ribbon"
... >
The RibbonGroup-part:
<RibbonGroup Header="MyRibbonGroup">
<primitives:RibbonMenuItemsPanel Margin="0,3,0,0">
<RibbonGallery ...>
<RibbonGalleryCategory ...>
...
</RibbonGalleryCategory>
</RibbonGallery>
</primitives:RibbonMenuItemsPanel>
</RibbonGroup>
Note that i use the System.Windows.Controls.Ribbon-namespace (.Net 4.5) and not the Microsoft.Windows.Controls.Ribbon-namespace. But this should be nearly the same.

I don't see any RibbonGroupsPanel in your xaml which leads me to thinking that you're not showing all of the relevant xaml.
In any case, it tells you that you're putting the wrong element inside RibbonGroupsPanel.RegisterStarLayoutProvider and that it accepts only types that implements IProvideStarLayoutInfo .

Related

WPF Visibility Resource with Binding

I got a WPF Application using MVVM Light. In one View i got many Controls which are using the same visibility binding. Because i dont like to insert my long binding path to every control. I'd like to use a Resource...
<SomeControl>
<SomeControl.Resource>
<Visibility x:Key="myVisibilityResource" >
<Binding Path="somePath" Converter="BoolToVisibilityConverter"></Binding>
</Visibility>
</SomeControl.Resource>
<SomeControl>
With this version i get the Error that Visibility does not support direct content. I would have to write it like this:
<Visibility x:Key="myVisibilityResource" >
Collapsed
</Visibility>
Any ideas?
If all you want is to be able to write "Visible" or "Collapsed" in your XAML (as in your last example) you can do it by binding to and ObjectDataProvider which is uses Enum.Parse to parse the given text (which can be "Visible", "Collapsed", or "Hidden"):
<Grid xmlns:sys="clr-namespace:System;assembly=mscorlib" >
<Grid.Resources>
<ObjectDataProvider x:Key="visibilityProvider"
MethodName="Parse"
ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="Visibility" />
<sys:String>Visible</sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Grid.Resources>
<Button x:Name="button1" Visibility="{Binding Source={StaticResource visibilityProvider}}" />
</Grid>
In the above code I am using an ObjectDataProvider to return a Visibility enumeration. The ObjectDataProvider calls Enum.Parse when binding. The button's Visibility property binds to the ObjectDataProvider.
The MethodParameters property specifies the parameters for Enum.Parse.
Unfortunately there is no way to bind MethodParameters directly to an underlying ViewModel. If you want to do this, I guess you could write your own ObjectDataProvider or you could use your own class/method instead of Enum.Parse which returns the correct Visibility value.
Create a style in resources:
<Style TargetType="Control" x:Key="VisibilityStyle">
<Setter Property="Visibility"
Value="{Binding Converter={StaticResource VisibleIfFalse}}"/>
</Style>
Then simply add the reference to the item to hide/show.
<TextBlock Text="123" Style="{StaticResource VisibilityStyle}"/>
<TextBlock Text="123" Style="{StaticResource VisibilityStyle}"/>
<TextBlock Text="123" Style="{StaticResource VisibilityStyle}"/>
<TextBlock Text="123" Style="{StaticResource VisibilityStyle}"/>
This also works for headers of grids...
How about something like this? It's not exactly what you asked for, but you would be copying less code around since you wouldn't have to include the converter every time.
<UserControl>
<Grid>
<SomeElement x:Name="Master" Visibility="{Binding somePath, Converter={StaticResource BoolToVisibilityConverter}}" />
<SomeOtherElement Visibility="{Binding Visibility, ElementName=Master}" />
<SomeOtherElement Visibility="{Binding Visibility, ElementName=Master}" />
</Grid>
</UserControl>

WPF UserControl or ControlTemplate... (not sure)

I have a listbox where I have to add about 20 static custom items. All the items are based on the same template (something like that) :
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="" Height="30" />
<TextBlock Text="" VerticalAlignment="Center" />
</StackPanel>
</Border>
I don't want to repeat that 20 times in the ListBox.Items I would like to have some kind of UserControl where I could do something Like the following where I could set some custom properties :
<ListBox>
<ListBox.Items>
<MyListBoxTemplate x:Name="Item1" ItemText="Item #1" ItemImageSource="/Image1.jpg" />
<MyListBoxTemplate x:Name="Item2" ItemText="Item #2" ItemImageSource="/Image2.jpg" />
...
</ListBox.Items>
</ListBox>
But I don't wan't to create a userControl just for that!!! Is there an easy way to put that template in the Window.Resources?
Thanks
If you are ONLY using it for that SPECIFIC listbox, you can just assign the ItemTemplate property. This will need to work in conjunction with a collection of custom objects defined in your resources somewhere else. This will save you from creating a custom UserControl, but you will need an object that can be defined in XAML and a list of them in XAML anyway. To be honest, creating a UserControl is relatively painless and may be easier, but it is possible without doing so.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate TargetType="CustomObjectType">
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" Height="30" />
<TextBlock Text="{Binding TextContent}" VerticalAlignment="Center" />
</StackPanel>
</Border>
<DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
EDIT: If you are going to use it in more than one place, put the DataTemplate in your Application resources and ive it a key, then assign the ItemTemplate property to {StaticResource MyListBoxItemsTemplateKey}
Not my favorite approach since it uses the XmlDataProvider and XPath syntax (which I tend to always forget). But you can embed your static data as xml within your Window.Resources like so:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<XmlDataProvider x:Key="MyStaticData" XPath="StaticItems" >
<x:XData>
<StaticItems xmlns="">
<StaticItem>
<ItemText>Item #1</ItemText>
<ItemImageSource>/Image1.jpg</ItemImageSource>
</StaticItem>
<StaticItem>
<ItemText>Item #2</ItemText>
<ItemImageSource>/Image2.jpg</ItemImageSource>
</StaticItem>
</StaticItems>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<Grid>
<ListBox>
<ListBox.ItemsSource>
<Binding Source="{StaticResource MyStaticData}" XPath="StaticItem" />
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding XPath=ItemImageSource}" Height="30" />
<TextBlock Text="{Binding XPath=ItemText}" VerticalAlignment="Center" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Then within your ListBox bind to the XmlDataProvider you specified and use the XPath notation within the bindings to drill down to the data you want the controls to bind to.
This site has a couple good examples too:
http://vbcity.com/blogs/xtab/archive/2010/12/24/more-xpath-examples-in-a-wpf-application.aspx
Hope this helps!

Binding properties through DataTemplates and ContentControl

I liked this answer, and it almost fit me.
But, how can I achieve this if my DataTemplate is in a external ResourceDictionary?
I'm using Prism and I provide the DataTemplates (for generic CRUD views) by each module, by using files like this:
<ResourceDictionary ... some hidden ns here ... >
<DataTemplate DataType="{x:Type model:Operation}">
<vw:OperationView />
</DataTemplate>
<DataTemplate DataType="{x:Type model:Customer}">
<vw:CustomerView />
</DataTemplate>
</ResourceDictionary>
Then I use this answer to merge the ResourceDictionaries into the Shell app and I have a default CRUD view which has that code:
<ContentControl Content="{Binding MyGenericObject}" />
That ContentControl automatically pull the correct view. It's working fine, but I want to know bind the property of the objects in each view.
That's a sample of these views (OperationView.xaml):
<UserControl x:Class="TryERP2.Cadastro.View.OperationView"
... some hidden NS ... >
<StackPanel>
<Label Content="Id" />
<TextBox Text="{Binding ????WHAT????}" />
<Label Content="Description" />
<TextBox Text="{Binding ????WHAT????}" />
</StackPanel>
</UserControl>
How can I bind these properties?
Since the DataContext behind OperationView will be an object of type Operation, then you simply bind to whatever property on Operation you want
<!-- DataContext will be model:Operation per your DataTemplate -->
<UserControl x:Class="TryERP2.Cadastro.View.OperationView"
... some hidden NS ... >
<StackPanel>
<Label Content="Id" />
<TextBox Text="{Binding Id}" />
<Label Content="Description" />
<TextBox Text="{Binding Description}" />
</StackPanel>
</UserControl>
The DataContext in the UserControl is your model object, so you can directly bind to its properties like this:
Text="{Binding SomeProperty}"
(If only a path is specified the binding is relative to the DataContext, note that in the answer you linked the intention was to have a TwoWay binding on the DataContext itself which was a primitive string, this cannot be done using a simple binding like {Binding .}, a property path targeting an actual property needs to be specified)

Focus and TabIndex on UserControls

I have a strange behaviour:
I have a MainWindow containing textboxes and (simple) usercontrols (textbox and button), but I stripped this to only a textbox for debug purposes.
When I use textboxes and usercontrols WITHOUT setting a TabIndex property the cursor steps through the controls in right order (in the order the controls are added to the window)
When I use textboxes and usercontrols WITH setting a TabIndex property the cursor steps through the controls in invalid order (first all usercontrols, then all textboxes), this is also true when the TabIndex is set to value corresponding to the order in which the control was added
Here is my usercontrol
<UserControl x:Class="SmallControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
>
<TextBox x:Name="txTEXT" Text="{Binding Text}" />
</UserControl>
The following Mainwindow xaml leads to order 000000,111111,222222,333333 ,thats ok
<GroupBox Header="Small,Textbox,Small,TextBox without TabIndex">
<UniformGrid Columns="4">
<local:SmallControl Text="000000" />
<TextBox Text="111111" />
<local:SmallControl Text="222222" />
<TextBox Text="333333" />
</UniformGrid>
</GroupBox>
The following Mainwindow xaml leads to order 000000,222222,111111,333333, thats NOT ok
<GroupBox Header="Small,Textbox,Small,TextBox with TabIndex">
<UniformGrid Columns="4">
<local:SmallControl TabIndex="0" Text="000000" />
<TextBox TabIndex="1" Text="111111" />
<local:SmallControl TabIndex="2" Text="222222" />
<TextBox TabIndex="3" Text="333333" />
</UniformGrid>
</GroupBox>
Is there a way to use TabIndex without beeing forced to add controls in the "right" order in XAML?
By default, WPF reads all the controls, both inside and outside UserControls, at the same tab level (unless specified otherwise). Since the controls inside the UserControl do not have a TabIndex specified, they get tabbed to last after the first tab cycle.
To change this behavior I usually set IsTabStop="False" on my UserControl definition, then I bind the inner controls TabIndex to the UserControl's TabIndex
UserControl XAML
<TextBox x:Name="txTEXT" Text="{Binding Text}"
TabIndex="{Binding Path=TabIndex, RelativeSource={RelativeSource
AncestorType={x:Type local:SearchView}}}"/>
Usage XAML
<GroupBox Header="Small,Textbox,Small,TextBox with TabIndex">
<UniformGrid Columns="4">
<local:SmallControl TabIndex="0" Text="000000" IsTabStop="False" />
<TextBox TabIndex="1" Text="111111" />
<local:SmallControl TabIndex="2" Text="222222" IsTabStop="False" />
<TextBox TabIndex="3" Text="333333" />
</UniformGrid>
</GroupBox>
You might also be able to get it tabbing correctly by setting the KeyboardNavigation.TabNavigation attached property on your UserControl to Local. I seem to recall having issues with this, but I honestly can't remember the details, so it might work.
<UserControl x:Class="SmallControl" ...
KeyboardNavigation.TabNavigation="Local" />

WPF Element Binding in a within a Resource control doesnt work

I have some xaml that will just copy text from one text box to another:
<StackPanel Orientation="Horizontal">
<TextBox Width="100" Height="30" Text="{Binding ElementName=src1, Path=Text}" />
<TextBox x:Name="src1" Width="100" Height="30" />
</StackPanel>
Nothing special, works fine. A bit dumb but just an example.
However if I put the StackPanel as a resource in the Window and create dynamically from code, like this:
<Window.Resources>
<StackPanel x:Key="MySP" Orientation="Horizontal">
<TextBox Width="100" Height="30" Text="{Binding ElementName=src, Path=Text}"/>
<TextBox x:Name="src" Width="100" Height="30" />
</StackPanel>
</Window.Resources>
.. then the element binding doesnt work anymore.
Why? and how to make it work? Any ideas gratefully received.
The following Xaml should work just fine
<Window ...>
<Window.Resources>
<StackPanel x:Key="MySP" Orientation="Horizontal">
<TextBox Width="100" Height="30" Text="{Binding ElementName=src, Path=Text}"/>
<TextBox x:Name="src" Width="100" Height="30" />
</StackPanel>
</Window.Resources>
<StaticResource ResourceKey="MySP"/>
</Window>
You could also use it from code
StackPanel mySP = TryFindResource("MySP") as StackPanel;
if (mySP != null)
{
this.Content = mySP;
}
However, what is the reason for you to have a StackPanel in the Windows Resoures?
If you want to be able to reuse it several times you would have to set x:Shared="False" on the Resource but then you'll get an exception saying something like Cannot register duplicate Name 'src' in this scope the second time you add it.
As far as I'm concerned you should not put that in <Window.Resources>. Only styles, static, dynamic resources and such...
http://msdn.microsoft.com/en-us/library/ms750613.aspx
<Window>
<Window.Resources>
</Window.Resources>
<StackPanel x:Key="MySP" Orientation="Horizontal">
<TextBox Width="100" Height="30" Text="{Binding ElementName=src, Path=Text}"/>
<TextBox x:Name="src" Width="100" Height="30" />
</StackPanel>
<Window>
Having a similar issue, trying to get relative binding to my source control - In my case, I'm creating a designer and need the element as a static so styles can use it's dimensions for centering calculations on a canvas.
Taking a line from [WPF Xaml Namescopes],
ResourceDictionary does not use XAML names or namescopes ; it uses keys instead, because it is a dictionary implementation.
So, directly using ElementName in a resource Dictionary simply does not work, because no name will bind without a NameScope. Also attempted reproducing your situation with Style setters, but no luck - one cannot set an object's name via a Style.
Now, the convoluted solution I cam up with is to
Create a DependencyProperty in the code-behind of the class
you're declaring this resource in.
replace ElementName=Root with RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type namespace:RootClass}} and bind
to said container directly, allowing you to bind to said
DependencyProperty whilst bypassing the names.
If you need bindings to operate between two elements in the same
StaticResource, bind the source to said DependencyProperty as
OneWayToSource or TwoWay, and the destination as OneWay or TwoWay.
1

Resources