Is posible to force a control to raise the Validation.Error event, even when the binding doesn't specify the NotifyOnValidationError?
Or
Is there another event that raises always when the red validation border is shown or hidden?
Explanation:
I have an attached behaviour that makes a binding between the Validation.GetHasError and a property of my ViewModel. This with the purpose of knowing on the view model side, when a View side validation has happened.
Example: A view model with an int property
class ViewModel
{
int Value { get; set; }
}
A text box:
<TextBox Text="{Binding Value}" Validation.Error="Validation_Handler" />
Example I want to know when the user enter a value that it is not an integer.
Modifying all view model properties to have string type and have all validation done on the ViewModel is not feasible because some ViewModel properties are generated dynamically on run time, and I want to preserve the default converter behavior.
As seen on this question
The easiest solution was to inherit the Binding class and set the NotifyOnValidationError to true on the constructor. This way the Validation.Error event is always triggered.
public class Binding : System.Data.Binding
{
public Binding(string path) : base(path)
{
NotifyOnValidationError = true;
}
}
And the XAML:
<TextBox Text="{ui:Binding Value}" Validation.Error="Validation_Handler" />
Instead of:
<TextBox Text="{Binding Value, NotifyOnValidationError='True'}" Validation.Error="Validation_Handler" />
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm creating multiple grids with textboxes and labels.
There are grids that have some textboxes in common and others ones are unique to each grid.
I'm using the visibility property to show and collapse each grid when I need it.
The question is, is there a way of making visible a textbox from a collapsed grid into a different visible grid while the grids are overlapping?
May be there is a better control to do this?
Here is a summarized example of what I want to do:
XAML
<ToolBarTray>
<ToolBar>
<Button Name="showgrid1" Click="showgrid1_Click"/>
<Button Name="showgrid2" Click="showgrid2_Click"/>
</ToolBar>
</ToolBarTray>
<Grid Name="grid1" Visibility="Collapsed">
<TextBox Name="Common"/>
<TextBox Name="UniqueTogrid1"/>
</Grid>
<Grid Name="grid2" Visibility="Collapsed">
<TextBox Name="UniqueTogrid2"/>
</Grid>
Code behind C#:
private void showgrid1_Click(object sender, RoutedEventArgs e)
{
grid1.Visibility = Visibility.Visible;
Common.Visibility = Visibility.Visible;
UniqueTogrid1.Visibility = Visibility.Visible;
grid2.Visibility = Visibility.Collapsed;
}
private void showgrid2_Click(object sender, RoutedEventArgs e)
{
grid1.Visibility = Visibility.Collapsed;
grid2.Visibility = Visibility.Visible;
UniqueTogrid2.Visibility = Visibility.Visible;
Common.Visibility = Visibility.Visible; //I want to show this textbox without declaring it in grid2 in XAML, while the grids are overlaping.
}
This code won't show the Common textbox in grid2.
Even with the edit, the question isn't entirely clear. In particular, your code example doesn't provide any actual values for the UI elements being displayed, rendering any change in visibility moot. Who cares what's visible when, if there's no data?
That said, from your use of the Click event as a way to respond to user input, I suspect that you similarly have some code somewhere that is explicitly setting the Text property for the named UI elements you're dealing with. This has led you to a desire to reuse the <TextBox Name="Common"/> element, so as to not duplicate code.
If that inference is correct, or even close to being correct, then…the motivation is honorable, but you've painted yourself into a corner through your improper use of the WPF API. Specifically, you should view the UI elements as throw-away objects, and keep all the interesting bits of your program in non-UI objects called "view models". See "MVVM" as a programming paradigm.
By "throw-away", I mean these objects are created as needed by the framework to serve the purposes of the current state of the UI. They should not take any more significant role than that. When I look at the code example you posted, there are at least a couple of major warning signs in the code: the elements have names, and there is code-behind that is manipulating their visual state.
Both of these characteristics are almost never needed in well-written WPF code. The XAML can very often completely describe not just the appearance of the UI but how it changes visual state based on the operation of the program.
Okay, so with that exposition out of the way, how to implement your code so that it better-suits the WPF API, while at the same time has minimal repetition?
I can see at least a couple of ways immediately. One is to preserve substantially the arrangement of the XAML as you've got it now, but move the important elements into a proper view model data structure. Another is to use data templates and multiple view model data structures to automatically update the UI according to what data is active at the moment. I'll show both approaches here.
Approach #1:
The first step is to create the view model. IMHO, a WPF program will almost always start with the view model, because the XAML (the user interface) exists to serve the view model (the program data), rather than the other way around. The view model should ideally not have any dependencies on the UI framework. It represents the state of your program independent of things specific to the framework, though it will often still have state that represents conditional aspects of the UI itself.
In some cases, you'll find that you choose to use the view model as an adapter between an even more-rigorous model data structure; this adds a new layer to the program, allowing for the model data structure to be entirely independent of UI concerns entirely. I didn't bother with that for this example.
class ViewModel1 : NotifyPropertyChangedBase
{
private string _commonText = "default common text view model 1";
public string CommonText
{
get => _commonText;
set => _UpdateField(ref _commonText, value);
}
private string _uniqueText1 = "default unique text #1";
public string UniqueText1
{
get => _uniqueText1;
set => _UpdateField(ref _uniqueText1, value);
}
private string _uniqueText2 = "default unique text #2";
public string UniqueText2
{
get => _uniqueText2;
set => _UpdateField(ref _uniqueText2, value);
}
private int _gridToShow;
public int GridToShow
{
get => _gridToShow;
set => _UpdateField(ref _gridToShow, value);
}
public ICommand SetGridToShowCommand { get; }
public ViewModel1()
{
SetGridToShowCommand = new SetGridToShow(this);
}
private class SetGridToShow : ICommand
{
private readonly ViewModel1 _owner;
public SetGridToShow(ViewModel1 owner)
{
_owner = owner;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) => true;
public void Execute(object parameter)
{
if (parameter is int index ||
(parameter is string text && int.TryParse(text, out index)))
{
_owner.GridToShow = index;
}
}
}
}
This class has a few features typical of WPF view models:
It inherits a base class that does the actual work of implementing INotifyPropertyChanged.
It has public properties that represent the current state of the program, and which will be used in bindings declared in the XAML, either to display a particular value or to control some particular state of the UI.
It has public properties (well, one in this case) for commands to react to user input. In this particular example, the implementation of the single command is a standalone nested class, but in a real-world program this would typically be generalized as well, using helper classes that do things like handling type conversion for command parameters and accepting delegates for the actual implementation of a command.
In this example, the view model includes three string properties, one that represents the shared value between the two UI states, and then two more, each of which being the "unique" value for each state, an int property that represents the current UI state, and an ICommand property that handles the user input.
With that view model declared, now we can look at the XAML:
<DockPanel>
<DockPanel.DataContext>
<l:ViewModel1/>
</DockPanel.DataContext>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Content="Show Grid 1" Command="{Binding SetGridToShowCommand}" CommandParameter="1"/>
<Button Content="Show Grid 2" Command="{Binding SetGridToShowCommand}" CommandParameter="2"/>
</ToolBar>
</ToolBarTray>
<Grid>
<StackPanel>
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding GridToShow}" Value="1">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBox Text="{Binding CommonText}"/>
<TextBox Text="{Binding UniqueText1}"/>
</StackPanel>
<StackPanel>
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding GridToShow}" Value="2">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBox Text="{Binding CommonText}"/>
<TextBox Text="{Binding UniqueText2}"/>
</StackPanel>
</Grid>
</DockPanel>
The important parts in the above, relative to your question, are:
Most important, the CommonText property is bound to two different TextBox elements. I.e. the XAML element is not shared (which would have been the literal answer to your question), but rather the underlying view model property is shared. This allows the UI to interact with the user in whatever manner is appropriate for the given UI state, while only have a single state in the view model that represents the user's input.
The view model object is set as the data context for this part of the visual tree, via the DockPanel.DataContext element binding.
The user input isn't implemented with handlers for the Click event, but rather via the ICommand that updates the view model state according to the input.
The UI state itself responds to the changes in the view model via DataTrigger elements provided in the Style elements set for each "grid" (I used a StackPanel instead of a Grid in this example, because it was more convenient, but the same general ideas apply regardless.)
Approach #2:
That example alone I think sufficiently addresses the scenario you describe. However, WPF also can display an entirely different configuration of UI elements for a given data context object, through the mechanism of data templates. If we apply that idea to your question, we can:
Establish a couple more view model objects to represent the "unique" values in the program.
Declare a template for each of the view model objects.
Instead of using DataTrigger to change the visual state of the UI, let WPF automatically update the state via the templates, by simply updating the current view model being displayed.
In this scheme, here are the view model objects I came up with…
The main one:
class ViewModel2 : NotifyPropertyChangedBase
{
private readonly ViewModel2A _viewModel2A = new ViewModel2A();
private readonly ViewModel2B _viewModel2B = new ViewModel2B();
public string CommonText => "common text view model 2";
private object _gridViewModel;
public object GridViewModel
{
get => _gridViewModel;
set => _UpdateField(ref _gridViewModel, value);
}
public ICommand SetGridToShowCommand { get; }
public ViewModel2()
{
SetGridToShowCommand = new SetGridToShow(this);
}
private class SetGridToShow : ICommand
{
private readonly ViewModel2 _owner;
public SetGridToShow(ViewModel2 owner)
{
_owner = owner;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) => true;
public void Execute(object parameter)
{
if (parameter is int index ||
(parameter is string text && int.TryParse(text, out index)))
{
_owner.SetGridToShowIndex(index);
}
}
}
private void SetGridToShowIndex(int index)
{
GridViewModel = index == 1 ? (object)_viewModel2A : _viewModel2B;
}
}
And the two "unique" ones:
class ViewModel2A
{
public string UniqueText1 => "unique text grid #1";
}
class ViewModel2B
{
public string UniqueText2 => "unique text grid #2";
}
I skipped the INotifyPropertyChanged for the purposes of this example, and just made these view models with read-only/display-only properties.
Note that in the main view model, all it does when the user input occurs, is to set the current "grid" view model to the appropriate "unique" view model object.
With that in place, we can write the XAML:
<DockPanel Grid.Column="1">
<DockPanel.DataContext>
<l:ViewModel2/>
</DockPanel.DataContext>
<DockPanel.Resources>
<DataTemplate DataType="{x:Type l:ViewModel2A}">
<StackPanel>
<!-- OneWay binding for illustration purposes (view model property is read-only) -->
<!-- RelativeSource allows for referencing properties from other than the current data context, such as the common text property -->
<TextBox Text="{Binding DataContext.CommonText, Mode=OneWay, RelativeSource={RelativeSource AncestorType=DockPanel}}"/>
<TextBox Text="{Binding UniqueText1, Mode=OneWay}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type l:ViewModel2B}">
<StackPanel>
<TextBox Text="{Binding DataContext.CommonText, Mode=OneWay, RelativeSource={RelativeSource AncestorType=DockPanel}}"/>
<TextBox Text="{Binding UniqueText2, Mode=OneWay}"/>
</StackPanel>
</DataTemplate>
</DockPanel.Resources>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Content="Show Grid 1" Command="{Binding SetGridToShowCommand}" CommandParameter="1"/>
<Button Content="Show Grid 2" Command="{Binding SetGridToShowCommand}" CommandParameter="2"/>
</ToolBar>
</ToolBarTray>
<Grid>
<ContentControl Content="{Binding GridViewModel}"/>
</Grid>
</DockPanel>
Here, rather than setting styles with triggers, there are two different templates declared in the resource dictionary of the parent DockPanel element, one for each "unique" view model type. Then in the Grid control, the content is simply bound to the current "unique" view model object. WPF will select the correct template according to the type of that current "unique" view model object.
One slightly complicated thing I did in the XAML above was to put the CommonText property in the main view model, making it actually common to both view states. Then the templates both refer to it by using the RelativeSource mode for the binding. It would also have been possible instead to have the data templates only provide UI elements for the "unique" properties, and have the parent UI element handle display of the CommonText property. That would arguably be a little cleaner and less repetitive, but it would also have been a significant enough departure from the code you originally posted that I decided not to cross that bridge. :)
Finally, all of the above relies on that base class I mentioned earlier to implement INotifyPropertyChanged. There are various ways to implement that, but to complete the above example, here's the implementation I used for the code above:
class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void _UpdateField<T>(ref T field, T newValue,
Action<T> onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I have a custom media player object that I create in code behind from a user control. There can be 1 to 4 of these at any time, but i want to bind the volume and the mute property of only one to a xaml control EG.
The control is:
MediaControlplayer vcMediaPlayerMaster = new MediaControlplayer();
In this case the mute option to the ischecked state of the control does not work. How can I hook the binding up to the properties of the control when it is instantiated in code behind ?
xaml is like this. The variable vcMediaPlayerMaster is a global variable in code behind. When i instantiated it i assumed its declaration as a global predefined variable would allow the xaml below to bind to it, but it seems not to be the case.
<ToggleButton x:Name="btnAudioToggle" ToolTip="Audio Mute/Unmute"
Click="BtnAudioToggle_OnClick" IsChecked="{Binding Mode =TwoWay,
ElementName=vcMediaPlayerMaster, Path=Mute}" BorderBrush="LightBlue"
Width="32" Height="32" Margin="0,5,10,10" Background="{StaticResource
IbAudio}" Style="{DynamicResource ToggleButtonStyle1}" > </ToggleButton>
I thought perhaps creating a binding in code behind may be the way to go, but i cant seem to find a simple example that explains the code behind process to do that to fit my case.
You could create a helper class to hold the currently active MediaPlayer.
As a simple example:
public class MediaPlayerHelper : INotifyPropertyChanged
{
private MediaControlplayer currentPlayer;
public static MediaPlayerHelper Instance { get; } = new MediaPlayerHelper();
public MediaControlplayer CurrentPlayer
{
get => this.currentPlayer;
set { /* Implement a setter with INotifyPropertyChanged */ }
}
// Implement INotifyPropertyChanged here
}
The binding to this would look like the following
<Slider Value="{Binding Volume, Source={x:Static helper:MediaPlayerHelper.Instance}}"/>
Don't forget to include the namespace in the opening tag of your class in XAML:
xmlns:helper="clr-namespace:SomeNamespace.Helper"
Now you just have to change the currently used MediaPlayer whenever it changes:
MediaPlayerHelper.Instance.CurrentPlayer = newCurrentPlayer;
Ok i finally got it to work. Applied the binding in code behind fully.
I was able to bind the property i wanted to the ischecked property of a button to toggle the bool property of the mediaplayer object
MediaControlplayer vcMediaPlayerMaster = new MediaControlplayer();
Binding myMuteBinding = new Binding("Mute");
myMuteBinding.Source = vcMediaPlayerMaster;
myMuteBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myMuteBinding.Mode = BindingMode.TwoWay;
btnAudioToggle.SetBinding(SimpleButton.IsCheckedProperty, myMuteBinding);
So this worked fine for me and i used the same principle to bind other properties.
I'm trying to create a game editor in C#/WPF. The editor consists of a user control that shows the scene (rendered in OpenGL using SharpGL) as well as many controls for editing the current scene and objects. Objects consist of components whose properties can be edited in the editor (kind of like in Unity game engine). I already have a "component editor" view which uses reflection to find all properties on the component and creates a property editor (for example, a slider) per each property. However, I'm not sure how to bind the properties between UI and code.
The problem is, I want these properties to be updated in the UI when they change in code, as well as updated in code when they're changed in the UI. If I want to bind the editor controls (such as a slider that changes a property) to the component properties, they would have to implement NotifyPropertyChanged, which would be quite cumbersome. I guess the other way is doing dirty-checking, but I'm not sure if that's a good idea either.
Can anybody give me pointers on how this property updating between UI/Code should be handled? I want it to work pretty much like it does in Unity, where you don't need to write anything extra into your component class to make properties editable.
EDIT: To make more clear what I'm trying to achieve and already have, here is a part of the "component editor" user control. It's datacontext is a Component instance (model). PropertiesConverter returns it's properties (through component.GetType().GetProperties()). ComponentPropertyTemplateSelector decides on the property editor user control (for example, for a double property it would select a "number editor" that has a textbox for editing the value). The problem that I'm interested in solving is how to two-way bind a Component's property to an editor control.
<ItemsControl x:Name="ComponentProperties" Grid.Row="1" ItemTemplateSelector="{StaticResource ComponentPropertyTemplateSelector}">
<ItemsControl.ItemsSource>
<Binding Converter="{StaticResource PropertiesConverter}"/>
</ItemsControl.ItemsSource>
</ItemsControl>
I would say you probably want to follow the MVVM pattern which does use the INotifyPropertyChanged interface. If you do a Google search on MVVM there are some good articles that come up right away. There are also some existing tools out there already to help get you started. From what you describe in your question the MVVM pattern essentially works that way. It decouples the UI and the code but still maintains that connection. The real quick version is that you implement the INotifyPropertyChanged on a class and then you set an instance of that class to the DataContext of the control you want to setup the binding for. Probably easier to see an example:
Xaml:
<StackPanel>
<Slider Value="{Binding SliderValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding MyText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding MyText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Slider Value="{Binding SliderValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
I created a view model base to save on some code writing:
class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
An example view model class:
class MyViewModel : ViewModelBase
{
private int sliderValue;
private string myText;
public int SliderValue
{
get { return this.sliderValue; }
set
{
this.sliderValue = value;
this.OnPropertyChanged();
}
}
public string MyText
{
get { return this.myText; }
set
{
this.myText = value;
this.OnPropertyChanged();
}
}
}
How to hook up the binding (in this case the code behind of the control):
public MainWindow()
{
InitializeComponent();
this.DataContext = new MyViewModel();
}
As you can see there is some work involved in setting up the view models and xaml. Compared to other solutions I think this is pretty good as far as the amount of "work" you have to put in. I don't know if there is any way to get around it though and have it work like "magic". It might be worth checking into what MVVM tools exist, there may be stuff out there that can make things even more simple.
You can add IPropertyChangeNotification support automatically using either Castle Dynamic Proxy (which wraps the classes in a proxy) or Fody (which modifies the IL in a post-build step).
I'm building a Windows Universal app and trying to expose data from my ViewModel to my View so that I can bind it to XAML elements. I have completely commented out all of my code at this point and am just writing lines of test code to try and get it to work, that is what is in the examples below. Binding directly from the View (if I create an object there as a test) does work.
Please help me to understand where I am going wrong, I think I've read every binding tutorial on the internet and still just don't get it.
View (MainPage.xaml.cs):
public MainPage()
{
InitializeComponent();
DataContext = new MainViewModel();
}
ViewModel (MainViewModel.cs):
public class MainViewModel
{
public Term newTerm = new Term
{
TermName = "Table",
TermDescription = "You eat dinner on it"
};
}
XAML (MainPage.xaml):
<StackPanel DataContext="{Binding newTerm}" x:Name="mvvmStack" Orientation="Vertical">
<TextBlock x:Name="mvvmTermName" Text="{Binding TermName, FallbackValue='Fallingback'}" />
<TextBlock x:Name="mvvmDescription" Text="{Binding TermDescription, FallbackValue='Fallingback', TargetNullValue='Unknown'}" />
</StackPanel>
The error I get is:
Error: BindingExpression path error: 'newTerm' property not found on ''. BindingExpression: Path='newTerm' DataItem=''; target element is 'Windows.UI.Xaml.Controls.StackPanel' (Name='mvvmStack'); target property is 'DataContext' (type 'Object')
I have read about this type of error and although I have some idea of what it is trying to say I cannot work out how to fix it. I'm very much a complete beginner with coding, especially C# so please take that into account when answering :-)
Just try to change it from field to a property and it will be working correctly. You can't bind to fields.
EDIT:
private Term _term;
public Term NewTerm{
get{return _term;}
set
{
_term= value;
OnPropertyChanged("Term");
}
}
if you need to add notify the view of changes in the viewmodel you need to implement INotifyPropertyChanged.
check this answer it will provide an example for property changed. https://stackoverflow.com/a/27685925/1448382
If you want to bind the view to sub properties, you have two options depending on the situation:
1- Relative Binding: this scenario is used when you will not modify the properties inside the Term object from the ViewModel i.e. they will be just initialized in the viewmodel and can be modified in the view, just like the way you are doing it. Plesae note, that anything you need to bind to should be a property and not a field.
2- Binding to Viewmodel directly: this scenario is used when you will modify the properties inside the Term object from the Viewmodel after the view load. This way you will need to add properties to the viewmodel for the properties TermName and TermDescription.
public string TermName{
get{return NewTerm.Name;}
set{NewTerm.Name = value;
OnPropertyChanged("TermName");
}//The same is applied for TermDescription
But be aware that you will need to remove the binding on the Stackpanel object since you have defined the properties directly in the Viewmodel.
Try something like that:
<Page.Resources>
<viewModels:MainViewModel x:Key="MainViewModel" />
</Page.Resources>
And then:
<StackPanel x:Name="mvvmStack" Orientation="Vertical">
<TextBlock x:Name="mvvmTermName" Text="{Binding newTerm.TermName, Source={StaticResource MainViewModel} FallbackValue='Fallingback'}" />
<TextBlock x:Name="mvvmDescription" Text="{Binding newTerm.TermDescription, Source={StaticResource MainViewModel} FallbackValue='Fallingback', TargetNullValue='Unknown'}" /></StackPanel>
Of cource newTerm should be an property with INotifyChanged
I'm new to WPF, trying to adhere to the MVVM pattern as best as I can. So far so good except I've run into a problem with binding certain properties from my model.
So I have non-static properties that I have exposed in my model but they can only be changed from within the model. I run some function that does a bunch of stuff and it keeps track of what it's doing through a bunch of parameters that I've exposed for viewing.
I'm ok when I've got properties in my ViewModel - I can update these ok because I have implemented INotifyPropertyChanged. I've seen that sometimes people have implemented this in their Model too so I tried that but not knowing how INotifyPropertyChanged really works I don't know if there's anything else I need to do to get it running ok once it's in the Model.
I tried to create a property in my ViewModel that read from the Model and I bound the xaml to this but because I can't alter it from the ViewModel I ran into the same problem of telling the UI that it has been changed. Currently I have the binding direct whilst I try and figure this out but my goal is to be able to bind to a property in the ViewModel that just grabs the value from the Model.
Can anyone give me a good simple example of one-way binding to basic controls like labels/textblocks etc that will update itself when it all changes from within the model?
For completeness here is a simplified version of what I have including sample xaml (showing binding to a Model property & binding to a property from the ViewModel). The binding works because if I make changes in the model they appear in the designer and initial build.
The model is my own code and I can add/remove anything to get it working. Maybe it's fairly straightforward but I'm just not seeing the solution at the moment and not seen anything that makes sense to me on the forums.
Thanks!
in the Model
public enum TempValues { zero, pos10, pos50, pos100 }
namespace AutoCalModel
{
public class AutoCalibration : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
private TempValues _TempRelayValue = TempValues.zero;
public TempValues TempRelayValue
{
get { return _TempRelayValue; }
set
{
if (!value.Equals( _TempRelayValue))
{
_TempRelayValue = value;
NotifyPropertyChanged("TempRelayValue");
}
}
}
// rest of class including code that changes the above TempRelayValue
// accessed through the public property only
}
}
in the xaml
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Name="labelPrsTitle" Text="Prs:" Margin="2,0,2,0"/>
<TextBlock Name="labelPrsValue" Text="{Binding Path=currentPrsValueString, Mode=OneWay}" Margin="2,0,5,0"/>
<Separator Margin="5,0,5,0"/>
<TextBlock Text="Temp Relay:" Margin="5,0,2,0"/>
<TextBlock Text="{Binding Path=TempRelayValue, Converter={StaticResource tempValuesConverter}, Mode=OneWay}" Margin="2,0,5,0">
<TextBlock.DataContext><Model:AutoCalibration/></TextBlock.DataContext>
</TextBlock>
</StackPanel>
One of my friend is also doing the same mistake.
// rest of class including code that changes the above **_TempRelayValue**
here you have mansioned that you will change the _tempRelayVAlue varialble. A variable don't have any notification assocated with it. So what you have to do is set the value via proerty like below and this should notify the UI that model or VM values has chagned. as you have implemanted the notifycation into properties not in variables.
TempRelayValue = yourvalues;