Is it right to put a viewmodel in a resourcedictionary? - wpf

I'm developing a WPF project, and usually I use resourcedictionary to organize the styles and colors. When using Expression Blend it will put the viewmodel object in a resource like this:
<local:VM x:Key="VM" d:IsDataSource="True"/>
and set the datacontext like this
<Window.DataContext><Binding Mode="OneWay" Source="{StaticResource VM}"/></Window.DataContext>
This is very useful to get the command or property in XAML using the source property in binding like this (especially in datatemplate)
{Binding XXCommand,Source={StaticResource VM}}
Can I put the viewmodel object in resourcedictionary or is it better to put this view specific in each view that is related to the viewmodel?
Also, if I put the below style in resourcedictionary I have to include the viewmodel object,
<Style x:Key="MenuItemStyle" TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Desc}"/>
<Setter Property="Icon" Value="{StaticResource IconImage}" />
<Setter Property="Command" Value="{Binding ChangeShowCommand,Source={StaticResource VM}}"/>
<Setter Property="CommandParameter" Value="{Binding}"/>
</Style>

This might be the answer: MVVM Instantiation Approaches. Nicely explained couple of instantiation approaches.

Related

XAML separate binding of ContainerStyle and ContentTemplate in ListBox

I tried this for a while now and searched in the web without success... Now I dare to ask on stackoverflow myself.
So, the aim is to separate the definitions of the ItemContainerStyle and the ContentTemplate of a ListBoxItem. I have defined the ListBoxItemStyle in a ResourceDictionary and two different DataTemplates in the Window.Resources.
I now like to set the style of the ListBoxItem according to the one defined in the ResourceDictionary and change the DataTemplate with a trigger (IsMouseOver).
My (not working) Code so fare looks like this:
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="20,60,10,10"
Grid.Row="1" Grid.Column="0"
PreviewMouseMove="DragMove_PreviewMouseMove"
PreviewMouseLeftButtonDown="Drag_PreviewMouseLeftButtonDown"
ItemsSource="{Binding Persons}" VerticalContentAlignment="Center"
Style="{StaticResource DefaultListBoxStyle}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Style" Value="{StaticResource DefaultListBoxItemStyle}"/>
<Setter Property="ContentTemplate" Value="{StaticResource PersonsListBoxItemTemplate_default}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource PersonsListBoxItemTemplate_infoButtons}"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
where DefaultListBoxStyle is the style defined in the ResourceDictionary and PersonsListBoxItemTemplate_default & PersonsListBoxItemTemplate_infoButtons are the DataTemplates defined in the Window.Resources.
Now I get an error, that the style-object must not have an impact on the style-property of the object it belongs to.
I tried different ways, but without success... I also tried to define the style first and then change the template, but it does not work either.
Thank you all for your help!
So you can't set Style Property in Style with Setter. For this you need to use BasedOn:
<Style TargetType="ListBoxItem" BasedOn="{StaticResource DefaultListBoxItemStyle}">
<Setter ... />
</Style>

Model "namespacing" for wpf StyleSelector?

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.

Converter for bound data in style

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>

Attached behaviors and styles

I use an attached behavior that allows a DoubleClick event to be wired to a command in a view model, as in the binding below:
<ListBox Style="{StaticResource MasterListBoxStyle}"
b:SelectionBehavior.DoubleClickCommand="{Binding EditCommand}"
>
I need multiple list boxes for a presentation, all of which will need a DoubleClick wired to an EditCommand.
Can I push this behavior into my MasterListBoxStyle? How?
Cheers,
Berryl
<Style x:Key="MasterListBoxStyle" TargetType="ListBox">
<Setter Property="ItemsSource" Value="{Binding MasterVm.AllDetailVms}" />
<Setter Property="ItemContainerStyle" Value="{StaticResource MasterListingRowStyle}" />
<Setter Property="IsSynchronizedWithCurrentItem" Value="True" />
<Setter Property="AlternationCount" Value="2" />
</Style>
You should be able to add a simple Setter like so in WPF:
<Setter Property="b:SelectionBehavior.DoubleClickCommand" Value="{Binding EditCommand}" />
Assuming the b xmlns is defined in the XAML file that contains your Style.
This won't work in Silverlight though, since Bindings are not supported in Setters. This is something Microsoft is fixing in Silverlight 5.

WPF Trigger for IsSelected in a DataTemplate for ListBox items with Blend

I wanted to change the Foreground color when I selected a listboxItem and I did it using this bit of code:
<DataTrigger Binding="{Binding
RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="True">
<Setter TargetName="descriptionTB" Property="Foreground" Value="#000"/>
</DataTrigger>
You can find the answer here.
But if I want a designer to do this in Blend, how would he do it without drilling into xaml?
Thank you
Artur,
The Triggers designer in Expression Blend only allows adding and modifying EventTriggers and Property triggers. I haven't found a way to add DataTriggers with Blend. I'm also not sure how to set RelativeSource Binding using Blend either. I've always handed code the XAML for test and use Blend for everything else.
Maybe I'm misunderstanding the question but can't you just create a style resource for descriptionTB and let the designer only deal with that style definition and not the binding?
<DataTrigger Binding="..">
<Setter TargetName="descriptionTB" Property="Style" Value="{StaticResource DescriptionTextBoxStyle}" />
</DataTrigger>
In the resources section of your control or window you add the style definition:
<Style TargetType="{x:Type TextBox}" x:Key="DescriptionTextBoxStyle">
<Setter Property="Foreground" Value="#000" />
</Style>
If you want to further isolate the designer from the mechanics of the UI you can create a resource dictionary in a separate xaml file in which you can collect all styles meant for the designer. Then you can merge that resource dictionary with your control's or application's main resources.

Resources