This must be something obvious, but can anyone tell me why my the value in my label is only updated once. My PropertyChangedEventHandler never fires:
<Page.Resources>
x:Key="SoSummaryViewModelDataSource"/>
</Page.Resources>
<Grid DataContext="{StaticResource SoSummaryViewModelDataSource}">
<Label Grid.Row="2"
Margin="30, 0, 0, 0"
FontWeight="Medium"
Content="{Binding TotalDisplayedCustomers, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
Here is my property:
public string TotalDisplayedCustomers
{
get { return _totalDisplayedCustomers; }
set
{
if (_totalDisplayedCustomers != value)
{
_totalDisplayedCustomers = value;
OnPropertyChanged("TotalDisplayedCustomers");
}
}
}
And here is my OnPropertyChanged:
protected void OnPropertyChanged(string propertyName)
{
//when propertyName is TotalDisplayedCustomers, handler is null, why??
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Ha you tried to inspect yout ViewModel load into your DataContext. When i want to inspect it, i use the Wpf Inspector Tools
Well here is what I came up with, I still don't understand what was wrong with my Binding, but instead of relying on the PropertyChanged firing on a string in my view model, I instead bound my Run to the Count property of an ObservableCollection.
First I used a DataContext on my page:
<Page.DataContext>
<vm:SoSummaryViewModel/>
</Page.DataContext>
Changed my TextBlock like this:
<TextBlock Grid.Row="2" Margin="40, 0, 0, 0">
<Run Text="Customer Count: " FontWeight="Medium"></Run>
<Run Text="{Binding SummaryLineItems.Count, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}">
<TextBlock Text=" (Filtered)" Visibility="{Binding HideOnTimeCustomers, Converter={StaticResource showIfTrue}}"/>
</TextBlock>
Related
I have a UWP application where the buttons hold state work just fine until I bind (any) buttons visibility or editable state where the hold state goes away. The buttons only work if I tap super quickly after something gets binded. If I switch to a different view then back to the original view, the buttons magically work again. Anyone have any ideas what could be causing this?
Added the IsHoldingState="true" to parent and button in xaml.
xaml code
<controls:RoundedButton Grid.Row="2" Style="{StaticResource SubmitButtonStyle}" Command="{Binding SubmitCommand}" VerticalAlignment="Bottom" Visibility="{Binding IsNotEmpty, Converter={StaticResource visibilityConverter}, ConverterParameter=false}" Margin="-16,-16,-32,-32" Width="384" Height="112" Opacity="0" Background="Transparent" />
<controls:RoundedButton Grid.Row="2" Style="{StaticResource SubmitButtonStyle}" Command="{Binding SubmitCommand}" VerticalAlignment="Bottom" Visibility="{Binding IsNotEmpty, Converter={StaticResource visibilityConverter}, ConverterParameter=false}">
cs code (where the binding is updated via onpropertychanged)
private bool isNotEmpty;
public bool IsNotEmpty
{
get { return isNotEmpty; }
set { Set(() => IsNotEmpty, ref isNotEmpty, value); }
}
protected bool Set<T>(Expression<Func<T>> selectorExpression, ref T field, T value)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
RaisePropertyChanged(selectorExpression);
return true;
}
protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
var propertyName = GetPropertyName(selectorExpression);
OnPropertyChanged(propertyName);
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
The problem may be in your ConverterParameter, ConverterParameter can't be directly assigned to a boolean value, please try this:
<Page.Resources>
<x:Boolean x:Key="DefaultParameter">False</x:Boolean>
</Page.Resources>
...
<controls:RoundedButton Visibility="{Binding IsNotEmpty, Converter={StaticResource visibilityConverter}, ConverterParameter={StaticResource DefaultParameter}}">
Best regards.
I have a TabControl where I create tabs dynamically. I am finding it difficult to change the title of the TabItem.
<TabControl Name="AttorneysTabControl" Grid.Column="2" Grid.Row="0">
<TabControl.Resources>
<DataTemplate x:Key="AttorneyTabHeader">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Names}" Margin="2,0,0,0" FontSize="16" VerticalAlignment="Center" />
<Button Width="Auto" UseLayoutRounding="False" BorderBrush="Transparent" Background="Transparent" Click="CloseAttorneysTabButtonClick">
<Image Source="/images/close-cross-thin-circular-button/close-cross-thin-circular-button16.png" Height="16"></Image>
</Button>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="AttorneyTabContent">
<local:AttorneyDetails></local:AttorneyDetails>
</DataTemplate>
</TabControl.Resources>
For each TabItem I set a HeaderTemplate from the TabControl.Resources like this;
newTabItem.HeaderTemplate = (System.Windows.DataTemplate)AttorneysTabControl.FindResource("AttorneyTabHeader");
But I don't know how to change the contents of the TabItem header once the template has been set. I have tried using DataContext for the TabItem if that's the way to do it but it did not work, so that I could just use Binding in the template. That will be a lot easier.
You should normally write (first line is your unchanged code):
newTabItem.HeaderTemplate = (System.Windows.DataTemplate)AttorneysTabControl.FindResource("AttorneyTabHeader");
var tabItemData = new TabItemData() { Name="Initial name"} ;
newTabItem.DataContext = tabItemData;
And then once you need to update the tab header:
tabItemData.Name = "New name".
If that didn't work, that'd probably because your TabItemData.Name property doesn't notify of its changes. So make sure that your TabItemData class implements INotifyPropertyChanged and that the Name property notifies. Example:
public class TabItemData : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return this.name; }
set
{
if (value != this.name)
{
this.name= value;
NotifyPropertyChanged("Name");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In case you're lost I suggest reading the Managing data in a WPF application chapter of my Learn WPF MVVM book.
All I want is when a user changes the value in the textbox alphaMin_txt, the property AlphaMin gets updated.
Code behind:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _alphaMin;
public string AlphaMin
{
get { return _alphaMin; }
set
{
if (value != _alphaMin)
{
_alphaMin = value;
NotifyPropertyChanged();
}
}
}
}
XAML:
<DockPanel DataContext="{Binding MainWindow}">
<TextBox Text="{Binding
Path=AlphaMin,
NotifyOnTargetUpdated=True,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged}" />
</DockPanel>
This should be a duplicate a hundred times over but I've been through it all and none of it is laid out plain and simple for this one-way update of the source. All the MSN tutorials are binding some UIControl to another, which is pointless because IntelliSense shows you how to do that.
Your DockPanel probably has a faulty DataContext binding. DataContext should be set at the window level.
<Window ... DataContext="{Binding RelativeSource={RelativeSource Self}}" ..>
Of course, this is assuming your XAML is MainWindow.xaml.
If you have a different DataContext for the rest of the MainWindow, then you can do this:
<TextBox Text="{Binding
RelativeSource={RelativeSource AncestorType=Window},
Path=AlphaMin,
NotifyOnTargetUpdated=True,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged}" />
Of course, you should remove the DataContext for the DockPanel.
Your code behind is correct; there are no changes needed. Using CallerMemberName is a good way to implement INotifyPropertyChanged.
Assign a name to <Window x:Name="MyWin"...> , then change DataContext binding to {Binding ElementName=MyWin}.
Change this NotifyPropertyChanged(); to NotifyPropertyChanged("AlphaMin");
I have been facing a issue in updating the XAML in windows phone 8... the properties are binded in XAML with the viewModel, propertyChange is triggered and it changes the values of the properties. but the property members in XAML are only updated once at the beginning since then it does not update any thing in XAML... Although the properties continue to change in ViewModel.... the properties belong to a LIST of observation collection and finally Observation Collection is binded to LongListSelector
I have changed the binding Mode to "two Way" but useless i have pasted the code below.
Looking forward for help.
ViewModel:
private string _description;
public string description
{
set
{
_description = value;
RaisePropertyChanged("_description");
}
get
{
return _description;
}
}
private double _progress_bar_Value;
public double progress_bar_Value
{
set
{
_progress_bar_Value = value;
RaisePropertyChanged("_progress_bar_Value");
}
get
{
return _progress_bar_Value; //= ProfileSetting.ProfileTab_DOB;
}
}
private double _Total_Bytes;
public double Total_Bytes
{
set
{
_Total_Bytes = value;
RaisePropertyChanged("_Total_Bytes");
}
get
{
return _Total_Bytes;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
`
>
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,0" Orientation="Vertical"
>
<TextBlock Text="{Binding description}"
FontSize="18"
TextWrapping="Wrap"
Foreground="White" x:Name="Totalsize"
/>
<ProgressBar x:Name="Download_progressBar"
IsIndeterminate="False"
Maximum="100"
Height="10"
Width="400"
Value="{Binding progress_bar_Value}"
Foreground="White"
/>
<TextBlock Text="{Binding Bytes_received}"
FontSize="18"
TextWrapping="Wrap"
Foreground="White"
x:Name="Total_received"
/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>`
Raise Property Changed on the public property not backing field (as commented by #HighCore)
The "a.text" is extracted from my JSON Response. I am trying to display the "a.text" in the listbox.
List<Feature> features = App.dResult.directions[0].features;
foreach (Feature f in features)
{
Attributes a = f.attributes;
MessageBox.Show(a.text);
directionListBox.ItemsSource = a.text;
}
I tried using binding the "a.text" to the listbox but there is no display.
<ListBox x:Name="directionListBox" ItemsSource="{Binding a.text}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding a.text}" Style="{StaticResource PhoneTextTitle2Style}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Can anyone provide me with some idea on how to bind the "a.text" to listbox?
Any help will be greatly appreciated.
The ItemsSource Property of a ListBox should not point to a String, like a.text, but to an ObservableCollection.
Try something like this:
1st: derive that code class from INotifyPropertyChanged.
2nd: You can get the ObservableList from here or use ObservableCollection instead.
3rd: Then use this code (untested, but might work):
ObservableList<String> featList = new ObservableCollection<String>();
public event PropertyChangedEventHandler PropertyChanged;
public void InvokePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public ObservableList<String> FeatList
{
get { return featList; }
set
{
featList = value;
InvokePropertyChanged("FeatList");
}
}
List<Feature> features = App.dResult.directions[0].features;
foreach (Feature f in features)
{
Attributes a = f.attributes;
//MessageBox.Show(a.text);
FeatList.add(a.text);
}
4th: At the top of the fild you have to use a 'using' statement to import the ObservableList.
Then, bind the listbox'es ItemSource to this list, and make the TextBlock's Binding just bind to the default DataContext, which will be the string from the list:
<ListBox x:Name="directionListBox" ItemsSource="{Binding FeatList}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding}" Style="{StaticResource PhoneTextTitle2Style}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>