I am learning wpf in my new project and am developing user control for game application.
Sadly, I'm facing problem in binding the behind method in the below code to the Button Command property.
Here is my code:
Codebehind:
[Command]
public void OnButtonClick(object param)
{
if (this.CustomClick != null)
this.CustomClick(this);
}
Xaml:
<ItemsControl x:Name="itemsctrlCell"
HorizontalAlignment="Center"
ItemsSource="{Binding ElementName=userctrlGameBoard, Path= Dimension,Converter={StaticResource Convert}}"
Width="Auto"
Height="Auto"
Margin="77,92,-75.2,-92.4">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border BorderThickness="1"
CornerRadius="15"
Height="Auto"
Width="Auto">
<ItemsPresenter Width="Auto"
Height="Auto"
HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Width="Auto" Height="Auto"></UniformGrid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="18"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</DataTemplate.Resources>
<WrapPanel x:Name="wrppanelCell"
Width="Auto"
Height="Auto">
<Button Name="btnCell"
Width="40"
Height="40"
FontSize="25"
FontWeight="Bold"
HorizontalContentAlignment="Right"
HorizontalAlignment="Center"
Command="{Binding ElementName=userctrlGameBoard,Path=OnButtonClick}"
CommandParameter="{Binding}">
</Button>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
How can I bind the behind method to the button command property?
Try this to create Command bindings.
In your .xaml:
<Window.Resources>
<RoutedUICommand x:Key="CloseCommand" Text=""/>
</Window.Resources>
<Window.Commandbindings>
<CommandBinding Command="{StaticResource CloseCommand}" Executed="Close" />
</Window.Commandbindings>
Your Button:
<Button Command={StaticResource CloseCommand}" />
Your .cs:
public MainConstructor()
{
InitializeComponent();
DataContext = this;
}
public void Close(Object sender, ExecutedRoutedEventArgs e)
{
// Stuff that happens in your `Close command`
}
The C# code is the code begind of this xaml file ? If yes why you want to bind ? When you do a Binding, you bind to a proprety, not to a function. You are supposed to bind your Command to a ICommand proprety. Here is what I do:
public class MyCommand : ICommand
{
#region private fields
private readonly Action execute;
private readonly Func<bool> canExecute;
#endregion
public event EventHandler CanExecuteChanged;
public MyCommand(Action execute)
: this(execute, null)
{
}
public MyCommand(Action execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public void Execute(object parameter)
{
this.execute();
}
public bool CanExecute(object parameter)
{
return this.canExecute == null ? true : this.canExecute();
}
}
Then you creat a ICommand proprety that you want to bind.
private ICommand inscription;
public ICommand Inscription
{
get
{
if (this.inscription == null)
this.inscription = new MyCommand(function_execute, function_canExecute);
return this.inscription;
}
}
The function_execute is the function that will be triger, this other one allow you to check if you want that your function_execute will be execute.
In your Xaml:
<Button Grid.Row="2" Content="Connexion" Command="{Binding Inscription}"></Button>
But if you don't do MVVM, you should just use the code behind without binding I think, I'm not an expert too lol.
Related
Can anyone tell me how to change button image when context menu Item is clicked?
I have a button with image and context menu in it. I want to change the image of the button, everytime I click contextmenu item.
With the following piece of code I am able to display contextmenu items on right click. But don't know how to proceed further.
Can anyone guide me ?
I tried using command strangely command never got called.
<Button Background="Gray" Name="statusBtn" VerticalAlignment="Top" HorizontalAlignment="Right" FontWeight="Bold" Foreground="Red">
<DockPanel >
<Image DockPanel.Dock="Top" Stretch="Fill" Source="{Binding ToEnum, Converter={StaticResource EnumToImgConverter}}" Height="37" Width="72" />
<TextBlock HorizontalAlignment="Center" Margin="0,23,1,2">Test</TextBlock>
</DockPanel>
<Button.ContextMenu>
<ContextMenu Name="ContextMenuName" ItemsSource="{Binding Path=Popuplistitems}">
<ContextMenu.ItemTemplate >
<DataTemplate DataType="MenuItem">
<MenuItem Header="{Binding Message}" Command="{Binding popupListCommand}">
<MenuItem.ItemContainerStyle >
<Style TargetType="MenuItem">
<Setter Property="IsCheckable" Value="True"/>
<Setter Property="IsChecked" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</Button.ContextMenu>
</Button>
First, I think you need to change your MenuItem.ItemContainerStyle to just MenuItem.Style - I believe the ItemContainerStyle is meant for the sub-menuitems that you can place into the MenuItem when you want nested context menus.
I was able to get the content of the button to change with the following code. I used text content, but it should be easy to swap it out for image content:
The xaml:
<Window x:Class="ChangeButtonContent.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>
<Button Height="30" Width="200">
<Button.Content>
<DockPanel >
<TextBlock Text="{Binding ChangingText, Mode=TwoWay}" />
</DockPanel>
</Button.Content>
<Button.ContextMenu>
<ContextMenu Name="ContextMenuName">
<MenuItem Command="{Binding ChangeTextCommand}" Header="ChangeText"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
</Grid>
The Code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
ChangingText = "Initial Text";
ChangeTextCommand = new MyCommand((notUsed) =>
{
ChangingText = "Text After Context Menu Click";
});
}
private string _changingText;
public string ChangingText
{
get
{
return _changingText;
}
set
{
_changingText = value;
OnPropertyChanged("ChangingText");
}
}
public MyCommand ChangeTextCommand
{
get;
private set;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MyCommand : ICommand
{
private Action<object> _action;
public MyCommand(Action<object> action)
{
_action = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action(parameter);
}
}
When i set the content of the content control like below but the binding of the element inside the content get break.
i have given a content inside a property of a class and set the property as the content to the content control.
[Xmal]
<Grid>
<Button HorizontalAlignment="Center"
VerticalAlignment="Top"
Click="Button_Click_1"
Content="Click" />
<local:MyTile x:Name="mytile">
<local:MyTile.TileViewContent>
<StackPanel>
<TextBox x:Name="text"
Background="Red"
Text="MyText" />
<TextBox Text="{Binding ElementName=text, Path=Text,Mode=TwoWay}" />
</StackPanel>
</local:MyTile.TileViewContent>
</local:MyTile>
<ContentControl x:Name="contentcontrol" />
</Grid>
[C#]
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
contentcontrol.Content = mytile.TileViewContent;
}
}
public class MyTile:Control
{
public FrameworkElement TileViewContent
{
get { return (FrameworkElement)GetValue(TileViewContentProperty); }
set { SetValue(TileViewContentProperty, value); }
}
public static readonly DependencyProperty TileViewContentProperty =
DependencyProperty.RegisterAttached("TileViewContent", typeof(FrameworkElement), typeof(MyTile), new PropertyMetadata(null));
}
When i set the content the binding not working. please help
If you want to simply binding is works, not necessarily through ContentControl, use the Style for your element:
<Window.Resources>
<Style x:Key="MyTemplateForMyControl" TargetType="{x:Type local:MyTile}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyTile}">
<StackPanel>
<TextBox x:Name="MyTextBox" Text="MyText" Background="Red" />
<TextBox Text="{Binding ElementName=MyTextBox, Path=Text}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Click" Click="Button_Click_1" />
<local:MyTile x:Name="MyTile" />
</Grid>
In code we are set the Style for your Control:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
MyTile.Style = this.Resources["MyTemplateForMyControl"] as Style;
}
If it is necessary to use ContentControl I can recommend instead of you Control use a DataTemplate:
<Window.Resources>
<DataTemplate DataType="{x:Type local:MyDataForTemplate}">
<StackPanel>
<TextBox x:Name="MyTextBox" Text="{Binding TextBoxContent}" Background="Red" />
<TextBox Text="{Binding ElementName=MyTextBox, Path=Text}" />
</StackPanel>
</DataTemplate>
<!-- Some data -->
<local:MyDataForTemplate x:Key="MyDataForTile" TextBoxContent="MyText" />
</Window.Resources>
<Grid>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Click" Click="Button_Click_1" />
<ContentControl Name="TileContentControl" />
</Grid>
There will be some data for a template:
public class MyDataForTemplate
{
string textBoxContent = "";
/// <summary>
/// Text for TextBox
/// </summary>
public string TextBoxContent
{
get
{
return textBoxContent;
}
set
{
textBoxContent = value;
}
}
}
In code we are set the data for a template:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
TileContentControl.Content = this.Resources["MyDataForTile"] as MyDataForTemplate;
}
I have a ListBox:
<ListBox Name="lbsfHolder"
ItemsSource="{Binding UISupportingFunctions}"
SelectedItem="{Binding Path=SelectedSupportedFunction, Mode=TwoWay}"
SelectionMode="Multiple"
IsSynchronizedWithCurrentItem="True"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<controls:SupportingFunction GotFocus="SupportingFunction_GotFocus"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In the ViewModel I have:
private SupportingFunction _selectedSupportedFunction;
public SupportingFunction SelectedSupportedFunction
{
get { return _selectedSupportedFunction; }
set
{
_selectedSupportedFunction = value;
NotifyPropertyChanged("SelectedSupportedFunction");
}
}
But when I'm trying to select any item in list box nothing happens. The SelectedItem is null for the ListBox and for SelectedValue, too. Do I need to add some special code to make this work?
UPD:
I've changed views a bit, now I have:
<UserControl x:Class="RFM.UI.WPF.Controls.SupportingFunction">
<Grid>
<ListBox Name="supportingFunctions"
ItemsSource="{Binding UISupportingFunctions}"
SelectedItem="{Binding Path=SelectedSupportedFunction, Mode=TwoWay}"
SelectionMode="Multiple"
IsSynchronizedWithCurrentItem="True"
HorizontalContentAlignment="Stretch">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<TextBox Name="tbsfName" Grid.Column="0" Text="{Binding Path=Title, Mode=TwoWay}"></TextBox>
<TextBox Name="tbsfExperssion" Grid.Column="1" Text="{Binding Path=Expression}" HorizontalAlignment="Stretch"></TextBox>
<Button Name="bsfDel" Grid.Column="2">Del</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</UserControl>
In Page where this control placed:
<StackPanel Name="spSupportingFunctions">
<StackPanel Name="spsfOperations" Orientation="Horizontal">
<Button Name="bsfAdd" Width="30" Command="commands:CustomCommands.AddSupportingFunction">Add</Button>
</StackPanel>
<controls:SupportingFunction DataContext="{Binding Self}" />
</StackPanel>
at code behind of this Page
public PlotDataPage()
{
DataContext = new PlotDataViewModel();
InitializeComponent();
}
and this is the full listing of PlotDataViewModel
public class UISupportingFunction : ISupportingFunction
{
public string Title { get; set; }
public string Expression { get; set; }
}
public class PlotDataViewModel : INotifyPropertyChanged
{
public PlotDataViewModel Self
{
get
{
return this;
}
}
private ObservableCollection<UISupportingFunction> _supportingFunctions;
public ObservableCollection<UISupportingFunction> UISupportingFunctions
{
get
{
return _supportingFunctions;
}
set
{
_supportingFunctions = value;
NotifyPropertyChanged("UISupportingFunctions");
}
}
private UISupportingFunction _selectedSupportedFunction;
public UISupportingFunction SelectedSupportedFunction
{
get
{
return _selectedSupportedFunction;
}
set
{
_selectedSupportedFunction = value;
NotifyPropertyChanged("SelectedSupportedFunction");
}
}
public PlotDataViewModel()
{
UISupportingFunctions = new ObservableCollection<UISupportingFunction>();
}
public void CreateNewSupportingFunction()
{
UISupportingFunctions.Add(new UISupportingFunction() { Title = Utils.GetNextFunctionName() });
}
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
public event PropertyChangedEventHandler PropertyChanged;
}
I'm just calling the CreateNewSupportingFunction() method when I click Add button. Everything looks fine - the items is add and I see them. But when I'm clicking on one of the TextBoxes and then to the bsfDel button right to each item I'm getting null in SelectedSupportedFunction.
Maybe it is because of focus event have been handling by TextBox and not by ListBox?
It's either your ItemsSource UISupportingFunctions is not a SupportingFunction object or you did not set the View's Datacontext to your ViewModel.
ViewModel.xaml.cs
this.DataContext = new ViewModelClass();
i have made a template that look like this :
<ControlTemplate x:Key="onoffValue" TargetType="{x:Type Control}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Height="20" Margin="0,5,0,0">
<RadioButton Content="On" Height="20" Name="On_radiobutton" />
<RadioButton Content="Off" Height="20" Name="Off_radiobutton" Margin="20,0,0,0" />
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=BootSector}" Value="true">
<Setter TargetName="On_radiobutton" Property="IsChecked" Value="true"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=BootSector}" Value="false">
<Setter TargetName="Off_radiobutton" Property="IsChecked" Value="true"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
For now, it is bind to the property BootSector(bool) ofa "Configuration" object.
I use this template in my window that has a configuration object as data context like this :
<Control Template="{StaticResource onoffValue}">
</Control>
It works great, but i want to go further.
I would like to know how i can pass a different property to my template to dynamically bind (dynamically change the property the template is bind to)
ie i tryed something like
<Control Template="{StaticResource onoffValue}" xmlns:test="{Binding Path=BootSector}"/>
and bind it in the template to "test" but it doesn't work
Is it possible ? How can i do that ? I think i'm not too far away but not there still !
Thank you in advance
Edit : Concerning Dmitry answer :
There is a bug using that. When i do :
<StackPanel local:ToggleControl.IsOn="{Binding BootSector, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Grid.Row="0" Grid.Column="1"
Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
<RadioButton Content="On" local:ToggleControl.Role="On" Height="20" Margin="5" />
<RadioButton Content="Off" local:ToggleControl.Role="Off" Height="20" Margin="5" />
</StackPanel>
By default BootSector is on false. When i click on the on button (true), it sets bootSector to true and then immediately to false . The behaviour should be that it stays to true until it is unchecked ? Is this related to the problem related here ? http://geekswithblogs.net/claraoscura/archive/2008/10/17/125901.aspx
Here, the idea is - generic behaviors are never complex and generally not worth creating a custom control. I undertand that implmentation may vary, but the approach will remain the same. It makes sense to use XAML for the parts which can change and code for the stuff which will remain constant.
UPDATE 1- It's getting even easier when using Custom controls. You won't need attached property no more - as you'll get a dedicated space for it inside your custom control, also, you can use x:Name and GetTemplateChild(..) to otain a reference to individual RadioButtons.
Code:
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.ComponentModel;
namespace RadioButtons
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += (o, e) =>
{
this.DataContext = new TwoBoolean()
{
PropertyA = false,
PropertyB = true
};
};
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(((TwoBoolean)this.DataContext).ToString());
}
}
public enum RadioButtonRole
{
On,
Off
}
public class ToggleControl : DependencyObject
{
public static readonly DependencyProperty IsOnProperty =
DependencyProperty.RegisterAttached("IsOn",
typeof(bool?),
typeof(ToggleControl),
new PropertyMetadata(null,
new PropertyChangedCallback((o, e) =>
{
ToggleControl.OnIsOnChanged((Panel)o, (bool)e.NewValue);
})));
public static readonly DependencyProperty RoleProperty =
DependencyProperty.RegisterAttached("Role",
typeof(RadioButtonRole?),
typeof(ToggleControl),
new PropertyMetadata(null,
new PropertyChangedCallback((o, e) =>
{
})));
private static readonly DependencyProperty IsSetUpProperty =
DependencyProperty.RegisterAttached("IsSetUp",
typeof(bool),
typeof(ToggleControl),
new PropertyMetadata(false));
private static void OnIsOnChanged(Panel panel, bool e)
{
if (!ToggleControl.IsSetup(panel))
{
ToggleControl.Setup(panel);
}
RadioButtonRole role;
if (e)
{
role = RadioButtonRole.On;
}
else
{
role = RadioButtonRole.Off;
}
ToggleControl.GetRadioButtonByRole(role, panel).IsChecked = true;
}
private static void Setup(Panel panel)
{
// get buttons
foreach (RadioButton radioButton in
new RadioButtonRole[2]
{
RadioButtonRole.On,
RadioButtonRole.Off
}.Select(t =>
ToggleControl.GetRadioButtonByRole(t, panel)))
{
radioButton.Checked += (o2, e2) =>
{
RadioButton checkedRadioButton = (RadioButton)o2;
panel.SetValue(ToggleControl.IsOnProperty,
ToggleControl.GetRadioButtonRole(checkedRadioButton) == RadioButtonRole.On);
};
}
panel.SetValue(ToggleControl.IsSetUpProperty, true);
}
private static bool IsSetup(Panel o)
{
return (bool)o.GetValue(ToggleControl.IsSetUpProperty);
}
private static RadioButton GetRadioButtonByRole(RadioButtonRole role,
Panel container)
{
return container.Children.OfType<RadioButton>().First(t =>
(RadioButtonRole)t.GetValue(ToggleControl.RoleProperty) == role);
}
private static RadioButtonRole GetRadioButtonRole(RadioButton radioButton)
{
return (RadioButtonRole)radioButton.GetValue(ToggleControl.RoleProperty);
}
public static void SetIsOn(DependencyObject o, bool? e)
{
o.SetValue(ToggleControl.IsOnProperty, e);
}
public static bool? GetIsOn(DependencyObject e)
{
return (bool?)e.GetValue(ToggleControl.IsOnProperty);
}
public static void SetRole(DependencyObject o, RadioButtonRole? e)
{
o.SetValue(ToggleControl.RoleProperty, e);
}
public static RadioButtonRole? GetRole(DependencyObject e)
{
return (RadioButtonRole?)e.GetValue(ToggleControl.RoleProperty);
}
}
public class TwoBoolean: INotifyPropertyChanged
{
private bool propertyA, propertyB;
public bool PropertyA
{
get
{
return this.propertyA;
}
set
{
this.propertyA = value;
this.OnPropertyChanged("PropertyA");
}
}
public bool PropertyB
{
get
{
return this.propertyB;
}
set
{
this.propertyB = value;
this.OnPropertyChanged("PropertyB");
}
}
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
public override string ToString()
{
return string.Format("PropertyA:{0}, PropertyB:{1}", this.PropertyA, this.PropertyB);
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
Markup:
<Window x:Class="RadioButtons.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RadioButtons"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Margin="5" VerticalAlignment="Center">PropertyA</TextBlock>
<StackPanel local:ToggleControl.IsOn="{Binding PropertyA, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Grid.Row="0" Grid.Column="1"
Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
<RadioButton Content="On" local:ToggleControl.Role="On" Height="20" Margin="5" />
<RadioButton Content="Off" local:ToggleControl.Role="Off" Height="20" Margin="5" />
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="0" Margin="5" VerticalAlignment="Center">PropertyB</TextBlock>
<StackPanel local:ToggleControl.IsOn="{Binding PropertyB, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Grid.Row="1" Grid.Column="1"
Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
<RadioButton Content="On" local:ToggleControl.Role="On" Height="20" Margin="5" />
<RadioButton Content="Off" local:ToggleControl.Role="Off" Height="20" Margin="5" />
</StackPanel>
<Button Click="Button_Click" Grid.Row="3" Grid.ColumnSpan="2">Save</Button>
</Grid>
</Window>
You should not use an xmlns to pass a parameter, rather use the Tag or template a ContentControl, then you can bind the Content to your property (set it to TwoWay) and use a TemplateBinding to Content inside the template.
In the following example I bind the XAML to a static object via ObjectDataProvider.
When the user changes information, I want it to automatically reflect in the XAML.
What I don't understand is:
how do I perpetuate the object? do I have to create a singleton? in the click event, how do I access the "object that is being edited"
eventually of course I want the data to be retrieved from a model which reads an XML file or web service, and I want of course my ViewModel to check my model every second or so to see if the data has changed and reflect this on the XAML.
How to I get THERE from HERE:
XAML:
<Window x:Class="TestBinding99382.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestBinding99382"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ObjectDataProvider
x:Key="DataSourceCustomer"
ObjectType="{x:Type local:Customer}" MethodName="GetCustomer"/>
<Style x:Key="DataRowStyle" TargetType="StackPanel">
<Setter Property="Orientation" Value="Horizontal"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Margin" Value="0 10 0 0"/>
<Setter Property="DataContext"
Value="{StaticResource DataSourceCustomer}"/>
<Setter Property="DockPanel.Dock" Value="Top"/>
</Style>
</Window.Resources>
<DockPanel>
<StackPanel DockPanel.Dock="Top"
DataContext="{StaticResource DataSourceCustomer}"
Orientation="Horizontal">
<TextBlock Text="{Binding Path=FirstName}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Path=LastName}"/>
<TextBlock Text=" ("/>
<TextBlock Text="{Binding Path=FullName}" FontWeight="Bold"/>
<TextBlock Text=")"/>
</StackPanel>
<StackPanel Style="{StaticResource DataRowStyle}">
<TextBlock Text="First Name:"/>
<TextBox Text="{Binding Path=FirstName}"
Width="200" Margin="3 0 0 0"/>
</StackPanel>
<StackPanel Style="{StaticResource DataRowStyle}">
<TextBlock Text="Last Name:"/>
<TextBox Text="{Binding Path=LastName}"
Width="200" Margin="3 0 0 0"/>
</StackPanel>
<StackPanel Style="{StaticResource DataRowStyle}">
<Button Content="Save Changes" Click="Button_Click"/>
</StackPanel>
</DockPanel>
</Window>
Code Behind:
using System.Windows;
using System.ComponentModel;
using System;
namespace TestBinding99382
{
public partial class Window1 : Window
{
private Customer _customer;
public Window1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//I want to edit the _customer object here
//and have it my changes automatically reflect in my XAML
//via the INotifyPropertyChanged inheritance.
}
}
public class Customer : INotifyPropertyChanged
{
private string _firstName;
private string _lastName;
public string FirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
this.RaisePropertyChanged("FirstName");
this.RaisePropertyChanged("FullName");
}
}
public string LastName
{
get
{
return _lastName;
}
set
{
_lastName = value;
this.RaisePropertyChanged("LastName");
this.RaisePropertyChanged("FullName");
}
}
public string FullName
{
get
{
return String.Format("{0} {1}", _firstName, _lastName);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public static Customer GetCustomer()
{
return new Customer { FirstName = "Jim", LastName = "Smith" };
}
}
}
in the click event, how do I access
the "object that is being edited"
You can access a resource in the behind code using FindResource method, see below.
private void Button_Click(object sender, RoutedEventArgs e)
{
ObjectDataProvider objectDataProvider
= FindResource("DataSourceCustomer") as ObjectDataProvider;
_customer = objectDataProvider.Data as Customer;
}
For your other questions:
What is perpetuate? You do not have to create a singleton to databind in WPF if that is your question.
eventually of course I want the data to be retrieved from a model which reads an XML file or web service, and I want of course my ViewModel to check my model every second or so to see if the data has changed and reflect this on the XAML.
WPF databinding will automatically update your view of you use an INotifyPropertyChanged object. Unless for performance reasons you only want to update your view every second or so just stick to normal databinding.