I am learning how to use avalonDock by debugging its test sample apps. Something I have not been able to explain at this stage is the presence of the "Model" Keyword in some xaml binding.
Mainly in the style selector, if you remove it, the binding does not work anymore:
<avalonDock:DockingManager.LayoutItemContainerStyleSelector>
<local:PanesStyleSelector>
<local:PanesStyleSelector.ToolStyle>
<Style TargetType="{x:Type avalonDock:LayoutAnchorableItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="IconSource" Value="{Binding Model.IconSource}"/>
<Setter Property="Visibility" Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter={x:Static Visibility.Hidden}}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
<Setter Property="IsSelected" Value="{Binding Model.IsSelected, Mode=TwoWay}"/>
<Setter Property="IsActive" Value="{Binding Model.IsActive, Mode=TwoWay}"/>
</Style>
</local:PanesStyleSelector.ToolStyle>
<local:PanesStyleSelector.FileStyle>
<Style TargetType="{x:Type avalonDock:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="ToolTip" Value="{Binding Model.FilePath}"/>
<Setter Property="CloseCommand" Value="{Binding Model.CloseCommand}"/>
<Setter Property="IconSource" Value="{Binding Model.IconSource}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
</Style>
</local:PanesStyleSelector.FileStyle>
</local:PanesStyleSelector>
</avalonDock:DockingManager.LayoutItemContainerStyleSelector>
MainWindow.xaml
PaneStyleSelector
Why ? I have not been able to figure out any "Model" Field or property. And it seems to work without it for other examples:
Microsoft Example
The nice thing about XAML is that there always seems to be a way to do things a number of ways. This, of course, makes it difficult to get ahead of the learning curve sometimes too. In short, whenever you see {Binding _______} think DataContext.
Also, know that object navigation in XAML is similar to IntelliSense when typing in a normal .cs file. Meaning, if you have:
public class A { public B b = new B(); }
public class B { public string C; }
then you can get to A's B's C by doing string s = new A().B.C.
What I'm getting at is, in XAML, these three are the same:
<Style TargetType="{x:Type avalonDock:LayoutAnchorableItem}">
<Setter Property="Title" Value="{Binding Title, Path=Model}"/>
...
<local:PanesStyleSelector.ToolStyle>
<Style TargetType="{x:Type avalonDock:LayoutAnchorableItem}">
<Setter Property="DataContext" Value="{Binding Model}" />
<Setter Property="Title" Value="{Binding Title}"/>
...
<!-- What you currently have -->
<Style TargetType="{x:Type avalonDock:LayoutAnchorableItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
...
So really, Model is a property the control is going to look for in it's DataContext, and it will bind to the Title property belonging to Model.
Now the question is, how do you figure out if this is correct? Simple. Navigate through the DataContext. There is a number of ways you can do this, rather you debug, or you use F12; but here is a quick way to figure it out.
We know the target type is LayoutAnchorableItem: TargetType="{x:Type avalonDock:LayoutAnchorableItem}", so we look at its source code and look for the Model property. After looking, you don't see it, but you also notice that LayoutAnchorableItem inherits from LayoutItem, which is also our second target type coincidentally. So we look at LayoutItem source code. As you know it, there is a public object Model property. With that being said, we can make the assumption that through a chain of events, we can figure that our Model property ends up getting set to an instance of FileViewModel or ToolViewModel, and both inherit from PaneViewModel.
With that being said, we know that the DataContext of each Pane in the DockingManager is either a LayoutAnchorableItem or LayoutItem, whose Model is eventually set to an instance of FileViewModel or
toolViewModel.
Related
I have a main list which is a ribbon group.
Inside each ribbon group there is another list called subfuctions for ribbon buttons.
<DataTemplate x:Key="buttonTempl">
<RibbonButton IsEnabled="{Binding IsEnabled}" Label="{Binding Path=SubFunctionName}" Command="{Binding SubFunctionCommand}" LargeImageSource="{Binding LargeButtonImage}" SmallImageSource="{Binding SmallButtonImage}"/>
</DataTemplate>
<RibbonGroupSizeDefinitionBaseCollection x:Key="groupSize">
<RibbonGroupSizeDefinition IsCollapsed="False" />
</RibbonGroupSizeDefinitionBaseCollection>
<Style TargetType="RibbonGroup" x:Key="groupStyle">
<Setter Property="GroupSizeDefinitions" Value="{StaticResource groupSize}"/>
<Setter Property="Header" Value="{Binding DisplayName}"/>
<Setter Property="ItemsSource" Value="{Binding SubFunctions}"/>
<Setter Property="ItemTemplate" Value="{StaticResource buttonTempl}"/>
<Setter Property="SmallImageSource" Value="{Binding RibbonGroupSmallImageSource}"/>
<Setter Property="Margin" Value="0"/>
</Style>
<Style TargetType="RibbonTab" x:Key="tabStyle">
<Setter Property="Header" Value="Pump"/>
<Setter Property="ItemsSource" Value="{Binding MainFunctions}"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource groupStyle}"/>
</Style>
Hence groupSizedefinition is working if I use ribbongroup as separate as below:
<RibbonGroup Header="Selection" Name="SelectionMenu" GroupSizeDefinitions="{StaticResource groupSize}">
but not working with the above code that is with template.
What could be done to work groupsizedefinition with ribbongroup defined as style?
This is not really an answer, but it is too much for a comment.
I tried to reproduce this problem and observed the following effects using the "Live Visual Tree" and the "Live Property Explorer" windows in the debugger.
Specifying the GroupSizeDefinitions explicitly
<RibbonGroup Style="{StaticResource groupStyle}" GroupSizeDefinitions="{StaticResource groupSize}" />
the GroupSizeDefinitions in the style is crossed out, and the local definition is used
Specifying the GroupSizeDefinitions in the styls
<RibbonGroup Style="{StaticResource groupStyle}"/>
The Live property explorer shows a Local definition, which in my opinion is not present, is also crossed out.
The GroupSizeDefinitions which are actually being used are under the heading Coercion.
I'm afraid that I can't explain that, but maybe somebody else can.
I am using the RibbonControlsLibrary (.Net 4.0) for my ribbons. My implementation is completely realized using MVVM.
Now I like to use the benefit of the resizing feature. But I can't set the reduction order of the group boxes. This is because I have to define the names of the group boxes in a special order. I can't set the names of the group boxes, because I am using data templates.
I tried to bind the name of the ribbon group box user controls to a property on the datacontext, but as I supposed this doesn't work.
So, do I have any chance to set the ribbon group box user control names to a property of the data context?
Setting the RibbonGroups' names
There may be others solutions, mine is to implement a Behavior that sets the RibbonGroup's name in the OnAttached method.
public class RibbonGroupNameBehavior : Behavior<RibbonGroup>
{
protected override void OnAttached()
{
base.OnAttached();
GroupeCommandesViewModel groupeCommandesViewModel = this.AssociatedObject.DataContext as GroupeCommandesViewModel;
if (groupeCommandesViewModel != null)
{
this.AssociatedObject.Name = groupeCommandesViewModel.Nom;
}
}
}
You may want to add a try-catch block around the assignment...
Using the behavior
As you are using DataTemplates, I think you'll have to assign the behavior to the RibbonGroups with a Style.
I have been using this solution with success.
As you'll see, my behavior's code does not provide the required dependency property, you'll have to add it.
Here is my shortened Ribbon's style :
<r:Ribbon.Style>
<Style TargetType="{x:Type r:Ribbon}">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type r:RibbonTab}">
<Setter Property="ItemsSource" Value="{Binding ListeCommandes, Converter={StaticResource CommandesToGroupesConverter}}" />
<Setter Property="GroupSizeReductionOrder" Value="{Binding ListeCommandesOrdreRedimensionnement}" />
<Setter Property="ItemContainerStyleSelector">
<Setter.Value>
<ribbonVM:RibbonGroupStyleSelector>
<ribbonVM:RibbonGroupStyleSelector.GenericStyle>
<Style TargetType="{x:Type r:RibbonGroup}" BasedOn="{StaticResource RibbonGroupStyle}" />
</ribbonVM:RibbonGroupStyleSelector.GenericStyle>
</ribbonVM:RibbonGroupStyleSelector>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</r:Ribbon.Style>
And my RibbonGroup's style :
<Style x:Key="RibbonGroupStyle" TargetType="{x:Type r:RibbonGroup}" BasedOn="{StaticResource RibbonControlStyle}">
<Setter Property="Header" Value="{Binding Libellé}" />
<Setter Property="ItemsSource" Value="{Binding Commandes}" />
<Setter Property="CanAddToQuickAccessToolBarDirectly" Value="False" />
<Setter Property="ihm_behaviors:RibbonGroupNameBehavior.IsEnabled" Value="True" />
</Style>
Databinding the GroupSizeReductionOrder property
If you look at the definition of the GroupSizeReductionOrder property, you'll see it's a StringCollection with a TypeConverter StringCollectionConverter.
From what I have seen, this converter only converts from string to StringCollection.
So your property shoud be either a string or a StringCollection.
Can't see the trees through the forest.
Trying a simple databinding and I want to format the value with a converter. (In this converter example, numeric data that is 0 is not displayed.)
Resource:
<conv:FormattingConverter x:Key="FormattingConverter"/>
<Style x:Key="EGTSTextBoxInt" TargetType="TextBox">
<Setter Property="Background" Value="{StaticResource CC_BACKGROUND}" />
<Setter Property="Foreground" Value="{StaticResource CC_FOREGROUND}" />
<Setter Property="FontFamily" Value="{StaticResource DefaultFont}" />
<Setter Property="FontSize" Value="{StaticResource DefaultFontSize}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontStyle" Value="Normal" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center"
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="IsReadOnly" Value="True" />
</Style>
Textbox:
<TextBox Name="Bill_Item"
Grid.Column="6"
MinWidth="46"
MinHeight="23"
Style="{StaticResource EGTSTextBoxInt}"
Text="{Binding Path=Item, Mode=TwoWay,
Converter={StaticResource FormattingConverter},
ConverterParameter=\{0:G\}}" />
What I want to do is get the Converter code embedded in the style so that I don't have to spell it out in each Text=line.
Adding code behind the XAML to do anything for this is not an option!
I am looking for a pure XAML method.
I am still trying to grasp how certain things are done in Styles.
Brian
There are several ways to do this.
But before you even start:
It's heavy
It's utterly useless in your case
1) Define a custom markup extension
The idea is to inherit from the Binding markup extension that allows you to write Text ="{Binding SomeProperty}".
You can find an example of someone who made his own binding here
This solution does not allow you to put the feature in a style.
2) Define an attached property
that will modify the Binding of the default property of a control (in your case, Text is the default property of TextBox, as you can do <TextBox>my text</TextBox>) in order to use the converter you want, automatically.
This actually allows you to put set this attached property in a style. It is, however, very bad practice. It's as bad a magic strings.
3)Don't do this, just don't.
Write the converter each time.
The Text property of the TextBox is about data. The Style property is about what that data looks like. It doesn't make sense to attach a Converter to a Style.
Edit: I think I see what you're trying to say now. You want Text="{Binding Path=Item}" in one place and <Setter Property="Text" Value="~somehow get the converter in here and have it applied to the existing text property which is bound to Items~" />
As mydogisbox mentioned, I don't think you can split up these ideas in two places like that.
Converters are for converting one value into another value, so they cannot be used without the value they are converting
You can however use StringFormat in your binding to format values without a Converter
<TextBox Text="{Binding Path=Item, StringFormat=G}" />
You could also create a class that inherits from Binding class and sets the default StringFormat, although I feel this is more trouble than it's worth
<TextBox Text="{local:NumberBinding Path=Item}" />
And if you are ever working with Labels instead of TextBoxes, you can apply a style setter to ContentStringFormat, which will apply formatting to the Label's Content
<Style TargetType="{x:Type Label}">
<Setter Property="ContentStringFormat" Value="G" />
</Style>
I would like to take the xaml I currently have for a ComboBox (below), and condense it into something like the Style also shown below. I think this should work, but I have a 'Type'ing issue and not sure how to resolve it
"Cannot resolve the Style Property 'Margin'. Verify that the owning type is the Style's TargetType, or use Class.Property syntax to specify the Property.)
As I look at the existing ComboBoxStyle (also below) that I'm looking to base this new style off of, I see that I hadn't used x:Type, but it does seem to work.
Is there any reason this new style shouldn't work? What must I change?
Cheers,
Berryl
combo box, as is, working):
<ComboBox
x:Name="cboDepartmentFilter" Style="{StaticResource ComboBoxStyle}"
Margin="{StaticResource FliterPanelItem_Margin}" Width="{StaticResource FilterPanelItem_Width}"
ItemsSource="{Binding Path=DepartmentFilterControl.Choices}"
ToolTip="{Binding DepartmentFilterControlData.ToolTipTitle}"
/>
what I want:
<ComboBox Style="{StaticResource FilterPanelComboBoxStyle}" DataContext="{Binding DepartmentFilterControl}" />
<!- in some resource file ->
<Style x:Key="FilterPanelComboBoxStyle" BasedOn="{StaticResource ComboBoxStyle}">
<Setter Property="Margin" Value="{StaticResource FliterPanelItem_Margin}" />
<Setter Property="Width" Value="{StaticResource FilterPanelItem_Width}" />
<Setter Property="ItemsSource" Value="{Binding Choices}" />
<Setter Property="ToolTip" Value="{Binding ToolTipTitle}" />
</Style>
<!--
This style defines a common margin for items in a filter panel.
-->
150
existing ComboBoxStyle:
<!-- ComboBox Style -->
<Style x:Key="ComboBoxStyle" TargetType="ComboBox">
<Setter Property="Background" Value="{StaticResource headerBrush}" />
...
<Setter Property="Template">
<Setter.Value>
...
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle" Value="{StaticResource ComboBoxItemStyle}" />
<Setter Property="IsSynchronizedWithCurrentItem" Value="True" />
</Style>
You still need to specify the TargetType in the derived style. (Or you prefix the properties with "ComboBox.")
I have a textbox that has the following simple XAML (not necessary to read it - just have it for reference):
<TextBox Name="m_ctrlUserDeviceType" Style="{StaticResource textStyleTextBox}" Text="{Binding Source={x:Static api:MySettings.Instance}, Path=UserDeviceType, ValidatesOnExceptions=true, NotifyOnValidationError=true}" Validation.Error="TextBox_Error" MinHeight="25" Margin="4" VerticalAlignment="Top" MaxLength="23" VerticalContentAlignment="Center" HorizontalAlignment="Left" MinWidth="100"></TextBox>
For completeness, the style textStyleTextBox looks like this (again, not necessary to read to answer question):
<Style x:Key="textStyleTextBox" TargetType="TextBox">
<Setter Property="Foreground" Value="#333333" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="MinHeight" Value="2" />
<Setter Property="MinWidth" Value="100" />
<Setter Property="Margin" Value="4" />
<Setter Property="MaxLength" Value="23" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Left" />
<!-- <Setter Property="Binding Source" Value="{x:Static api:MySettings.Instance}"/>
<Setter Property="Binding ValidatesOnExceptions" Value="true" />
<Setter Property="Binding NotifyOnValidationError" Value="true" /> -->
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
I have a lot of the stuff (MiHeight, Margin, etc.)in the style because I have a lot of these textboxes and they're almost exactly the same. In fact, there's a lot more in common than just the style. The details of the binding to the class MySettings are almost the same. The only difference is which particular property the textbox is binding too. Additionally, I always user TextBox_Error for Validation.Error.
Is there a way to put the binding info in Style or Data Template so I don't have to keep typing it for each textbox?
I would need to be able to assign an individual property (Path) for each textbox, and I suppose I still need the ability to not use any of it for some particular textbox added in the future (that has nothing to do with databinding to MySettings).
Is there a way to put the TextBox_Error part inside of style or DataTemplate? Using Setter Property did not seem to work for me.
I keep mentioning Data Template as I think the answer might have something to do with that based on reading Pro Silverlight 2 in C# 2008. However, I wasn't able to figure it out. I also tried adding stuff to "Style" as you can see from the commented out stuff in that section.
Thanks,
Dave
I dont think that there is a way to do what you are asking. However, I do think that you could go about it a different way.
What I would look into, is creating a custom control that extends TextBox, then create some dependency properties that, when the control is initialised, setup the bindings and error validation.
This way you can use your custom textbox all over your app and control every property, and even style them the same (just change the target type of your style)
HTH