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
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
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");
}
}
}
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";
This might be a duplicate question, but I'm unable to find a good answer. All the answers like Binding WinForms ListBox to object properties don't work on my WinForm. I'll explain.
I have a list of Firms that I show in a ListBox. I would like when the SelectedItem changes, that it updates a property on my model. So that I can read the Firms properties.
// the classes
public class Firm
{
public string Name { get; set; }
public int Id { get; set; }
// more properties ...
}
public class MyModel : INotifyPropertyChanged
{
private Firm _firm = new Firm();
public Firm Firm
{
get { return _firm; }
set
{
if (Equals(value, _firm)) return;
_firm = value;
OnPropertyChanged();
}
}
// more properties and OnPropertyChanged() ...
}
// the form
private MyModel Model;
public void MyForm(List<Firm> firms)
{
lstFirm.DataBindings.Add("SelectedItem", Model, "Firm",
true, DataSourceUpdateMode.OnPropertyChanged);
lstFirm.DisplayMember = "Name";
lstFirm.ValueMember = "Id";
lstFirm.DataSource = firms;
}
public void lstFirm_SelectedIndexChanged(object sender, EventArgs e)
{
// Do something with Model.Firm
}
The problem is that Model.Firm null is. Does anybody have an idea what I need to do to make a databinding between the ListBox and the Model? I bind other stuff on my WinForm (such as TextBoxes to String properties) and those work nicely.
From what I can see, your code never sets Model.Firm... Where's the constructor for MyModel? If you don't provide one, Model.Firm will stay null unless you explicitly set it. Here's an example constructor:
public MyModel(Firm firm)
{
_firm = firm;
}
Also, Equals() doesn't do what you think it does. Instead of if (Equals(value, _firm)) return;, use this: if (value == _firm) return;
Ok, so after a weekend of testing, I figured it out.
I was debuging in the SelectedIndexChanged event and didn't see the change in my Model.Firm just yet. But as the SelectedItemChanged event is only internal, I couldn't use that and that's where the databinding on SelectedItem applies the values to databound items.
Now the reason why the change isn't visible yet, is because the SelectedItemChanged is only fired after the SelectedIndexChanged is executed. So internally in the ListBox control, it probably looks like
this.SelectedIndex = value;
this.SelectedItem = FindItem(value);
this.SelectedIndexChanged(/*values*/);
this.SelectedItemChanged(/*values*/); // Apply databinding changes
So it's quite normal that you don't see the changes, before the change has occured. And I didn't know this, so I was kinda stumped why the SelectedItem (who was displaying the changed value) wasn't copied over to the databound model property.
So I didn't have to change anything major to get it all working. :)
I have a ListBox that is bound to a BindingList collection. This works great.
My only grief occurs when the first item enters the collection. The default behavior of the ListBox is to select that item - yet, this does not raise the SelectedIndexChanged event. I assume this is because the SelectedIndex is initially set to null; on becoming anything but null, the index isn't actually changed; rather assigned. How can I stop the default behavior of selecting (highlighting) the first initial item added to the ListBox?
If my assumption is wrong, please shed some light?
Update
Here is the core parts of my code thus far.
public UavControlForm()
{
InitializeComponent();
_controlFacade = new UavController.Facade.ControlFacade();
UpdateFlightUavListBox();
}
private void UpdateFlightUavListBox()
{
lsbFlightUavs.DataSource = _controlFacade.GetFlightUavTally();
lsbFlightUavs.DisplayMember = "Name";
}
private static BindingList<FlightUav> _flightUavTally = new BindingList<FlightUav>();
public BindingList<FlightUav> FlightUavTally
{
get { return _flightUavTally; }
}
public void AddFlightUav(double[] latLonAndAlt)
{
FlightUav flightUav = new FlightUav();
flightUav.Latitude = latLonAndAlt[0];
flightUav.Longitude = latLonAndAlt[1];
flightUav.Altitude = latLonAndAlt[2];
_flightUavTally.Add(flightUav);
UtilStk.InjectAircraftIntoStk(flightUav.Name);
flightUav.SetFlightDefaults();
PlayScenario();
}
Update:
So, setting lsbFlightUavs.SelectedIndex = -1 solves the problem. The above method AddFlightUav() is called from a button's OnClick handler in a second form from the main form. How can I call lsbFlightUavs.SelectedIndex = -1 from this second form when the AddFlightUav() method returns? I know I can make the ListBox static, but that seems like bad practice to me.. what would be a more elegant solution?
Using WinForms, I implemented the Singleton pattern. This enabled me to access the ListBox control from my second form.
Form 1
private static UavControlForm _instance = new UavControlForm();
private UavControlForm()
{
InitializeComponent();
}
public static UavControlForm Instance
{
get { return _instance; }
}
public ListBox FlightUavListBox
{
get { return lsbFlightUavs; }
}
Form 2
UavControlForm.Instance.FlightUavListBox.SelectedIndex = -1;