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.
Related
<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
I have a listbox in my MainUI. I add Item to it by below code:
for (int i = 0; i < 50; i++) {
ListBoxItem sub1 = new ListBoxItem();
if (i % 2 == 0) {
sub1.Foreground = Brushes.Red;
} else {
sub1.Foreground = Brushes.Green;
}
sub1.Content = i;
this.listStatus.Items.Add(sub1);
}
After that i want to save that values to file with red and green color.
I try to write them to .doc file buy i can only get black characters by below code:
int lisboxcounter = 0;
FileStream fs = new FileStream(#"D:\Test.doc", FileMode.OpenOrCreate);
StreamWriter s = new StreamWriter(fs);
while (this.listStatus.Items.Count > lisboxcounter) {
s.WriteLine(this.listStatus.Items[lisboxcounter].ToString());
lisboxcounter++;
}
s.Close();
fs.Close();
and values with System.Windows.Controls.ListBoxItem: 0.
How can i write value only have ; 0,1,2,3 ... with red and green color?
thanks a lot.
Your best bet is to write to an RichTextBox and then save the contents to an RTF file.
XAML
<StackPanel Orientation="Horizontal"
Grid.Row="0">
<Button Width="80"
Content="Load"
Name="_loadButton"
Click="_loadButton_Click" />
<Button Width="80"
Content="Save"
Name="_saveButton"
Click="_saveButton_Click" />
</StackPanel>
<RichTextBox Grid.Row="1" Name="_rtfBox" VerticalScrollBarVisibility="Auto" />
</Grid>
Code-behind
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.IO;
using System.Diagnostics;
namespace SaveAsRtf
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void _loadButton_Click(object sender, RoutedEventArgs e)
{
var newDoc = new FlowDocument();
for (int i = 0; i < 50; i++)
{
Paragraph newPara = new Paragraph();
if (i % 2 == 0)
{
newPara.Foreground = Brushes.Red;
}
else
{
newPara.Foreground = Brushes.Green;
}
newPara.Inlines.Add(new Run(i.ToString()));
newDoc.Blocks.Add(newPara);
}
_rtfBox.Document = newDoc;
}
private void _saveButton_Click(object sender, RoutedEventArgs e)
{
string temp = System.IO.Path.GetTempFileName() + ".rtf";
using (FileStream fs = File.Create(temp))
{
TextRange text = new TextRange(_rtfBox.Document.ContentStart, _rtfBox.Document.ContentEnd);
text.Save(fs, DataFormats.Rtf);
}
Process.Start(temp);
}
}
}
I am trying to open HTML file in WebBrowser window of WPF using MVVM patten.
Note: I have fixed the issues i was getting. Now this code works as desired.
ViewHTMLPageView.xaml
<Window x:Class="MyProject.ViewHTMLPageView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyProject.Utility"
Title="HTML Report" Height="454" Width="787"
>
<Grid Name="grid1">
<WebBrowser local:WebBrowserUtility.BindableSource="{Binding ReportPage}" />
</Grid>
</Window>
ViewHTMLPageViewModel.cs
namespace MyProject
{
public class ViewHTMLPageViewModel: ViewModelBase
{
public ViewHTMLPageView()
{
//Testing html page on load
_reportPage = "<table border='5'><tr><td> This is sample <b> bold </b></td></tr></table>";
OnPropertyChanged("ReportPage");
}
private string _reportPage;
public string ReportPage
{
get
{
return _reportPage;
}
set
{
if (_reportPage != value)
{
_reportPage = value;
OnPropertyChanged("ReportPage");
}
}
}
}
WebBrowserUtility.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
namespace MyProject.Utility
{
public static class WebBrowserUtility
{
public static readonly DependencyProperty BindableSourceProperty =
DependencyProperty.RegisterAttached("BindableSource", typeof(string),
typeof(WebBrowserUtility), new UIPropertyMetadata(null,
BindableSourcePropertyChanged));
public static string GetBindableSource(DependencyObject obj)
{
return (string)obj.GetValue(BindableSourceProperty);
}
public static void SetBindableSource(DependencyObject obj, string value)
{
obj.SetValue(BindableSourceProperty, value);
}
public static void BindableSourcePropertyChanged(DependencyObject o,
DependencyPropertyChangedEventArgs e)
{
var webBrowser = (WebBrowser)o;
webBrowser.NavigateToString((string)e.NewValue);
}
}
}
In WebBrowserUtility.cs, change the following statement:
using System.Windows.Forms;
to
using System.Windows.Controls;
Now, for +1 on your question, can you tell me why this fixes your problem?
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);
}
}
}
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.