I have a Window which contains a control.
The control has a viewmodel set as the DataContext object.
The Window object has its own ViewModel set as the DataContext.
If I bind a property of the control inside the Window XAML how does it determine which DataContext to use?
Data context is resolved using bottom approach. It means that first the property is searched in the control itself, then the parent of control, Then parent of patent and so on utill it finds the property or reaches at the root window.
There are some possible ways:
1) You can decide from the code behind what would be the data context: DataContext = this; <- for example
2) you can do it through the DictionaryResources which you can write in the App.xaml:
<DataTemplate DataType="{x:Type viewModel:SolutionsToRecoverViewModel}">
<someView:SolutionsRecovery/>
</DataTemplate>
3) you can create a dictionary file buy yourself (and write the las xaml code) and in the initalization of the window register it:
public class someClass
{
private static bool _registerUIMapping = false;
public CopyNPasteBottemViewModel()
{
if (!_registerUIMapping)
{
ResourceDictionary MyResourceDictionary = new ResourceDictionary();
MyResourceDictionary.Source = new Uri("somePath/UIMapping.xaml", UriKind.Relative);
Application.Current.Resources.MergedDictionaries.Add(MyResourceDictionary);
_registerUIMapping = true;
}
}
private bool _doThisForTheNextConflictProperty = false;
public bool DoThisForTheNextConflict
{
get
{
return _doThisForTheNextConflictProperty;
}
set
{
_doThisForTheNextConflictProperty = value;
OnPropertyChanged("DoThisForTheNextConflict");
}
}
}
Related
I have the following code in the ViewModel class, in the constructor where I define that the buttons are always Enabled = false when starting the form ...
public partial class EditarConceptoWindow : ChildWindow
{
public EditarConceptoWindow(string documentoId)
{
InitializeComponent();
viewModel.Saved += new EventHandler<Microsoft.Practices.Prism.Events.DataEventArgs<bool>>(ViewModel_Saved);
viewModel.Calculation += new EventHandler<Microsoft.Practices.Prism.Events.DataEventArgs<bool>>(ViewModel_Calculation);
this.DataContext = viewModel;
BtnCalcular.IsEnabled = false;
BtnObtenerTCRM.IsEnabled = false;
....... rest of code
In a checked event of a check box when placing the Selected check box, it must be enabled to be set to true, depending on whether a particular element of a combobox has been selected as well;
private void cbAgregarManual_Checked(object sender, RoutedEventArgs e)
{
if (this.ComboConcepto.SelectedValue.ToString() == "DPI")
{
BtnCalcular.IsEnabled = true;
BtnObtenerTCRM.IsEnabled= true;
}
}
This must be done if and only if the checkbox is clicked and the DPI value is selected in the combobox.
But the behavior of the buttons is that when starting the form they are always IsEnabled = true and if the checkbox control is clicked if it works but I can't find a reason because only until I click the checkbox it works, there are some controls (such as TextBoxes, and also the buttons) with this directive in the XAML.
IsEnabled="{Binding ElementName=cbAgregarManual, Path=IsChecked }"
I suggest that you centralize the logic of the enabling into one property to avoid this mismatch of logic setting confusion.
In this new property it will use INotifyPropertyChanged for the notification of that change, but called in from other properties. So to sum up, when any of the associated values change, they do the notify call on the logic property; that process ensures that the control is properly en/dis-abled.
Example
Such as this pseudo code where I check three different other properties:
public bool IsEnabledCombo { get { return ClickStatus
&& OtherStatus
&& !string.IsNullOrEmpty( UserText); }
public bool ClickStatus { get { return _clickStatus; }
set { _clickStatus = value;
NotifyPropertyChanged("ClickStatus");
NotifyPropertyChanged("IsEnabledCombo");
}}
public bool OtherStatus { get { return _otherStatus; }
set { _clickStatus = value;
NotifyPropertyChanged("OtherStatus");
NotifyPropertyChanged("IsEnabledCombo");
}}
public string UserText { ...
set { _userText = value;
NotifyPropertyChanged("UserText");
NotifyPropertyChanged("IsEnabledCombo");
Bind your control as such
IsEnabled="{Binding IsEnabledCombo }"
So wherever one of the related values can change they also call NotifyPropertyChanged("IsEnabledCombo"); and the control status is updated automatically.
I provide a another notify chained example doing similar on my blog:
Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding
My boss had downloaded a xaml control that I must use in app. It looks like ok but there is a strange trouble with inner logic - the
property CurrentColor (that I need to use in our app) is defined in control.xaml.cs file like :
public SolidColorBrush CurrentColor
{
get { return (SolidColorBrush)GetValue(CurrentColorProperty); }
set
{
SetValue(CurrentColorProperty, value);
ActiveColor = CurrentColor;
}
}
I am using this control in my dialog (that has its own view model class) and
I am writing this kind of binding:
CurrentColor="{Binding myOwnViewModel.ColorActualValue, Mode=Default, UpdateSourceTrigger=PropertyChanged}">
in myOwnViewModel.cs (that implements INotifyPropertyChanged) I have my property
public SolidColorBrush ColorActualValue{ // here is some logic}
But when I debug an app I have never target MY CurrentColor - I am always go to the CurrentColor from control.xaml.cs
How could I bind this "third party" control to my property from my ViewModel?
Perhaps this is because (control.xaml.cs):
public static DependencyProperty CurrentColorProperty =
DependencyProperty.Register("CurrentColor", typeof(SolidColorBrush), typeof(ColorPickerComboBox), new PropertyMetadata(Brushes.Chocolate));
public static RoutedEvent ActiveColorChangedEvent = EventManager.RegisterRoutedEvent("ActiveColorChanged",
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ColorPickerComboBox));
I have found the question What's wrong with "DataContext = this" in WPF user controls? and removed DataContext = this; from constructor of this control - but this still not helped
Should the binding look like this?
CurrentColor="{Binding ColorActualValue, Mode=Default, UpdateSourceTrigger=PropertyChanged}">
The DataContext of your 'dialog' needs to be the ViewModel class that contains the ColorActualValue property
public Dialog()
{
DataContext = new myOwnViewModel();
}
In my WPF application, I have some properties which I have bound to the XAML counterpart, but for some reason do not get set whenever their values change. I have implemented the INotifyPropertyChanged interface as well as set my DataContext for this View too, and it is still not picking up any changes.
I have this same pattern for other properties within this ViewModel which do work, while others don't.
Here is a snippet of my current code:
ViewModel
public class TestViewModel : INotifyPropertyChanged
{
private string testString;
public TestViewModel()
{
.....
this.RunCommand = new RelayCommand(this.RunAction);
}
public string TestString
{
get
{
return this.testString;
}
set
{
this.testString = value;
this.OnPropertyChanged("TestString");
}
}
private void RunAction()
{
.....
this.testString = "Running.";
}
}
View
<StatusBarItem>
<TextBlock Text="{Binding Path=TestString, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />
</StatusBarItem>
DataContext (set in code-behind of another MainWindow class)
var testViewModel = SimpleIoc.Default.GetInstance<TestViewModel>();
var testWindow = new TestWindow() { DataContext = testViewModel };
testingWindow.Show();
If it helps, this is part of a multi-windowed application which uses MVVM-Light to pass properties between classes.
You are not changing the value of the TestString, you are assigning a command to change the value but you do not seem to be executing it.
this.RunCommand = new RelayCommand(this.RunAction);
Bind that command to something or execute it manually from somewhere.
Also you need to assign the property not the field
this.TestString = "Running.";
I found the problem. You are only updating the private property testString. But you do not update the property TestString so the notify is never called.
Try this:
this.TestString = "Running";
i have a problem with my Checkboxes.
I have a MainWindow(), from here i open my second Window to set some searchpropertys for the user.
(in wich fields they want to search ... like Name, Firstname and other)
After the user confirmed his choices, the Window get closed and the values get saved in the app.propertys.
On the next start up of the application the values from the session before are still how they should be, so this part works.
Now the problem:
If i now open the Window all the Checkboxes arnt set like they should be?!
I have them bound to my ViewModel like this :
<CheckBox x:Name="cVersichertenstatus" Content=... **IsChecked="{Binding Versichertenstatuschecked}"** .../>
The code for my bindings lock like this:
private bool versichertenstatusischecked;
public bool Versichertenstatuschecked
{
get
{
return versichertenstatusischecked;
}
set
{
if (Versichertenstatuschecked != value)
{
versichertenstatusischecked = value;
//this.OnPropertyChanged("Versichertenstatuschecked");
}
}
}
After the start up i set all the binding propertys with the values of the app.propertys.
But it change nothing. The Checkboxvalues are always false :-(
I guess its because i dont use OnPropertyChanged, but if i try i get this error:
object reference not set to an instance of the object
I dont get it, i have alot of bindings and all work fine, only the checkbox things do not.
Can someone explain me what i have to do to resolve this error?
Edit:
Set the Datacontext :
public MainWindow()
{
InitializeComponent();
SetupBindings();
var l = new app_config_load();
l.load();
}
private void SetupBindings()
{
pViewModelList viewModel = new pViewModelList();
plistview.DataContext = viewModel;
}
and the load() class:
public void load()
{
Properties.Settings get = new Properties.Settings();
pViewModelList a = new pViewModelList();
a.Nachnamechecked = get.cnachname_app;
a.Versichertenstatuschecked = get.cversichertenstatus_app;
a.Geburtsdatumchecked = get.cgeburtsdatum_app;
a.Versicherungsnrchecked = get.cversichertennummer_app;
a.Vornamechecked = get.cvorname_app;
get.Save();
}
Do i have to initialize somehow the Propertys first? Thought this happens automaticly ?!
Did you set the DataContext?
public MyWindow(MyClass myClass){
InitializeComponent();
this.DataContext = myClass;
}
Before InitializeComponent(); all of your GUI - Elements will be null!
How to get your Element from MainWindow:
public MyClass GetData()
{
MyClass data = this.DataContext as MyClass;
return data;
}
and try:
IsChecked="{Binding Path=Versichertenstatuschecked}"
I think I know what the problem is. You miss the Mode of the binding.
IsChecked="{Binding Versichertenstatuschecked, Mode=TwoWay}"
Using this will trigger changes in the viewModel to be displayed in the view.
i solved the problem by my self.
I just needed to wait till the Window is loaded before i use my Class to set the bindingpropertys.
I used the "loaded" event to call the Class and jeah, no longer any Object Reference errors :)
Such things are realy frustrating.
Cya
So here I come creating a user control. It consists of a treeview dropping down from a combobox.
Actually, there is a button with a control (DropTree) dropping down from its contextmenu. So I have a control DropTree.
public partial class DropTree : UserControl
{
public TreeView TreeView
{ get{return treeView;} }
public DropTree()
{ InitializeComponent(); }
}
to simplify it, I made the TreeView control public, then I have my main control which is called ComboTreeView.
Now I need to represent some treeview properties in it, so I define several dependency properties:
public static DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(ComboTreeView), new FrameworkPropertyMetadata { Inherits = true, IsNotDataBindable = false, DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
and in constructor it is:
public ComboTreeView()
{
InitializeComponent();
TreeViewControl.SetBinding(TreeView.SelectedItemProperty, new Binding("SelectedItem") { Source = this, Mode = BindingMode.TwoWay });
}
and it all seems ok, until i run it. It crashes saying that SelectedItem cannot be binded to data. I don't understand?
The same goes for ItemsSource and SelectedValue... but only SelectedValuePath property defined this way goes fine.
Can anybody help? Or is there any other way to bind it correctly?
PS: by the way, I need to use DataBinding for ComboTreeView in my code later.
Try to set the Binding on SelectedValue instead of SelectedItem.
TreeView.SelectedItem is a readonly property. You can't set it, whether explicitly or through binding. In order to select a node in a TreeView, you must set the TreeViewItem.IsSelected property to true.