Caliburn.micro and a usercontrol click handler - c#

I have created a very simple user control, an ImageButton
<UserControl x:Class="SampleApp.Controls.ImageButton"
Name="ImageButtonControl"
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"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Button>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="6*" />
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Image Grid.Row="1" Source="{Binding ElementName=ImageButtonControl, Path=Image}" VerticalAlignment="Stretch" HorizontalAlignment="Center" />
<TextBlock Grid.Row="2" Text="{Binding ElementName=ImageButtonControl, Path=Text}" VerticalAlignment="Stretch" HorizontalAlignment="Center" />
</Grid>
</Button>
</UserControl>
With code behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace SampleApp.Controls
{
/// <summary>
/// Interaction logic for ImageButton.xaml
/// </summary>
public partial class ImageButton : UserControl
{
public ImageButton()
{
InitializeComponent();
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ImageButton), new UIPropertyMetadata(""));
public ImageSource Image
{
get { return (ImageSource)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
public static readonly DependencyProperty ImageProperty =
DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageButton), new UIPropertyMetadata(null));
}
}
Now I want to use that in my little sample application like
xmlns:controls="clr-namespace:SampleApp.Controls"
<controls:ImageButton Grid.Row="1"
Grid.Column="1"
Margin="2"
Image="/Images/link.png"
Text="DoSomething">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="DoSomething" />
</i:EventTrigger>
</i:Interaction.Triggers>
</controls:ImageButton>
If I give it a x:Name, like
<controls:ImageButton x:Name="DoSomething"
e.g. DoSomething the method DoSomething with that name is directly called when the view is shown, i.e. when I active the viewmodel that contains that button, just like I click the Button (if it was a normal button and not a usercontrol, it would work that way), but the button-click handler is never called on clicking.
Now I tried to add an ActionMessage as seen above, but it does not work either...
What is wrong here?

That's because there is no convention configured for your user control type. You could either add a convention via the ConventionManager (see http://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Conventions), or you could derive your type from Button instead.
You could also not use a custom user control and instead just add the image to the Content property of the Button in your view.

Related

get child nodes of node WPF

I have created this UserControl
public partial class Dropdown : UserControl
{
public string Title { get; set; } = string.Empty;
private void loadSuccess(object sender, RoutedEventArgs e)
{
TitleBlock.Text = Title;
}
public Dropdown()
{
Loaded += loadSuccess;
InitializeComponent();
}
}
<UserControl x:Class="Lamprey.UserControls.Dropdown"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Lamprey.UserControls"
mc:Ignorable="d"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="17"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text=">" Grid.Row="0" Grid.Column="0" Foreground="#FFC7C7C7"></TextBlock>
<TextBlock x:Name="TitleBlock" Grid.Row="0" Grid.Column="1"></TextBlock>
<ListBox x:Name="Items" Grid.Column="1" Grid.Row="1" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</UserControl>
It is meant to be used like this
<usercontrols:Dropdown Title="History">
<ListBoxItem>
<TextBlock>Example</TextBlock>
</ListBoxItem>
</usercontrols:Dropdown>
I am trying to figure out how I can get a list of children of the <Dropdown> so I can move them into the Items <ListBox>.
The end goal is for any children addded to <Dropdown> to be automatically added to the <ListBox> named Items. That way, the entire listbox can be hidden when the dropdown is closed, and shown when the dropdown is opened.
The key is to define a collection dependency property and bind it to the ListBox. This property must be declared as the control's content property in order to be able to add items to it implicitly in XAML.
Define a custom non-generic collection or use an existing one
DropDownItemCollection.cs
public class DropDownItemCollection : List<object>
{ }
Define a dependency property of the non-generic collection type
Declare this property as the content property using the ContentProperty attribute to decorate the property owner
Optionally, define a DataTemplate type property e.g., ItemTemplate to allow templating the items using an explicit DataTemplate
DropDown.xaml.cs
[ContentProperty(nameof(DropDown.DropDownItems))]
public partial class DropDown : UserControl
{
public DropDownItemCollection DropDownItems
{
get => (DropDownItemCollection)GetValue(DropDownItemsProperty);
set => SetValue(DropDownItemsProperty, value);
}
public static readonly DependencyProperty DropDownItemsProperty =
DependencyProperty.Register(
"DropDownItems",
typeof(DropDownItemCollection),
typeof(DropDown),
new PropertyMetadata(default));
public DataTemplate ItemTemplate
{
get => (DataTemplate)GetValue(ItemTemplateProperty);
set => SetValue(ItemTemplateProperty, value);
}
public static readonly DependencyProperty ItemTemplateProperty =
DependencyProperty.Register(
"ItemTemplate",
typeof(DataTemplate),
typeof(DropDown),
new PropertyMetadata(default));
public DropDown()
{
InitializeComponent();
this.DropDownItems = new DropDownItemCollection();
}
}
Bind the internal ListBox to the new DropDownItems property
DropDown.xaml
<UserControl>
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DropDownItems}"
ItemTemplate="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ItemTemplate}" />
</UserControl>
Example
<!--
Since the collection is of type object you can add anything to the collection.
The ItemTemplate property allows to explicitly template the item layout.
-->
<Window>
<Window.Resources>
<DataTemplate x:Key="DroptDownItemTemplate">
<Grid>
<Border Background="OrangeRed" />
<TextBlock Text="{Binding}" />
</Grid>
</DataTemplate>
</Window.Resources>
<DropDown ItemTemplate={StaticResource DroptDownItemTemplate}">
<sys:String>Item 1</sys:String>
<sys:String>Item 2</sys:String>
</DropDown>
</Window>
Remarks
You can skip all this when extending ListBox instead of UserControl. Doing so, your control will support item creation in XAML and templating out of the box.
Hiding and showing the internal ListBox will lead to changes in the layout and therfore result in ugly content resizing. You should consider to host the ListBox (or in case of extending ListBox the ItemsPresenter) inside a Popup to create the flyout that overlays instead of resizing.

Can't make my DependencyProperty work as I expected [duplicate]

This question already has answers here:
Callback when dependency property recieves xaml change
(2 answers)
Closed 4 years ago.
I have a very simple User Control which displays a waiting animation with a text above:
<UserControl x:Class="VNegoceNET.Controls.PleaseWait"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VNegoceNET.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="RootElement" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.RowSpan="3" Background="White" Content="" Opacity="0.8"/>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"
Grid.Row="0" FontSize="18" Foreground="Black"
Margin="8" x:Name="Caption" Text="Loading..."/>
<local:SpinningWait Grid.Row="1"/>
</Grid>
</UserControl>
I want to use it like this:
<controls:PleaseWait Text="Jegg Robot"/>
My problem is that it still displays "Loading..." instead of "Jegg Robot", despite my Dependency Property:
public partial class PleaseWait : UserControl
{
public PleaseWait()
{
InitializeComponent();
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof(String), typeof(PleaseWait), new PropertyMetadata("Loading in progress..."));
public string Text
{
get => (string)this.GetValue(TextProperty);
set
{
Caption.Text = value;
this.SetValue(TextProperty, value);
}
}
}
What I have missed?
WPF doesn't use common property wrappers for DP (public string Text), it uses SetValue() directly, when property is set from xaml (<controls:PleaseWait Text="Jegg Robot"/>). so code in setter isn't invoked.
What is needed is propertyChangedCallback:
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(String), typeof(PleaseWait),
new PropertyMetadata("Loading in progress...", OnTextChanged));
public string Text
{
get => (string)this.GetValue(TextProperty);
set { this.SetValue(TextProperty, value); }
}
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var c = (PleaseWait) d;
c.Caption.Text = c.Text;
}
Instead of using a PropertyChangedCallback, like ASh mentioned, you can bind the TextProperty of your TextBlock
...
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"
Grid.Row="0" FontSize="18" Foreground="Black"
Margin="8" x:Name="Caption" Text="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:PleaseWait}}}"/>
...

Save ObservableCollection to textfile when closing MainWindow

I'm realtivley new to C# and WPF and have gotten the task to program an Alarm. Now I have the problem, that I have to save the set times to a textfile when closing the mainwindow.
The times are stored in an ObservableCollection of the type Reminder, a class i wrote myself and stores the time and name of the alarm as string.
public override string ToString()
{
return ReminderName + " " + ReminderTime.ToString("HH:mm");
}
My saving function looks like this:
...
public RelayCommand<object> SaveAllTimes { get; set; }
...
public MainWindowModel()
{
...
SaveAllTimes = new RelayCommand<object>(SaveReminders, CanSaveReminders);
...
}
private void SaveReminders(object sender)
{
StreamWriter writer = new StreamWriter("time.txt");
foreach (Reminder time in Reminders)
{
writer.WriteLine(time.ToString());
}
}
Now how can I bind the view to this function, that it's executed when the user closes it?
My view looks like this:
<Window x:Class="Wecker1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Wecker1"
Height="350"
Width="310" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="3*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<ListBox Name="Liste" ItemsSource="{Binding Reminders}" Margin="10" Grid.Row="0">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" IsChecked="{Binding Active}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Button Command="{Binding SaveTime}" Content="Add Reminder" Margin="10" Grid.Column="1"/>
<Button Margin="10" Content="Stop" Command="{Binding DeleteTime}"
CommandParameter="{Binding ElementName=Liste,Path=SelectedItem}" />
</Grid>
</Grid>
</Window>
here is my approach using pure MVVM, not dependent to any other provider
xaml
<Window x:Class="CSharpWPF.ViewModel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:CSharpWPF"
l:MyEventHandler.ClosingCommand="{Binding SaveAllTimes}">
</Window>
MyEventHandler class
namespace CSharpWPF
{
public class MyEventHandler
{
public static ICommand GetClosingCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(ClosingCommandProperty);
}
public static void SetClosingCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(ClosingCommandProperty, value);
}
// Using a DependencyProperty as the backing store for ClosingCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ClosingCommandProperty =
DependencyProperty.RegisterAttached("ClosingCommand", typeof(ICommand), typeof(MyEventHandler), new PropertyMetadata(OnClosingCommandChanged));
private static void OnClosingCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Window window = d as Window;
window.Closing += (s, ee) => GetClosingCommand(d).Execute(ee);
}
}
}
so the whole idea is to route the events to binded commands via Attached Properties, you may create more handlers as you need
Somewhere in your code, you are creating your View and ViewModel. From my point of view (and this part surely is opinion-based) you should implement your On-Exit code there, because your saving of data is at the end of the process, not the end of the view. When your MainWindow was run, you can call a viewmodel method to save all it's relevant data.
If you do want to have it upon closing the view instead of ending the program, you can go two paths: the dark side, by writing a code-behind OnClose handler for the window. Don't tell anyone I said so. That's not WPF style. Or the correct path by implementing a Close-Behavior for your window. That's too broad for a single post, you should look up WPF, View and Behavior, you will find lots of tutorials for different behaviors.
You can use interactivity to bind Closing event to your Command like below
<Window xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding SaveAllTimes }"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Window>

WPF "Cannot find source for binding" with ContentPresenters, and UserControl

I have a:
System.Windows.Data Error: 4 : Cannot find source for binding with
reference 'ElementName=Test'. BindingExpression:Path=Value;
DataItem=null; target element is 'Slider' (Name=''); target property
is 'Value' (type 'Double')
error in a very special case.
I though about a name scope problem but I don't know how to fix it.
Consider the following WPF application :
MyUserControl.xaml:
<UserControl x:Class="WpfApplication1.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Move me !"/>
<Slider x:Name="Test" Grid.Row="0" Grid.Column="1" />
<Label Grid.Row="1" Content="Binded slider"/>
<ContentPresenter Grid.Row="1" Grid.Column="1">
<ContentPresenter.Content>
<Slider Value="{Binding Value, ElementName=Test}"/>
</ContentPresenter.Content>
</ContentPresenter>
</Grid>
</UserControl>
MyUserControl.xaml.cs:
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
}
}
MainWindow.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="300" Height="120">
<StackPanel>
<Button Click="Button_Click" Content="Click me to show Sliders !" Height="25"/>
<ContentPresenter x:Name="contentPresenter"/>
</StackPanel>
</Window>
MainWindow.xaml.cs:
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
private MyUserControl myUserControl;
public MainWindow()
{
InitializeComponent();
myUserControl = new MyUserControl();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
contentPresenter.Content = myUserControl;
}
}
}
Given the code of MyUserControl.xaml, I expect the binded slider to have the same value has the first one.
But nothing happens.
Now, the tricky part: Start the application, Click on the button, Move the first slider, Open "WPF Inspector" and Attach it to the application. Result: The binding is fixed.
How do you explain this phenomenon?
This will do the trick
<!--<ContentPresenter Grid.Row="1" Grid.Column="1">
<ContentPresenter.Content>-->
<Slider Value="{Binding Value, ElementName=Test}" Grid.Column="1" Grid.Row="1"/>
<!--</ContentPresenter.Content>
</ContentPresenter>-->
Because Slider is inside a content presenter you can't access it's value like that. You would need to bind to the same viewmodel property to achive this while having it in the content presenter.
Edit
Get Prism and user a ViewModel... I won't go into details... But What you need to do is this...
After you donwloaded everything add the Microsoft.Practices.Prism dll to your project
Create a new class (ViewModel).Name it whatever you want. I call my MyUserControlViewModel and make it look like this
using Microsoft.Practices.Prism.ViewModel;
namespace YourNamespace
{
public class MyUserControlViewModel : NotificationObject
{
private double _sliderValue;
public double SliderValue
{
get { return _sliderValue; }
set
{
_sliderValue = value;
RaisePropertyChanged(() => SliderValue);
}
}
}
}
Change the XAML in your usercontrol like this
<Slider x:Name="Test" Grid.Row="0" Grid.Column="1" Value="{Binding SliderValue, Mode=TwoWay}"/>
<ContentPresenter Grid.Row="1" Grid.Column="1">
<ContentPresenter.Content>
<Slider Value="{Binding SliderValue}"/>
</ContentPresenter.Content>
</ContentPresenter>
And add this line of code into your MyUserControl.cs file
DataContext = new MyUserControlViewModel();
Now the ViewModel takes over for the heavy lifting... You bound the value of the first slider to the Property SliderValue (the Mode=TwoWay indicates that this control can set and get the state of the property) and you have bound the other slider to the same SliderValue so that it moves in sync with the first
Hope this helps

How to create second window that shows part of main window

I have application with WPF Ribbon and Grid. And I need to show this Grid not only in main application window but also on second window. This Grid contain a lot of elements like ToggleButtons, TextBoxes, Images.
Scheme of my application code looks like that:
<ribbon:RibbonWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
[...]
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
Title="MainWindow"
x:Name="RibbonWindow"
Height="870" Width="1000">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ribbon:Ribbon x:Name="Ribbon">
[...]
</ribbon:Ribbon>
<Grid Background="#FF5C5C5C" Height="765" Width="986" Grid.Row="1" Margin="0,0,-2,-70" x:Name="MainGrid">
<ToggleButton/>
<TextBlock />
<ToggleButton/>
<Rectangle />
[...]
</Grid>
</Grid>
</ribbon:RibbonWindow>
MainGrid is the Grid that I want to show in second window. It can even be only view of this Grid. But when I change something in first window, like write something in TextBox or click on ToggleButton, I need to have it visible on second screen too.
Umm this is going to be tricky. What I would do is create a UserControl with the Grid and then put one UserControl in Window1 and another in Window2. But to synchronize the state of the Window1-Grid and the Window2-Grid you will have to bind them to the same object.
Edit: Here, cooked up an example for you
Step 1: Put the Grid into a UserControl so it can be reused.
Notice I set the UpdateSourceTrigger property on the binding to PropertyChanged, this updates the source object as the user is typing, so we will see changes in Window2 as they are happening in Window1.
CommonGrid.xaml
<UserControl x:Class="WindowSync.CommonGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="5">
<TextBlock Text="Name: " />
<TextBox Width="200" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="5">
<CheckBox IsChecked="{Binding IsAdmin, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text=" Is Admin" />
</StackPanel>
</Grid>
</UserControl>
Step 2: Put the UserControl into the desired windows.
Note: you have to reference the namespace that UserControl is in, in this case the namespace is WindowSync, this line lets us user the namespace xmlns:app="clr-namespace:WindowSync".
Window1.xaml
<Window x:Class="WindowSync.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WindowSync"
Title="Window 1" Height="200" Width="400">
<app:CommonGrid x:Name="Window1Grid" />
</Window>
Windo1.xaml.cs
public Window1()
{
InitializeComponent();
Window1Grid.DataContext = Person.User; // bind the UserControl in Window1 to the an object
new Window2().Show(); // create an instance of window 2 and show it
}
Window2.xaml
<Window x:Class="WindowSync.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WindowSync"
Title="Window 2" Height="200" Width="400">
<app:CommonGrid x:Name="Window2Grid" />
</Window>
Window2.xaml.cs
public Window2()
{
InitializeComponent();
Window2Grid.DataContext = Person.User; // bind the UserControl in Window2 to the same object
}
Person.cs
I just created a random object called person for the demonstration.
Note: you have to implement the INotifyPropertyChanged interface on your object, and raise the appropriate PropertyChanged event whenever something is changed, this is what let's us synchronize the two grids. Window1 changes something, the PropertyChanged event gets fired, Window2 picks it up and makes the changes.
public class Person : INotifyPropertyChanged
{
public static Person User = new Person();
#region Name
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
OnPropertyChanged("Name");
}
}
#endregion
#region IsAdmin
private bool _IsAdmin;
public bool IsAdmin
{
get { return _IsAdmin; }
set
{
_IsAdmin = value;
OnPropertyChanged("IsAdmin");
}
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
#endregion
}
Anywyas, I hope this helps you out. I uploaded a zipped version of the project if you get stuck. http://www.mediafire.com/?yv84xbben6tjdy7
Good luck.

Categories