I hope I can explain my problem properly.
I have a datagrid bound to an ObservableCollection object, and a TextBox bound to the selected item of my datagrid.
When I programmatically modify the SelectedItem property value (Name), my TextBox text value is not updated !
here is my design code:
<DataGrid Name="grid" HorizontalAlignment="Left" Margin="119,28,0,0" VerticalAlignment="Top" Height="237" Width="200" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="nom" Binding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid.Columns>
</DataGrid>
<TextBox Name="textbox" Text="{Binding ElementName=grid, Path=SelectedItem.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Height="18" Margin="119,276,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="200"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="392,54,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
and here is my Code Behind:
ObservableCollection<Element> obs;
class Element
{
public string Name { get; set; }
public Element(string name) { Name = name; }
}
public MainWindow()
{
InitializeComponent();
obs = new ObservableCollection<Element>() { new Element("element2"), new Element("element2"), new Element("element3")};
grid.ItemsSource = obs;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var sel = grid.SelectedItem as Element;
sel.Name = "something";
grid.Items.Refresh(); //this updates the selected element to "something" but does nothing to the textbox
}
Problem solved.
I had to fire PropertyChanged event whenever a modification is made to the model.
here my new code:
class Element : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
public Element(string name) { Name = name; }
}
Related
I'm having problems to do a binding in Windows Phone. Hope you can help me.
I have the following Data Template:
<DataTemplate>
<TextBox Name="txt1"/>
<TextBox Name="txt2"/>
</DataTemplate>
I have a ListBox that receives the following Class in the ItemsSource Property:
public class Product
{
private int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
Is there anyway to bind the Text property with the Object of the ListBoxItem like...
<TextBox Name="txt1" Text={Binding ElementName=ListBox, Path=SelectedItem.Product.Name}/>
I got a working example
xaml:
Here's the code
<Grid x:Name="gdTest" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,0,5,0" >
<ListBox Width="400" Margin="10" x:Name="lstDemo">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Id}" Margin="20" />
<TextBlock Text="{Binding Path=Name}" Margin="20"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using StackOverFlowTestApp.Resources;
using Microsoft.Phone.Tasks;
using Microsoft.Phone.UserData;
using Windows.UI;
using System.Windows.Media;
using System.IO;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework;
namespace StackOverFlowTestApp
{
public partial class MainPage : PhoneApplicationPage
{
private SoundEffect effect;
// Constructor
public MainPage()
{
InitializeComponent();
List<Product> liProd = new List<Product>();
for (int i = 0; i < 10; i++) {
liProd.Add(new Product()
{
Id = i,
Name = "Anobik" + i.ToString()
});
}
lstDemo.ItemsSource = liProd;
}
}
public class Product
{
private int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
}
if you require any more explanation then let me know.
I want to use twoway binding in my customcontrol. It's codes;
CustomControl;
<Grid>
<PasswordBox x:Name="passwordB" GotFocus="PasswordBox_GotFocus" LostFocus="PasswordBox_LostFocus" PasswordChanged="passwordB_PasswordChanged" Style="{StaticResource AkbankControlStyleWatermarkPasswordBoxLoginFormInputPasswordBox}"></PasswordBox>
<TextBlock x:Name="lblWaterMark" MouseLeftButtonDown="lblWaterMark_Tapped" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20,10,20,10" Opacity="0.8" FontFamily="Segoe UI" FontSize="16" Foreground="#FF8E8E8E" FontWeight="SemiBold"></TextBlock>
</Grid>
It's name is WatermarkPasswordTextBox :)
DependencyProperty;
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register(
"PassText",
typeof(string),
typeof(WatermarkPasswordTextBox),
new PropertyMetadata(""));
Properties;
private string _passText = "";
public string PassText
{
get
{
if (passwordB != null)
{
_passText = passwordB.Password;
return _passText;
}
else
{
return String.Empty;
}
}
set
{
if (passwordB != null)
{
SetProperty<string>(ref _passText, value, "PassText");
passwordB.Password = _passText;
passwordB_PasswordChanged(passwordB, null);
}
else
{
SetProperty<string>(ref _passText, value, "PassText");
}
}
}
OnApplyTemplate ;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.SetBinding(
WatermarkPasswordTextBox.PasswordProperty,
new Binding
{
Path = new PropertyPath("PassText"),
Mode = BindingMode.TwoWay,
Source = this
});
}
My Xaml;
<CustomControls:WatermarkPasswordTextBox
PassText="{Binding Password,Mode=TwoWay}"
Padding="5"
x:Name="CustomerPasswordTextBox"
x:FieldModifier="public"
LenghtMax="6"
Watermark="{Binding LocalizedResources.PasswordWatermarkWatermark,Source={StaticResource LocalizedStrings}}"
RelayedKeyUp="CustomerPasswordTextBox_KeyUp"
HorizontalContentAlignment="Left"/>
Error Code;
System.ArgumentException: Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'.
This code is giving runtime error.
Thanks.
I am building a Windows Phone App, and I am trying to bind the ObservableCollection with nested struct without success.
MyViewModel.cs
public class MyViewModel : PropertyChangedBase
{
private Player _Player1;
public Player Player1
{
get { return _Player1; }
set
{
if (!value.Equals(_Player1))
{
_Player1 = value;
NotifyOfPropertyChange(() => Player1);
}
}
}
private Player _Player2;
public Player Player2
{
get { return _Player2; }
set
{
if (!value.Equals(_Player2))
{
_Player2 = value;
NotifyOfPropertyChange(() => Player2);
}
}
}
public struct Player
{
public string Name;
public bool IsWinner;
}
}
MyPageViewModel.cs
public class MyPageViewModel : Screen
{
public ObservableCollection<MyViewModel> Matches { get; private set; }
public MyPageViewModel()
{
this.Matches = new ObservableCollection<MyViewModel>();
LoadData();
}
public void LoadData()
{
// Matches
this.Matches.Add(new MyViewModel()
{
Player1 = new MyViewModel.Player
{ Name = "Jhonn", IsWinner = false },
Player2 = new MyViewModel.Player
{ Name = "Marrie", IsWinner = true }
});
}
}
MyPage.xaml
<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Matches}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding Player1.Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding Player2.Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have no binding error, but no players names are showed. I always have a blank screen.
Your problem is here:
public struct Player
{
public string Name;
public bool IsWinner;
}
In order to be bound, Name needs to be a property. Make Player a class and expose Name as a property on the class and you'll be golden:
public class Player
{
public string Name {get; set;}
public bool IsWinner {get;set;}
}
You should be able to get away without implementing INotifyPropertyChanged, as long as you only set them one time. If they're going to change, go ahead and implement INPC.
i have an combox control defined with events in my mainpage.xaml
<Grid x:Name="LayoutRoot">
<ComboBox SelectionChanged="ComboBox_SelectionChanged"></ComboBox>
</Grid>
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
now how do we defined events for combox control in mvvm model .
and how do we bind the collection list to combo box. i am using SL 3
thanks
prince
In your xaml, you can bind the ItemSource and SelectedItem as shown below:
MainPage.xaml
<UserControl x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:App1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.DataContext>
<local:MainPage_ViewModel/>
</UserControl.DataContext>
<Grid x:Name="LayoutRoot" Background="White">
<ComboBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" SelectionChanged="ComboBox_SelectionChanged" Height="30" Width="100"/>
</Grid>
In the MainPage.xaml.cs, your Selection changed method could just call the method on your ViewModel since you are using SL3:
MainPage.xaml.cs
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private MainPage_ViewModel viewModel
{
get { return this.DataContext as MainPage_ViewModel; }
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.viewModel.SelectionChanged();
}
}
Your ViewModel would have the MyItems collection and the SelectedItem to bind to:
MainPage_ViewModel.cs
public class MainPage_ViewModel : INotifyPropertyChanged
{
public ObservableCollection<string> MyItems
{
get { return myItems; }
set { myItems = value; }
}
private ObservableCollection<string> myItems = new ObservableCollection<string>() { "One", "Two", "Three" };
public string SelectedItem
{
get { return selectedItem; }
set { selectedItem = value; }
}
private string selectedItem = string.Empty;
public void SelectionChanged()
{
//Perform logic that needs to happen when selection changes
}
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Depending on what you were using your SelectionChanged method for, you may no longer need it since this would bind the SelectedItem to the ViewModel.
Hope this helps!
New to wpf and through a learning curve.
I have a userControl with a Toolbar Save Button and a TextBox.
What I am trying to achieve is as follows
When I press the save Button in the toolbar I should record in the textbox that I am about to save and that I have saved the customer (CustomerView UserControl)
I seem to have 2 problems
1) that the SaveCommand is not hooked I thought I had hooked it
2) is not writing the action to the textbox.
Could you tell me where I am going wrong?
Thanks a lot!!!
MainWindow.xaml
<Window x:Class="MyCompany.CustomerStore.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:MyCompany.CustomerStore.Views"
Title="MainWindow" Height="350" Width="525">
<Grid>
<view:CustomerView></view:CustomerView>
</Grid>
CustomerView.xaml
<UserControl x:Class="MyCompany.CustomerStore.Views.CustomerView"
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>
<DockPanel LastChildFill="True">
<ToolBar DockPanel.Dock="Top">
<Button Command="{Binding Path=SaveCommand}">Save</Button>
</ToolBar>
<TextBox Name="txtPrintAction" Text="{Binding CustomerLog, Mode=TwoWay}"></TextBox>
</DockPanel>
</Grid>
CustomerModel.cs
public class CustomerModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string CustomerLog { get; set; }
}
CustomerViewModel.cs
public class CustomerViewModel:WorkspaceViewModel,ICustomerViewModel
{
readonly CustomerModel _customerModel;
RelayCommand _saveCommand;
public CustomerViewModel(CustomerModel customer)
{
_customerModel = customer;
}
public string FirstName
{
get { return _customerModel.FirstName; }
set
{
_customerModel.FirstName = value;
base.OnPropertyChanged("FirstName");
}
}
public string LastName
{
get { return _customerModel.LastName; }
set
{
_customerModel.LastName = value;
base.OnPropertyChanged("LastName");
}
}
public string CustomerLog
{
get { return _customerModel.CustomerLog; }
set
{
_customerModel.CustomerLog = value;
base.OnPropertyChanged("CustomerLog");
}
}
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(param => Save(), param => CanSave);
}
return _saveCommand;
}
}
private void Save()
{
AppendToLog("I am about to save");
//Pretend we have saved the customer
AppendToLog("CustomerSaved");
}
internal void AppendToLog(string text)
{
_customerModel.CustomerLog += text + Environment.NewLine; ;
OnPropertyChanged("CustomerLog");
}
static bool CanSave
{
get
{
return true;
}
}
Where do you declare a relationship between the view
x:Class="MyCompany.CustomerStore.Views.CustomerView
and the model class CustomerViewModel?
I don't see that anywhere.
I think you need to set the DataContext of the View to the Model.