I am using MVVM Light. I have created a window that looks like this:
<Window Name="MainWindow" ...>
<Window.Resources>
...
<viewModels:MainViewModel x:Key="mainVM" />
...
<BooleanToVisibilityConverter x:Key="visConv" />
...
</Window.Resources>
<Grid DataContext="{StaticResource mainVM}>
...
<Button Command="{Binding RaiseMyControl}" />
...
<my:MyUserControl Visibility="{Binding MyControlVisible,
Converter={StaticResource visConv}}" />
</Grid>
</Window>
So basically, the MainViewModel is a view model class for the window. It contains:
bool MyControlVisible property which is binded to MyUserControl's Visibility
property
RelayCommand RaiseMyControl command which purpose is to set the value of the
MyControlVisible property to true (default is false).
Clicking the button in the window results in the appearance of the MyUserControl - simple.
MyUserControl user control looks like this:
<UserControl ...>
<UserControl.Resources>
...
<viewModels:MyUserControlViewModel x:Key="userControlVM" />
...
</UserControl.Resources>
<Grid DataContext="{StaticResource userControlVM}>
...
<Border Width="200" Height="100" Background="Red">
<TextBlock Text="{Binding MyUserControlText}" />
</Border>
<!-- This border has a DataTrigger bound to "bool Fading" property of
the view model. When Fading is true, the border fades in through
an animation. When it is false, the border fades out. -->
...
<Button Command="{Binding CloseMyControl}" />
</Grid>
</UserControl>
Again, very simple. The MyUserControlViewModel is a view model class for the user control. It contains:
string MyUserControlText property which is binded to TextBlock's Text
property
bool Fading property which is binded to border's data template, and is used to make
the border fade in or out
RelayCommand CloseMyControl command which does two things: 1. It sets the Fading
property to false to make the border fade out, and 2. it sets the Visibility
property of the user control to Collapsed.
Here's the problem: as soon as the Visibility is set to Collapsed, the user control disappears. I need it to fade out first and then to disappear afterwards. How can I make it happen? Thanks.
Since the visibility belongs to the fade-out i would run two animations at the same time. Additionally to your fade-animation (of whatever type or composite that may be) you can create a ObjectAnimationUsingKeyFrames which sets the Visibiliy at the key time at which the fade ends.
XAML example:
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
Additionally all storyboards and animations have a Completed event to which you could subscribe and just set the value right away.
To direct the animation at another control use Storyboard.Target for complex references, or Storyboard.TargetName for reference by name.
To animate the UserControl you could try:
Storyboard.Target="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}"
or
Storyboard.Target="{Binding RelativeSource={RelativeSource AncestorType=my:MyUserControl}}"
Both should work if the logical tree is intact.
I'd try setting the visibility to Collapsed as part of the fade out animation, not a separate line in the CloseMyControl command.
Related
I have, I think a simple question. I have several buttons and depending on which one is clicked, need to bind data to my DataGrid - for examples if Button1 is clicked, bind fields A-D to the grid; if Button2 is clicked, bind fields E-J to the grid. I have the data binding working fine but can't seem to integrate the buttons to determine which data to bind. The same DataGrid is using no matter which button is pressing but I need to bind different data based on which button is clicked. Any thoughts?
Use ToggleButton instead of Button, as they expose IsChecked property.
Declare a Freezable like <DiscreteObjectKeyFrame x:Key="A-D" Value="True"/> under Window.Resources or DataGrid.Resources .
Define <BooleanToVisibilityConverter x:Key="BooleanToVisCnvKey"/> under Window.Resources or DataGrid.Resources.
Bind Visibility of DataGridColumn to DiscreteObjectKeyFrame .Value declared in (2) above, and use a IValueConverter to convert boolean to Visibility.
<Window.Resources>
<DiscreteObjectKeyFrame x:Key="FlagKey" Value="False"/>
<BooleanToVisibilityConverter x:Key="BooleanToVisCnvKey"/>
</Window.Resources>
...
<DataGrid>
...
<DataGridTextColumn Visibility="{Binding Value, Source={StaticResource FlagKey}, Converter={StaticResource BooleanToVisCnvKey}}" ...>
...
</DataGrid>
...
<ToggleButton ... IsChecked="{Binding Value,Source={StaticResource FlagKey}, Mode=TwoWay}" />
I have a ListView which is bound to a List of items of the following type:
class Item : INotifyPropertyChanged
{
//Both these props have property change notification implemented. Left out for brevity.
int Price{get;set}
int Size{get;set}
}
I have a DataTemplate for this class to show in ListView
The size of the list does not change but the values of the properties of the items in the list do. Suppose I first have three items like this:
Item format : Size#Price
{(10#34), (15#37), (10#38)}
Suppose now the first item only changes due to a data update:
{(15#34), (15#37), (10#38)}
Please note that I do not remove the existing item. I only change its properties. So a property changed notification will fire for each change. I want to highlight/flash the item that changed in the ListView upon such a change. How do I do this (Preferably in XAML)?
Not sure I follow this right, Are you just looking to say flash the ListViewItem when the Size or Price property changes?
If so you should be able to do that with a Binding.TargetUpdated event trigger. You do need to make sure your binding for Size and Price in their binding also specify NotifyOnTargetUpdated=True for this event to fire.
So something like this should work fine:
<DataTemplate x:Key="SomeTemplate" DataType="viewModel:Item">
<StackPanel x:Name="stackPanel"
Background="Transparent"
Orientation="Vertical">
<!-- This prolly aint your layout. Just here as an example -->
<TextBlock Text="{Binding Size, NotifyOnTargetUpdated=True}" />
<TextBlock Text="{Binding Price, NotifyOnTargetUpdated=True}" />
</StackPanel>
<DataTemplate.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard AutoReverse="True">
<!-- From="1.0" helps prevent spam property changes skewing the opacity -->
<DoubleAnimation Duration="0:0:0.3"
Storyboard.TargetName="stackPanel"
Storyboard.TargetProperty="Opacity"
From="1.0"
To="0.3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Alternate:
From blend with xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
you should also have <ei:PropertyChangedTrigger> using which you can then say invoke a Behavior to trigger a Storyboard <ei:ControlStoryboardAction>. Personally I've only used the first approach as it's slightly simpler.
I'm attempting to flip a button on a form using a storyboard. What I currently have is a storyboard that uses a custom grid animation to make certain grid rows grow (found here). The button that I have that initiates this storyboard has an image of arrows overlayed on it and it needs to be flipped to correct the direction of the control for the user to understand. The storyboard that I have works (as in it doesn't produce any errors) but it only makes the gridrow height property grow; the button image is not flipped vertically.
<!-- "Open the description box" Storyboard-->
<Storyboard x:Key="openDescription">
<local:GridLengthAnimation
Storyboard.TargetName="Row4"
Storyboard.TargetProperty="Height"
From="0*" To=".5*" Duration="0:0:1"
AccelerationRatio=".5"
DecelerationRatio=".5"/>
<!-- This is the section that needs to be tweaked -->
<DoubleAnimation
Storyboard.TargetName="btnDetailsZoom"
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
From="0"
To="-1"
Duration="00:00:01"/>
</Storyboard>
<!-- Code for the button -->
<s:SurfaceButton Grid.Row="4" Grid.Column="4" VerticalAlignment="Top" Margin="25,-50,25,-50" Name="btnDetailsZoom" PreviewTouchDown="onDetailsZoom">
<s:SurfaceButton.Background>
<ImageBrush ImageSource="/uiTest2;component/Resources/doubleArrowUp.png" />
</s:SurfaceButton.Background>
</s:SurfaceButton>
If anyone knows about how to correctly use the scaletransform property within a storyboard (since I'm fairly sure that's partially correct), I would greatly appreciate some guidance.
Thanks!
It looks like you forgot to define the Transform Property on the Button, like this:
<!-- Code for the button -->
<s:SurfaceButton Grid.Row="4" Grid.Column="4" VerticalAlignment="Top" Margin="25,-50,25,-50" Name="btnDetailsZoom" PreviewTouchDown="onDetailsZoom">
<s:SurfaceButton.RenderTransform>
<ScaleTransform />
</s:SurfaceButton.RenderTransform>
<s:SurfaceButton.Background>
<ImageBrush ImageSource="/uiTest2;component/Resources/doubleArrowUp.png" />
</s:SurfaceButton.Background>
</s:SurfaceButton>
I am working on WPF and have little knowledge of XAML customly created controls.
I have a custom control name 'DualButton' as follows :
<Controls:DualButton x:Name="StandardConferenceCancelButton"
Width="90"
Height="25"
Margin="2"
LeftButtonCommand="{Binding StandardModeConnectCommand}"
RightButtonCommand="{Binding ConferenceCancelCommand}"
>
<AccessText HorizontalAlignment="Center" Text="{x:Static I18N:TelephonyRegionViewRes.Standard}" />
</Controls:DualButton>
its 2 dependancy properties 'LeftButtonCommand' and 'RightButtonCommand'binds two different ICommands.
I want to set Visibility of this button to CanExecute of LeftButtonCommand so that when LeftButtonCommandCanExecute() returns true, that time only button gets visible.
I took dependancyProperty 'IsEnabled' what further I need to do in this
I know it's late, but might help others...
In your DataContext, create a property like IsVisible that returns
StandardModeConnectCommand.CanExecute()
In your window or user control, add the resource
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
In your dual button, after or before the commands, add:
Visibility="{Binding IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
Finally, in the places where the returned value of CanEecute is likely to change, add in your datacontext a
NotifyPropertyChanged(nameof(IsVIsible));
You should be on track with this.
I am using Silverlight 4 and the MVVM pattern.
My view model has two properties:
SomeProperty and
MyCommand
SomeProperty is a complex type and has a lot of subproperties. MyCommand is a property to handle commanding from a Button.
I have a child window (the view) with a Grid as the LayoutRoot which is bound to the SomeProperty property of the view model.
<Grid x:Name="LayoutRoot" DataContext="{Binding SomeProperty, Mode=TwoWay}">
...
</Grid>
However, inside the Grid I want to bind a Button's Command property to the MyCommand property of the view model:
<Button Command={Binding MyCommand} />
But this is not working because MyCommand is a property of the view model, and not a property of the view model's SomeProperty property. (When I click on the Button it does not execute the command.)
Anywho, is there a way using data binding in Silverlight 4 such that I can have a container UI element set its DataContext property explicitly, but then have a different control within the container reference a property that's a sibling (or parent or whatever) of the DataContext of the containing control?
My current workaround is to define the binding in the view's class, but I'd rather have it in the XAML.
Thanks
If you give your root element (ChildWindow, UserControl, whatever) a name, then you can use ElementName to get to the view model.
<UserControl x:Name="MyUserControl">
<Grid x:Name="LayoutRoot" DataContext="{Binding SomeProperty, Mode=TwoWay}">
<Button Command="{Binding MyCommand}" DataContext="{Binding DataContext, ElementName=MyUserControl}" />
</Grid>
</UserControl>
Or, here's another way to do the same thing.
<UserControl x:Name="MyUserControl">
<Grid x:Name="LayoutRoot" DataContext="{Binding SomeProperty, Mode=TwoWay}">
<Button Command="{Binding DataContext.MyCommand, ElementName=MyUserControl}" />
</Grid>
</UserControl>
You try add datacontext to binding? The datacontext have to point to your viewmodel, because the default data context is a parent control or parent data context, in this case your layout root.
See this
and this
I hope this help.
Regards.
I use a version of the BindableProxy described in this post:
http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx
Above your Grid (probably within the UserControl.Resources) you would create:
<UserControl.Resources>
<ns:BindableProxy x:Key="BindableProxy" />
<UserControl.Resources>
Then, in the button binding:
<Button Command="{Binding DataSource.MyCommand, Source={StaticResource BindableProxy}}" />