WPF databind Image.Source in MVVM - wpf

I'm using MVVM and am trying to databind the Source property of Image to my ViewModel in such a way that I can change the icon on the fly. What is the best pattern to follow for this? I still have the flexibility to change my ViewModel to suit, but I don't know where to start in either the xaml or ViewModel.
To be clear, I don't want my ViewModel to know about the specific images (that's for the View to know), just the state that triggers different images. For now I have just two states, lets say Red and Green. Should I create an Enum property or a bool? And then how do I databind to switch the image source?

You can use a DataTrigger, and change the image (entirely in XAML) based on the value of a property in your ViewModel. I, personally, would use an enum, since you may want multiple states.
VisualStateManager will work for this as well, but will require WPF Futures or .NET 4.
In order to use a DataTrigger, you can do something like:
<Image>
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="1.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding ViewModelEnumProperty}" Value="Image2">
<Setter Property="Source" Value="2.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
This will use "1.png", but when your enum is set to "Image2" in the VM, it'd switch to 2.png. More DataTriggers can be added as needed.

Related

WPF toggle button how to switch between 2 customized brushes

Hi I'm new to the WPF world.
I am working with a Toggle button and not sure how I can switch between 2 brushes.
Basically I have 2 brushes that each defines a XAML image, both of them are stored in a ResourceDictionary. One brush should by default shown and the other one should be shown when IsChecked property is true.
I kind know that I need to wrap them into styles and should use a trigger to toggle them but I am not familiar with the syntax how to do this.
What's the generic way to do this?
Any suggestion is appreciated.
Generically:
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Name, Path=IsChecked}" Value="true">
<DataTrigger.EnterActions>
<!-Set The Brush That You Want To Use-->
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>

How to change the control template effectively in WPF?

The subject is that I've defined a customized control bound to a DataContext. And I wished to change the control template dynamically according to the DataContext's specific property values.
There're 2 ways I've thought of,but I have no idea about which way is better.
1.Do not use the control template in a ResourceDictionary and all details of the control are defined in C# code.Use the DependencyProperty CallBack method to render the control when DataContext's property values change.
2.Define control template in the ResourceDictionary and use DataTrigger to change the 'Control.Template' property.
In my application,thousands of instances in this type would be created,so it's really unacceptable if the ControlTemplate changging is not effective.
Could you please give me some advices or better solutions?
Using any standard WPF technique might not be effective if it would involve a thousands of instances of complex controls. See http://msdn.microsoft.com/en-us/magazine/dd483292.aspx.
I would go with MultiBinding + IMultiValueConverter to Control.Template dependency property, since Template would depend on multiple DataContext properties and would, perhaps, involve complex logic.
Perhaps you could used a ContentPresenter in your ControlTemplate to customize parts of your control. You could provide DataTemplates for those customizable parts which are automatically applied.
I would use a style with the data triggers to control which template is displayed. Like this example:
<Style x:Key="Die1Face" TargetType="{x:Type Button}">
<Setter Property="Template" Value="{StaticResource dieNone}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ThrowDie1[0]}" Value="1" >
<Setter Property="Template" Value="{StaticResource dieOneA}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ThrowDie1[0]}" Value="2" >
<Setter Property="Template" Value="{StaticResource dieTwoA}" />
</DataTrigger>
</Style.Triggers>
</Style>
This would give the flexibility you need.

Custom panel with alternate background

I'd like to create a simple custom panel to layout children in a business form fashion. Ideally I'd like my markup to look like this:
<Panels:FormPanel>
<TextBlock Text="Name:"/>
<TextBox />
<TextBlock Text="Address"/>
<TextBlock Text="Unknown"/>
<TextBlock Text="City"/>
<TextBox HorizontalAlignment="Stretch"/>
<TextBlock Text="State"/>
<ComboBox/>
<TextBlock Text="Country"/>
<StackPanel>...</StackPanel>
</Panels:FormPanel>
The panel will layout controls in two columns labels on the left side and values on the right.
I have no problem laying out my controls. The problem is that I also need to alternate background for the rows to create stripes for easier reading.
Any ideas how can this be done?
This doesn't directly answer your question, but you could consider this as another solution to the underlying problem.
Take a look at http://wpg.codeplex.com/. I used a similar property-grid-like control in Windows Forms that was modified to understand custom attributes on my business objects.
Now, in WPF, I would think something similar would work really well if you follow the MVVM pattern and you decorate your ViewModel with attributes that such a property grid understands. Then you don't need to explicitly define the fields like you show above.
You could have a ViewModel:
class PersonViewModel
{
[DisplayName("Name")] // The property Grid uses this the Textblock text
[IsRequired] // The property grid could do validation on the field
[Visible]
public string Name { get; set; }
public long InvisibleSystemField { get; set; } // Not shown
}
And then you'd only have Views (Xaml files) like this:
<myCommon:PropertyGrid DataContext={Binding}/>
It could simply use it's DataContext as the starting point for reflection.
OK I'll stop there for now :)
I'm working on a WPF powered LOB application and I'll possibly build something like this in future.
Implementing a custom panel is not actually that difficult. You have to override two methods, Measure and Arrange. Google for "wpf custom panel" to get some articles about that.
What I would suggest you do to get the behavior exactly as you required in the question is extend Windows.Controls.Grid. Your custom grid could then have two columns by default that you initialize in the constructor and you can programmatically set the Grid.Column and Grid.Row properties on the child controls.
Also worth looking at could be the ItemsControl. It does have support for alternatively colored rows. This example (from MSDN) shows how to use it:
<Grid>
<Grid.Resources>
<Style x:Key="alternatingWithTriggers" TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
<Style.Triggers>
<Trigger Property="ListBox.AlternationIndex" Value="1">
<Setter Property="Background" Value="CornflowerBlue"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="ListBox.AlternationIndex" Value="2">
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="Navy"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ListBox AlternationCount="3" ItemsSource="{StaticResource data}"
ItemContainerStyle="{StaticResource alternatingWithTriggers}">
</ListBox>
</Grid>
You could then specify a template for the items that includes a Label and a TextBox, but getting this to work could be fiddly.
Here's one final thing I'll suggest:
XAML Powertoys include features that allow you to generate business forms from ViewModels, ViewModels from Models and much more. You might need to modify the source to get alternating row colors though.
Good luck!

UserControl as ListBoxItem and IsSelected

I have a usercontrol that I want to use as a ListBoxItem.
<ListBox.ItemTemplate>
<DataTemplate>
<local:MyUserControl/>
</DataTemplate>
</ListBox.ItemTemplate>
I'd like to play a storyboard when the usercontrol is unselected.
<UserControl.Resources>
<Style TargetType="{x:Type UserControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}, Mode=FindAncestor}}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource OnMouseLeaveSB}"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
But the storyboard is never firing. Is there a better way to do this?
Edited to Add:
What I am really trying to accomplish this this:
When the mouse is over the UserControl, I want to play a storyboard (OnMouseEnterSB). When the mouse leaves the UserControl, I want to play another storyboard (OnMouseLeaveSB). I have all this working fine.
When the UserControl is selected, however, and the mouse leaves, I do NOT want to play the storyboard.
Finally, when the UserControl is unselected, I want to play the OnMouseLeaveSB storyboard.
I don't have WPF experience rather I am a Silverlgiht girl and in Silverlight the thing you are describing is called "VisualStateManager" (just binged it, it is also available in WPF).
With VSM you would define different visual appearances for each "state" of your (user)control (mouseover, mouseleft, normal) and also depending on the previous and/or next state you can define different transitions between those states (or you may use a default transition for moving between all different states).
Read this blog-post by Tim Heuer. Describes it well with many screenshots :). You may also want to check out this link.
Using VSM the states and animations are a part of the control not the application with bunch of event-handlers and animation.Begin() calls. I really like and recommend it :)
If i understand your question correctly, you want to play this animation 'OnMouseLeaveSB' when any ListViewItem loses selection. But in your trigger you're playing the animation for all the unselected items. Hence even if this works, it will not be the one you wanted.
Reason why the storyboard does not fire is that the default BlueHighlight hides your animation. A hack to get rid of this would be to set the border color which is explained here www.HereIsYourLink.com
To achieve what you want, you'll have to insert your storyboard in Trigger.ExitActions with the IsSelected value 'True'.
If you're not in a hurry, take a look at VSM too.

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