Scroll multiple image in wpf - wpf

<Grid>
<Grid.Background>
<ImageBrush ImageSource="Images\Desert.jpg"
Stretch="UniformToFill" TileMode="Tile"
ViewportUnits="Absolute" Viewport="0,0,1024,768"/>
</Grid.Background>
<Grid.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<RectAnimation Storyboard.TargetProperty="Background.Viewport"
To="-1024,0,1024,768" Duration="0:0:10"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
I have this code that scroll a single image in a grid with looping.
Now I have 2 images 1(red) and 2(yellow) am looking something like this.
and it will scroll in loop

You can build a single ImageSource based on multiple images if you wanted to follow your current approach. I have 2 png's (Desert1.png and Desert2.png in an Images folder) and use DataBinding to set the ImageBrush ImageSource to a property defined on the code behind:
<!- Your original xaml ... only difference is the binding -->
<ImageBrush ImageSource="{Binding CombinedImage}"
Stretch="None" TileMode="Tile"
ViewportUnits="Absolute" Viewport="0,0,1024,768"/>
Here's a sample of the code behind (feel free to refactor / use / abuse as you see fit):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xaml;
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var uriSource1 = new Uri(#"pack://application:,,,/Images/Desert1.png", UriKind.Absolute);
BitmapImage bitmapImage1 = new BitmapImage(uriSource1);
var uriSource2 = new Uri(#"pack://application:,,,/Images/Desert2.png", UriKind.Absolute);
BitmapImage bitmapImage2 = new BitmapImage(uriSource2);
this.DataContext = this;
List<BitmapImage> images = new List<BitmapImage>() { bitmapImage1, bitmapImage2 };
CombinedImage = GetCombinedImage(images);
}
private static RenderTargetBitmap GetCombinedImage(IEnumerable<BitmapImage> images )
{
// Get total width of all images
int totalWidthOfAllImages = images.Sum(p => (int)p.Width);
// Get max height of all images
int maxHeightOfAllImages = images.Max(p => (int)p.Height);
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
double left = 0;
foreach (BitmapImage image in images)
{
drawingContext.DrawImage(image, new Rect(left, 0, image.Width, image.Height));
left += image.Width;
}
}
RenderTargetBitmap bmp = new RenderTargetBitmap(totalWidthOfAllImages, maxHeightOfAllImages, 96, 96, PixelFormats.Default);
bmp.Render(drawingVisual);
return bmp;
}
public ImageSource CombinedImage { get; private set; }
}
}

I have code for image slider. I created using user control for windows phone
Please check with this video http://www.screencast.com/t/XnhHwQFY For first time you need to change logic.
But, I think same code you can use for WPF also
ImageSlider.xaml - Create user control
<UserControl x:Class="ImageSliderDemo.ImageSlider"
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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<Canvas Height="220" x:Name="imageSliderCanvas" Width="451">
<Image x:Name="imageViewOne"
Canvas.Left="0"
Canvas.Top="0"
Height="220" Width="440" Canvas.ZIndex="9">
<Image.RenderTransform>
<TranslateTransform />
</Image.RenderTransform>
</Image>
<Image x:Name="imageViewTwo"
Canvas.Left="0"
Height="220" Width="440" Canvas.ZIndex="10">
<Image.RenderTransform>
<TranslateTransform />
</Image.RenderTransform>
</Image>
</Canvas>
<StackPanel x:Name="PART_Host" />
</Grid>
</UserControl>
ImageSlider.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Markup;
namespace ImageSliderDemo
{
public partial class ImageSlider : UserControl
{
private const int LOWER_ZINDEX = 9, UPPER_ZINDEX = 11, POSITION_FROM480 = 480, POSITION_TO0 = 0;
private int nextImage = 1;
#region "Image Slider Properies"
#region "Property - Length Readonly"
public static readonly DependencyProperty LengthProperty = DependencyProperty.Register("Length", typeof(int), typeof(ImageSlider), new PropertyMetadata(0));
public int Length
{
get { return (int)GetValue(LengthProperty); }
private set { SetValue(LengthProperty, value); }
}
#endregion
#region "Property - Begin Delay Readonly"
public static readonly DependencyProperty BeginDelayProperty = DependencyProperty.Register("BeginDelay", typeof(double), typeof(ImageSlider), new PropertyMetadata(5000.00));
public double BeginDelay
{
get { return (double)GetValue(BeginDelayProperty); }
set { SetValue(BeginDelayProperty, value); }
}
#endregion
#region "Property - Animation Duration Readonly"
public static readonly DependencyProperty AnimationDurationProperty = DependencyProperty.Register("AnimationDuration", typeof(double), typeof(ImageSlider), new PropertyMetadata(900.00));
public double AnimationDuration
{
get { return (double)GetValue(AnimationDurationProperty); }
set { SetValue(AnimationDurationProperty, value); }
}
#endregion
#region "Property - Images"
public static readonly DependencyProperty ImagesProperty = DependencyProperty.Register("Images", typeof(List<SliderImage>), typeof(ImageSlider), new PropertyMetadata(null));
public List<SliderImage> Images
{
get { return (List<SliderImage>)GetValue(ImagesProperty); }
set { SetValue(ImagesProperty, value); }
}
#endregion
#endregion
public ImageSlider()
{
InitializeComponent();
}
/// <summary>
/// This Start method used begin the animation
/// </summary>
public void Start()
{
if (this.Images != null)
{
this.Length = this.Images.Count;
hidePrevious(imageViewOne);
showNext(imageViewTwo);
}
else
{
MessageBox.Show("Please add atleast two images");
}
}
#region "Animation methods"
private void showNext(Image imageView)
{
TranslateTransform trans = imageView.RenderTransform as TranslateTransform;
DoubleAnimation animation = new DoubleAnimation();
animation.To = POSITION_TO0;
animation.Duration = TimeSpan.FromMilliseconds(this.AnimationDuration);
animation.From = POSITION_FROM480;
animation.BeginTime = TimeSpan.FromMilliseconds(this.BeginDelay);
Storyboard.SetTarget(animation, trans);
Storyboard.SetTargetProperty(animation, new
PropertyPath(TranslateTransform.XProperty));
// Create storyboard, add animation, and fire it up!
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
Canvas.SetZIndex(imageView, UPPER_ZINDEX);
imageView.Visibility = Visibility.Visible;
if (nextImage > this.Length)
{
nextImage = 1;
}
BitmapImage nextBitmapImage = new BitmapImage(new Uri(this.Images[nextImage-1].Path, UriKind.Relative));
imageView.Source = nextBitmapImage;
nextImage++;
}
private void hidePrevious(Image imageView)
{
TranslateTransform trans = imageView.RenderTransform as TranslateTransform;
DoubleAnimation animation = new DoubleAnimation();
animation.To = - POSITION_FROM480;
animation.Duration = TimeSpan.FromMilliseconds(this.AnimationDuration);
animation.From = POSITION_TO0;
animation.BeginTime = TimeSpan.FromMilliseconds(this.BeginDelay);
Storyboard.SetTarget(animation, trans);
Storyboard.SetTargetProperty(animation, new
PropertyPath(TranslateTransform.XProperty));
// Create storyboard, add animation, and fire it up!
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
animation.Completed += hideAnimation_Completed;
}
private void hideAnimation_Completed(object sender, EventArgs e)
{
if (Canvas.GetZIndex(imageViewOne) > Canvas.GetZIndex(imageViewTwo))
{
Canvas.SetZIndex(imageViewOne, LOWER_ZINDEX);
hidePrevious(imageViewOne);
showNext(imageViewTwo);
}
else
{
Canvas.SetZIndex(imageViewTwo, LOWER_ZINDEX);
hidePrevious(imageViewTwo);
showNext(imageViewOne);
}
}
#endregion
}
}
Ctrl + B , Just build once
SliderImage.cs -- Add new class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ImageSliderDemo
{
public class SliderImage
{
public string Name { get; set; }
public string Path { get; set; }
public SliderImage(string name, string path)
{
this.Name = name;
this.Path = path;
}
}
}
then do this steps
MainPage.xaml
add at top of xaml page xmlns:local="clr-namespace:[YOUR_PROJECT_NAMESPACE]"
then add just add this below in xaml
<local:ImageSlider x:Name="imageSlider"/>
MainPage.xaml.cs load images
List<SliderImage> images = new List<SliderImage>();
images.Add(new SliderImage("One", "Images/1.png"));
images.Add(new SliderImage("Two", "Images/2.png"));
images.Add(new SliderImage("Three", "Images/3.png"));
images.Add(new SliderImage("Four", "Images/4.png"));
imageSlider.Images = images;
imageSlider.Start();
Note : I used ImageSliderDemo as my namespace. If your using different please make sure you updated in user control as well. And I found only first time it is show same image twice. you can change the logic in ImageSlider.xaml.cs file

Related

StrokeStartLineCap not set when PathGeometry is bound

XAML produces the expected result: a line with rounded ends.
However, data binding the same PathGeometry produces flat ends. I'm not sure why this is, can anyone explain?
Here is a simplified example:
XAML:
<Grid>
<Path Fill="Green" Stroke="Black" StrokeThickness="8"
Stretch="None" IsHitTestVisible="False"
Data="{Binding IndicatorGeometry}"
StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
<!--<Path Fill="Green" Stroke="Black" StrokeThickness="8"
Stretch="None" IsHitTestVisible="False"
StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="64,64">
<LineSegment Point="128,8"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>-->
</Grid>
C#:
private static PathFigure[] ms_figure = new []
{
new PathFigure(
new Point(64, 64),
new[]
{
new LineSegment(new Point(128, 8), false)
},
true)
};
public PathGeometry IndicatorGeometry
{
get { return (PathGeometry)GetValue(IndicatorGeometryProperty); }
set { SetValue(IndicatorGeometryProperty, value); }
}
public static readonly DependencyProperty IndicatorGeometryProperty =
DependencyProperty.Register("IndicatorGeometry", typeof(PathGeometry), typeof(MainWindow),
new FrameworkPropertyMetadata(new PathGeometry(ms_figure)));
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
If you compare the Geometry created by the XAML to the one created in code behind, then they are different.
The code-behind one has a number of differences...it uses "z" to close the Path, while your XAML one doesn't...also one had a PathFigureCollection the other didn't....also it set the freezable property to true.
You need to try and build the one in the code-behind to be the same as the XAML produced one...it seems like its a lot of work to build the Geometry to match.
I've come up with an alternative way to build the Geometry which works...hopefully this helps in your case.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private static Geometry m_DefaultIndicatorGeometry = Geometry.Parse("M 64,64 L 128,8");
public Geometry IndicatorGeometry
{
get { return (Geometry)GetValue(IndicatorGeometryProperty); }
set { SetValue(IndicatorGeometryProperty, value); }
}
public static readonly DependencyProperty IndicatorGeometryProperty =
DependencyProperty.Register("IndicatorGeometry", typeof(Geometry), typeof(MainWindow),
new FrameworkPropertyMetadata(m_DefaultIndicatorGeometry));
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}
}
You could alternatively just use a string as the property, because the Data property has a TypeConverter to convert a string that describes a Path using the Path Markup Syntax into a Geometry.
public partial class MainWindow : Window
{
private static string m_DefaultIndicatorGeometry = "M 64,64 L 128,8";
public string IndicatorGeometry
{
get { return (string)GetValue(IndicatorGeometryProperty); }
set { SetValue(IndicatorGeometryProperty, value); }
}
public static readonly DependencyProperty IndicatorGeometryProperty =
DependencyProperty.Register("IndicatorGeometry", typeof(string), typeof(MainWindow),
new FrameworkPropertyMetadata(m_DefaultIndicatorGeometry));
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}

Connect a line between two ellipses

I'm trying to connect a line between two ellipses where if one was dragged the line would move with it. I have a canvas and inside that are two stackpanels... in each stackpanel is an ellipse on the left... content control in the middle... and another ellipse on the right. The idea is to connect a line between the right ellipse from one stackpanel to the left ellipse in the second stackpanel. So far I have this but can't seem to get much farther as the propertypath being used to do the binding doesn't make too much sense to me... which is why I have a Canvas in there right now.
Line line = new Line();
line.Stroke = connectedEllipse.Fill;
line.StrokeThickness = 2;
Binding x1 = new Binding();
Binding x2 = new Binding();
Binding y1 = new Binding();
Binding y2 = new Binding();
x1.Path = new PropertyPath(Canvas.LeftProperty);
x2.Path = new PropertyPath(Canvas.LeftProperty);
y1.Path = new PropertyPath(Canvas.TopProperty);
y2.Path = new PropertyPath(Canvas.TopProperty);
x1.Source = y1.Source = connectedEllipse;
x2.Source = y2.Source = (sender as Ellipse);
line.SetBinding(Line.X1Property, x1);
line.SetBinding(Line.X2Property, x2);
line.SetBinding(Line.Y1Property, y1);
line.SetBinding(Line.Y2Property, y2);
Ok I've hacked up some code which doesn't use the attached properties method. This probably isn't "good" code since I wrote it up in 20 minutes but it will get you started.
MainWindow.xaml
<Window x:Class="EllipseTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:EllipseTest"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" >
<Window.Resources>
<ControlTemplate x:Key="template1">
<Ellipse Width="60" Height="30" Fill="Blue" />
</ControlTemplate>
</Window.Resources>
<Canvas Name="canvas">
<my:ExtendedThumb x:Name="thumb1" Canvas.Left ="0" Canvas.Top="0" DragDelta="myThumb_DragDelta" Template="{StaticResource template1}" />
<my:ExtendedThumb x:Name="thumb2" Canvas.Left ="50" Canvas.Top="20" DragDelta="myThumb_DragDelta" Template="{StaticResource template1}" />
</Canvas>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace EllipseTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Path path;
public MainWindow()
{
InitializeComponent();
}
private void myThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
ExtendedThumb thumb = e.Source as ExtendedThumb;
Canvas.SetLeft(thumb, Canvas.GetLeft(thumb) + e.HorizontalChange);
Canvas.SetTop(thumb, Canvas.GetTop(thumb) + e.VerticalChange);
if (thumb == thumb1)
UpdateLine(thumb, thumb2);
else
UpdateLine(thumb1, thumb);
}
private void UpdateLine(ExtendedThumb firstThumb, ExtendedThumb secondThumb)
{
double left1 = Canvas.GetLeft(firstThumb);
double top1 = Canvas.GetTop(firstThumb);
double left2 = Canvas.GetLeft(secondThumb);
double top2 = Canvas.GetTop(secondThumb);
thumb1.ConnectingLine.StartPoint = new Point(left1 +firstThumb.ActualWidth / 2, top1 + firstThumb.ActualHeight / 2);
thumb1.ConnectingLine.EndPoint = new Point(left2 + secondThumb.ActualWidth / 2, top2 + secondThumb.ActualHeight / 2);
thumb2.ConnectingLine.StartPoint = new Point(left2 + secondThumb.ActualWidth / 2, top2 + secondThumb.ActualHeight / 2);
thumb2.ConnectingLine.EndPoint = new Point(left1 + firstThumb.ActualWidth / 2, top1 + firstThumb.ActualHeight / 2);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
path = new Path();
path.Stroke = Brushes.Black;
path.StrokeThickness = 2;
canvas.Children.Add(path);
LineGeometry line = new LineGeometry();
path.Data = line;
thumb1.ConnectingLine = line;
thumb2.ConnectingLine = line;
UpdateLine(thumb1, thumb2);
}
}
}
ExtendedThumb.cs
using System;
using System.Collections.Generic;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Linq;
using System.Text;
namespace EllipseTest
{
public class ExtendedThumb : Thumb
{
public LineGeometry ConnectingLine { get; set; }
public ExtendedThumb() : base() { ConnectingLine = new LineGeometry(); }
}
}
Also, I got the idea from the contents of this link: http://denisvuyka.wordpress.com/2007/10/13/wpf-draggable-objects-and-simple-shape-connectors/

WPF Multi-touch tracking touch points

I'm trying to do a simple application that, when a user touchs a screen, app creates simple point, ellipse, or sth 2d object, and when user moves his finger it should follow, but also when there is a scond touch at the same time new object also has to be created and do the same thing with respect to users movement. Whenever user fingersup, object will be deleted.
To do this, I'm trying to change the touchdrawing code from this link http://www.cookingwithxaml.com/recipes/wpf4/wpf4touch.zip but I couldn't figure out which method should I need to change ?
Can you give advice about that please ?
Thanks.
Here is some sample xaml/C# code that does what I think you want:
MainWindow.xaml:
<Window x:Class="MultitouchExperiments.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Canvas
x:Name="TouchCanvas"
TouchDown="TouchCanvas_TouchDown" TouchUp="TouchCanvas_TouchUp"
TouchMove="TouchCanvas_TouchMove" TouchLeave="TouchCanvas_TouchLeave"
TouchEnter="TouchCanvas_TouchEnter"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Background="Black"
IsManipulationEnabled="True" />
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
namespace MultitouchExperiments
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Dictionary<TouchDevice, Ellipse> _Followers = new Dictionary<TouchDevice, Ellipse>();
public MainWindow()
{
InitializeComponent();
}
private void TouchCanvas_TouchDown(object sender, TouchEventArgs e)
{
TouchCanvas.CaptureTouch(e.TouchDevice);
Ellipse follower = new Ellipse();
follower.Width = follower.Height = 50;
follower.Fill = Brushes.White;
follower.Stroke = Brushes.White;
TouchPoint point = e.GetTouchPoint(TouchCanvas);
follower.RenderTransform = new TranslateTransform(point.Position.X, point.Position.Y);
_Followers[e.TouchDevice] = follower;
TouchCanvas.Children.Add(follower);
}
private void TouchCanvas_TouchUp(object sender, TouchEventArgs e)
{
TouchCanvas.ReleaseTouchCapture(e.TouchDevice);
TouchCanvas.Children.Remove(_Followers[e.TouchDevice]);
_Followers.Remove(e.TouchDevice);
}
private void TouchCanvas_TouchMove(object sender, TouchEventArgs e)
{
if (e.TouchDevice.Captured == TouchCanvas)
{
Ellipse follower = _Followers[e.TouchDevice];
TranslateTransform transform = follower.RenderTransform as TranslateTransform;
TouchPoint point = e.GetTouchPoint(TouchCanvas);
transform.X = point.Position.X;
transform.Y = point.Position.Y;
}
}
private void TouchCanvas_TouchLeave(object sender, TouchEventArgs e)
{
//Debug.WriteLine("leave " + e.TouchDevice.Id);
}
private void TouchCanvas_TouchEnter(object sender, TouchEventArgs e)
{
//Debug.WriteLine("enter " + e.TouchDevice.Id);
}
}
}

observable collection not getting updated on UI change

I am trying to bind an observable collection to a user control but it is not getting updated on user change but it is getting updated when the user control is changed through code. Following is an example i tried. It might be a bit long but it is working so you can copy and paste the code as it is.
Please see my question at the end of the post.
--Customer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace TestMVVM
{
class Customer : INotifyPropertyChanged
{
private string firstName;
private string lastName;
public string FirstName
{
get { return firstName; }
set
{
if (firstName != value)
{
firstName = value;
RaisePropertyChanged("FirstName");
}
}
}
public string LastName
{
get { return lastName; }
set
{
if (lastName != value)
{
lastName = value;
RaisePropertyChanged("LastName");
}
}
}
#region PropertChanged Block
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(property));
}
}
#endregion
}
}
--UCTextBox.xaml
<UserControl x:Class="TestMVVM.UCTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="40" Width="200">
<Grid>
<TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="txtTextControl"
VerticalAlignment="Top" Width="120" />
</Grid>
--UCTextBox.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace TestMVVM
{
///
/// Interaction logic for UCTextBox.xaml
///
public partial class UCTextBox : UserControl, INotifyPropertyChanged
{
public UCTextBox()
{
InitializeComponent();
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(UCTextBox),
new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(textChangedCallBack)));
static void textChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
UCTextBox pasTextBox = (UCTextBox)property;
pasTextBox.txtTextControl.Text = (string)args.NewValue;
}
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
NotifyPropertyChanged("Text");
}
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
-- Window1.xaml
<Window x:Class="TestMVVM.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestMVVM"
Title="Window1" Height="300" Width="300">
<Grid>
<local:UCTextBox x:Name="txtUC" />
<Button Height="23" HorizontalAlignment="Left" Margin="39,0,0,82"
Name="btnUpdate" VerticalAlignment="Bottom" Width="75" Click="btnUpdate_Click">Update</Button>
<Button Height="23" Margin="120,0,83,82" Name="btnChange" VerticalAlignment="Bottom" Click="btnChange_Click">Change</Button>
</Grid>
-- Window1.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
namespace TestMVVM
{
///
/// Interaction logic for Window1.xaml
///
public partial class Window1 : Window
{
CustomerHeaderViewModel customerHeaderViewModel = null;
public Window1()
{
InitializeComponent();
customerHeaderViewModel = new CustomerHeaderViewModel();
customerHeaderViewModel.LoadCustomers();
txtUC.DataContext = customerHeaderViewModel.Customers[0];
Binding binding = new Binding();
binding.Source = customerHeaderViewModel.Customers[0];
binding.Path = new System.Windows.PropertyPath("FirstName");
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
txtUC.SetBinding(UCTextBox.TextProperty, binding);
}
private void btnUpdate_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(customerHeaderViewModel.Customers[0].FirstName);
}
private void btnChange_Click(object sender, RoutedEventArgs e)
{
txtUC.Text = "Tom";
}
}
class CustomerHeaderViewModel
{
public ObservableCollection Customers { get; set; }
public void LoadCustomers()
{
ObservableCollection customers = new ObservableCollection();
customers.Add(new Customer { FirstName = "Jim", LastName = "Smith", NumberOfContracts = 23 });
Customers = customers;
}
}
}
When i run the Window1.xaml my user control shows the data as "Jim". Now when i change the text to say "John" and click on Update, the messagebox still shows "Jim" that means the observable collection is not getting updated. When i click on Change button the user control changes the data to "Tom". Now when i click on Update button the Messagebox shows "Tom". Can anyone please tell me how to achieve the updation of observable collection by changing the data in user control rather than through code?
That's because you're not handling the txtTextControl.TextChanged event, so your Text dependency property is never updated.
Anyway, you don't need to handle that manually with a DependencyPropertyChangedCallback and an event handler, you can just bind the txtTextControl.Text to the Text dependency property :
<TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="txtTextControl"
VerticalAlignment="Top" Width="120"
Text="{Binding Path=Text, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:UCTextBox}}}"/>
An observable collection, observers the collection only. You will get notified when items are added or deleted not when fields of a single items did change. That is something completely different. Like Thomas Levesque said, you just need to bind the right property.

XAML page Flip twist

I have this Page.xaml
<UserControl x:Class="SLBookDemoApp.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SLMitsuControls;assembly=SLMitsuControls"
Width="800" Height="600" Loaded="UserControl_Loaded">
<Grid>
<local:UCBook x:Name="book" Margin="50" />
</Grid>
</UserControl>
And the correspondent Page.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SLMitsuControls;
namespace SLBookDemoApp
{
public partial class Page : UserControl, IDataProvider
{
public Page()
{
InitializeComponent();
}
private List<Grid> pages;
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
/*
pages = new List<Button>
{
new Button { Content = "Page 0"},
new Button { Content = "Page 1", Background = new SolidColorBrush(Colors.Green) },
new Button { Content = "Page 2", Background = new SolidColorBrush(Colors.Yellow) },
new Button { Content = "Page 3", Background = new SolidColorBrush(Colors.Brown) },
new Button { Content = "Page 4", Background = new SolidColorBrush(Colors.Magenta) },
new Button { Content = "Page 5", Background = new SolidColorBrush(Colors.Red) }
};
*/
System.Windows.Application.LoadComponent(this, new System.Uri("/SLBookDemoApp;PagTeste2.xaml", System.UriKind.Relative));
Grid LayoutRoot = ((Grid)(FindName("LayoutRoot")));
//TextBlock testTextBlock = ((TextBlock)(FindName("testTextBlock")));
pages = new List<Grid>
{
};
pages.Add(LayoutRoot);
/*
int i = 0;
foreach (var b in pages)
{
if (i % 2 == 0)
b.Click += Button_Click;
else
b.Click += Button_Click_1;
i++;
}
*/
book.SetData(this);
}
#region IDataProvider Members
public object GetItem(int index)
{
return pages[index];
}
public int GetCount()
{
return pages.Count;
}
#endregion
private void Button_Click(object sender, RoutedEventArgs e)
{
book.AnimateToNextPage(500);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
book.AnimateToPreviousPage(500);
}
}
}
And the XAML I wnat to include is this PagTeste2.xaml
<Grid
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SLBookDemoApp.PagTeste2"
x:Name="LayoutRoot">
<Rectangle Width="192" Height="80" Fill="#FF8F0A0A" Stroke="#FF000000" Canvas.Left="224" Canvas.Top="104"/>
</Grid>
With the correspondent PagTeste2.xaml.cs
using System;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
//using System.Windows.Navigation;
using SLMitsuControls;
namespace SLBookDemoApp
{
public partial class PagTeste2
{
public PagTeste2()
{
this.InitializeComponent();
// Insert code required on object creation below this point.
}
}
}
I am getting an error on this line
System.Windows.Application.LoadComponent(this, new System.Uri("/SLBookDemoApp;PagTeste2.xaml", System.UriKind.Relative));
Anyone knows why ?
Use this instead:
this.Content = new PagTeste2();
You only have to do any sort of assembly loading if you're loading content from a different assembly and even then you wouldn't use it to set content.
If you're actually asking how do you dynamically load an assembly, MS have an example of how.
You may want to try /SLBookDemoApp;component/PageTeste2.xaml.
If PagTeste2.xaml is at the top-level folder of your project you can load it using this code:
Application.LoadComponent(
this,
new System.Uri(
"/SLBookDemoApp;component/PagTeste2.xaml",
System.UriKind.Relative
)
);
If you have placed PagTeste2.xaml in a subfolder inside your project (say folder Tests) you need to include the path to the file in the uri:
Application.LoadComponent(
this,
new System.Uri(
"/SLBookDemoApp;component/Tests/PagTeste2.xaml",
System.UriKind.Relative
)
);
Also, pay close attention to spelling. PagTest2.xaml is different from PageTeste2.xaml and PageTest2.xaml. Apparently Test is inserted before the e in Page.
You can read more about pack URI's on MSDN.

Resources