DataBinding over a property in viewModel - c#

surely this question has beed debated thousand of time, but I do not find any suitable solution to my need. I am new to SilverLIght and I intended to start well using MVVM.
therefore I did the following view model :
public class MyViewModel
{
private IRepository _Repository;
public string CountText { get; set; }
public MyViewModel (IRepository repository)
{
_Repository = repository;
CountText = "test ctor";
}
public void MyButtonCommand()
{
_Repository.GetResult((Result r) => MyActionAsync(r), (Exception e) => ManageException(e));
}
public void MyActionAsync(SchedeConsunitiviResult result)
{
CountText = string.Format("{0} items", result.Count);
}
public void ManageException(Exception e)
{
//to log the exception here and display some alert message
}
}
and here my xaml :
<sdk:Label Content="{Binding Path=CountText, Mode=TwoWay}" Grid.Row="3" Height="28" HorizontalAlignment="Left" Margin="12,142,0,0" Name="label1" VerticalAlignment="Top" Width="120" Grid.ColumnSpan="2" />
The first instanciation of CountText is visible in the Label. But the second one after the async method does not change the content of the LAbel. Should I add some mechanism like PropertyChanged in order to tell the view this property has changed? if so, how can I do that using xaml only?
thx for your help

Implement the INotifyPropertyChanged and notify that your property has changed with the EventHandler.
public class MyViewModel : INotifyPropertyChanged
{
private string countText;
public string CountText
{
get { return this.countText; }
set { this.countText = value; NotifyPropertyChanged("CountText"); }
}
.....snip.....
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(params string[] properties)
{
if (PropertyChanged != null)
{
foreach (string property in properties)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(property));
}
}
}

As far as I know you do need a mechanism like PropertyChanged in your viewmodel

Related

Unable to Update XAML TextBlock Text Binding

I have a TextBlock in XAML that's bound to a property called EditsWarning:
<TextBlock DockPanel.Dock="Top" Text="{Binding EditsWarning, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource Esri_TextBlockRegular}" HorizontalAlignment="Left" FontSize="14" FontWeight="DemiBold" VerticalAlignment="Center" Margin="10,0,10,5" TextWrapping="WrapWithOverflow"/>
The Definition for the EditsWarning Property is here:
public string EditsWarning
{
get { return editsWarningMessage; }
set
{
SetProperty(ref editsWarningMessage, value, () => this.EditsWarning);
}
}
The EditsWarning Property is set to an instance of a class like this:
editsWarning = new OutstandingEditsTextBlock();
editsWarningMessage = editsWarning.EditsWarningMessage.ToString();
And the OutstandingEditsTextBlock class is here, and implements INotifyPropertyChanged
internal class OutstandingEditsTextBlock : INotifyPropertyChanged
{
private string editsWarning;
public OutstandingEditsTextBlock()
{
if (Project.Current.HasEdits)
{
this.editsWarning = "This session/version has outstanding edits.";
}
else
{
this.editsWarning = string.Empty;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public string EditsWarningMessage
{
get { return this.editsWarning; }
set
{
this.editsWarning = value;
this.OnPropertyChanged("EditsWarningMessage");
}
}
public void OnPropertyChanged(string propertyName)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I noticed that I can get it to display either value, however, I can never get it to update in the same debugging session. In fact, it looks like the setter for the public property is never hit.
Can someone please help me figure out what I'm doing wrong?
Thank you.

Bound target not updating when button pressed to change value

I have some code which uses a form. The form is bound to my class, FormData. I have binding working well and updating my formData (local instance), but when I try to change the value of one of the variables in formData on button click/LostFocus trigger, it doesn't update.
Here's my relevant XAML:
<TextBox x:Name="friendly_name_textBox"
Style="{StaticResource TextErrorStyle}"
Text="{Binding
PrimaryUserName,
Mode=TwoWay,
ValidatesOnExceptions=True,
ValidatesOnDataErrors=True,
UpdateSourceTrigger=PropertyChanged,
NotifyOnValidationError=True}"
HorizontalAlignment="Left"
Margin="0,75,0,0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="120"/>`
The button trigger (which does get run):
private void Button_Click(object sender, RoutedEventArgs e)
{
formData.PrimaryUserName = "TEST";
}
And my FormData code:
public string PrimaryUserName
{
get
{
return primaryUserNameValue;
}
set
{
if(primaryUserNameValue != value)
{
primaryUserNameValue = value;
}
}
}
You need to implement the INotifyPropertyChanged interface and raise the PropertyChanged event in your formData class:
public class formData : INotifyPropertyChanged
{
private string primaryUserNameValue;
public string PrimaryUserName
{
get
{
return primaryUserNameValue;
}
set
{
if (primaryUserNameValue != value)
{
primaryUserNameValue = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Your Class needs to implement INotifyPropertyChanged, so that the target knows if the source property changes:
https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-property-change-notification
It's really easy, please have a look at the documentation and adjust your code accordingly. Your Property would have to look like this:
public string PrimaryUserName
{
get
{
return primaryUserNameValue;
}
set
{
if(primaryUserNameValue != value)
{
primaryUserNameValue = value;
OnPropertyChanged("PrimaryUserName");
}
}
}
But you also need the event and onPropertyChanged function to make it work.
Happy Coding!

Updating textbox from Button click C#

I have the following textbox
<TextBox Grid.Column="1"
Grid.Row="1"
Name="groupAddressBox"
Width ="80"
Text="{Binding Path=GroupAddress, Converter={StaticResource groupAddressConverter}}"/>
When I change the text manually, it's all good.
But when I try to do this via a button
private void Test_Click(object sender, RoutedEventArgs e)
{
groupAddressBox.Text = "0/0/1";
}
Although the text changes, the source is not updated, and when I click on ok, it recognizes the value that was there before the change.
I cannot upgrade the source straight away, so I prefer to do this this way.
Is there something that can help me force the source upgrade via this way?
Based on your question, I tried to create a Simple Example of MVVM Pattern with very basic functionality. Please do necessary change to XAML and CS file as I took the highlighted code only.
Helper Classes
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
public class CommandHandler : ICommand
{
public event EventHandler CanExecuteChanged { add { } remove { } }
private Action<object> action;
private bool canExecute;
public CommandHandler(Action<object> action, bool canExecute)
{
this.action = action;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute;
}
public void Execute(object parameter)
{
action(parameter);
}
}
ViewModel
public class ViewModel : ViewModelBase
{
private string groupAddress;
public string GroupAddress
{
get
{
return groupAddress;
}
set
{
if(value != groupAddress)
{
groupAddress = value;
OnPropertyChanged("GroupAddress");
}
}
}
public ViewModel()
{
}
private ICommand clickCommand;
public ICommand ClickCommand
{
get
{
return clickCommand ?? (clickCommand = new CommandHandler(() => MyAction(), true));
}
}
public void MyAction()
{
GroupAddress = "New Group Address";
}
}
Window Xaml
<TextBox Grid.Column="1" Grid.Row="1" Width ="80"
Text="{Binding GroupAddress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Push" Style="{StaticResource TransparentButtonStyle}"
Margin="5" Command="{Binding ClickCommand}"/>
Window Xaml cs
ViewModel vm = new ViewModel();
this.DataContext = vm;

Modify searchbox results view in UWP C#

I am working on my application update and I want to use a new searchbox and I want to show my results like Windows Store .
how can I do this ?
You can use an AutoSuggestBox which is bound to a changing ObservableCollection everytime the Text inside the AutoSuggestBox is changed.
For example, this is your Model:
public class App
{
public ind Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public Image Picture { get; set; }
}
You can implement a method updating an ObservableCollection with a parameter (in this case the search expression) in your ViewModel:
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
SuggestedApps = new ObservableCollection<App>();
SuggestedApps.CollectionChanged += SuggestedApps_CollectionChanged;
}
private void SuggestedApps_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged("SuggestedApps");
}
private ObservableCollection<App> suggestedApps;
public ObservableCollection<App> SuggestedApps
{
get
{
return suggestedApps;
}
set
{
suggestedApps = value;
OnPropertyChanged("SuggestedApps");
}
}
public void SuggestForSearch(string searchExpression)
{
SuggestedApps.Clear();
//Assumgin EF as DataSource
//You can use another Search algorithm here instead of String.Contains
foreach(var item in yourDataSource.Apps.Where(x => x.Name.Contains(searchExpression.Trim())))
{
SuggestedApps.Add(item);
}
}
public void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
In your Xaml code you can use this to bind an AutoSuggestBox to it and define a Template:
<AutoSuggestBox x:Name="AutoSuggestBoxApps" ItemsSource="{Binding SuggestedApps}" TextChanged="AutoSuggestBoxApps_TextChanged">
<AutoSuggestBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Picture}"/>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Category}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</AutoSuggestBox.ItemTemplate>
</AutoSuggestBox>
In the implemetation of the TextChanged-Event you just call the SuggestForSearch Method from your ViewModel:
private void AutoSuggestBoxApps_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
(this.DataContext as ViewModel).SuggestForSearch((sender as AutoSuggestBox).Text);
}
There is a control for UWP named AutoSuggestBox that you should read up on:
https://msdn.microsoft.com/nb-no/library/windows/apps/xaml/windows.ui.xaml.controls.autosuggestbox.aspx
This should give you the tools you need to give the wanted functionality

Observable collection not reacting to it's collecion

My ListBox doesn't react to my ObservableCollection.
This is the ListBox I am talking about.
<ListBox x:Name="CreateFieldsList"
HorizontalAlignment="Left"
Height="218"
VerticalAlignment="Top"
Width="244"
Margin="0,86,0,0"
BorderBrush="#FFB9B9B9">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="4"
Width="215"
Height="32.96"
Background="White">
<TextBlock Text="{Binding Name}"
FontWeight="Normal"
FontSize="18.667"
Padding="8,3,0,0" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In my MainWindow, I prepare the data binding like this
private ObservableCollection<FieldListItem> _fieldItems;
public MainWindow()
{
InitializeComponent();
_fieldItems = new ObservableCollection<FieldListItem>();
CreateFieldsList.ItemSource = _fieldItems;
}
A FieldListItem is following
public class FieldListItem : ViewItem
{
private Field _field;
public string Name
{
get { return _field.Name; }
}
public string Value
{
get { return _field.Value; }
}
public FieldListItem(Field f)
{
_field = f;
}
}
and finally the ViewItem
public class ViewItem : INotifyPropertyChanged
{
private event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string caller = "")
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
//The interface forces me to implement this. Why?
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { }
remove { }
}
}
I don't know why this isn't working. Could you please help?
The INotifyPropertyChanged interface needs you to implement an event. Your event implementation does not work because registrations and deregistrations are ignored because the add and remove blocks are empty.
Implement the event without add and remove:
public class ViewItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string caller = "")
{
var copy = PropertyChanged;
if (copy != null)
copy(this, new PropertyChangedEventArgs(caller));
}
}

Categories