Showing posts with label INPC. Show all posts
Showing posts with label INPC. Show all posts

Thursday, 21 November 2013

Binding visual state manager to a view model

Using an attached property:

using System;
using System.Windows;
using System.Windows.Controls;

namespace StateHelperSL
{
public class VisualStateHelper : DependencyObject
{
public static readonly DependencyProperty VisualStatePropertyProperty = DependencyProperty.RegisterAttached(
"VisualStateProperty",
typeof(string),
typeof(VisualStateHelper),
new PropertyMetadata(VisualStatePropertyChangedCallback));

private static void VisualStatePropertyChangedCallback(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
var ctrl = s as Control;
if (ctrl == null)
throw new InvalidOperationException("This attached property only supports types derived from Control.");

VisualStateManager.GoToState(ctrl, e.NewValue.ToString(), true);
}

public static string GetVisualStateProperty(DependencyObject obj)
{
return (string)obj.GetValue(VisualStatePropertyProperty);
}

public static void SetVisualStateProperty(DependencyObject obj, string value)
{
obj.SetValue(VisualStatePropertyProperty, value);
}
}
}
You can bind your view:
<UserControl x:Class="StateHelperSL.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StateHelperSL"
local:VisualStateHelper.VisualStateProperty="{Binding State, Mode=OneWay}"
mc:Ignorable="d">

<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Gone">
<Storyboard>
<DoubleAnimation To="1000"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
Storyboard.TargetName="AnimatableButton"
d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel Margin="50">
<Button x:Name="AnimatableButton" Click="ButtonBase_OnClick" Height="30" Content="Click me">
<Button.RenderTransform>
<CompositeTransform/>
</Button.RenderTransform>
</Button>

</StackPanel>
</Grid>
</UserControl>
View code behind:
using System.Windows;

namespace StateHelperSL
{
public partial class MainPage
{
private readonly ViewModel vm;

public MainPage()
{
this.InitializeComponent();
this.vm = new ViewModel();
this.DataContext = this.vm;
}

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
vm.State = "Gone";
}
}
}

To your view model:


namespace StateHelperSL
{
public class ViewModel : PropertyChangedBase
{
private string state;

public ViewModel()
{
State = "Normal";
}

public string State
{
get { return this.state; }
set
{
if (state == value) return;
this.state = value;
NotifyOfPropertyChange("State");
}
}
}
}

Sunday, 23 September 2012

INPC Parent Child Notification

Here is a simple example of a parent listening to change notification from a child and exposing an aggregate value (or “denormalized” value in database terminology).

The Order (parent) exposes the TotalCost, which is a sum of the Cost properties in OrderLines (child).

image

public class Order : InpcBase
{
private readonly ObservableCollection<OrderLine> orderLines;

public Order()
{
orderLines = new ObservableCollection<OrderLine>();
}

public decimal TotalCost
{
get { return orderLines.Sum(ol => ol.Cost); }
}

public void AddOrderLine(OrderLine orderLine)
{
orderLine.PropertyChanged += orderLine_PropertyChanged;
}

private void orderLine_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Cost") OnPropertyChanged("TotalCost");
}
}

public class OrderLine : InpcBase
{
private decimal cost;
public decimal Cost
{
get { return cost; }
set
{
if (cost == value) return;
cost = value;
OnPropertyChanged("Cost");
}
}
}

public abstract class InpcBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler == null) return;
handler(this, new PropertyChangedEventArgs(name));
}
}