I have a TextBox, its Text property is bound to a property of type double named Grade. I also have a CheckBox, when the CheckBox is checked I want the Grade to take an auto calculated value (i.e. automatically set to MaxScore/Count of questions). If the CheckBox is not checked then I want to set and change the Grade Manually. My question is how can I implement this?
<TextBox Height="23"
Visibility="{Binding Path=Visible2, Converter={StaticResource boolToVis}, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding Path=Grade,UpdateSourceTrigger =PropertyChanged,Mode=TwoWay}"
HorizontalAlignment="Left" Margin="376,453,0,0"
Name="textBox3" VerticalAlignment="Top" Width="120" />
and i bind this to:
public double Grade
{
get
{
return grade;
}
set
{
grade = value;
OnPropertyChanged("Grade");
foreach (ExaminationQuestion exaq in
this.Examination.ExaminationQuestions)
{
if (exaq.Question.Guid == SelectedQuestionDropList.Guid)
{
exaq.Grade = value;
}
}
}
}
Thanks
in your VM, have another public Property Auto and make sure your Checkbox binds to it and so does your TextBox (so that it becomes readonly/disabled/hidden). And my default AutoCheck will be true
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Label Content="Grade" />
<TextBox Height="23" Width="120"
Text="{Binding Path=GradeDisplay}"
IsEnabled="{Binding EnableBox}"
/>
<Label Content="Auto?" />
<CheckBox IsChecked="{Binding IsAuto}" />
</StackPanel>
And for the View Model
public bool EnableBox { get; set; }
public string GradeDisplay
{
get
{
if (EnableBox)
return Grade.ToString();
else
return "AUTO";
}
set
{
double result;
if (double.TryParse(value, out result))
Grade = result;
NotifyPropertyChanged("GradeDisplay");
}
}
private bool _IsAuto;
public bool IsAuto
{
get
{
return _IsAuto;
}
set
{
_IsAuto = value;
EnableBox = !value;
NotifyPropertyChanged("GradeDisplay");
NotifyPropertyChanged("EnableBox");
}
}
private double _Grade;
private double Grade
{
set
{
_Grade = value;
}
get
{
if (IsAuto)
{
// CODE TO GET AUTO GRADE
return 0.0;
}
else
{ // RETURN MANUALLY SET GRADE
return _Grade;
}
}
}
// CTOR
public MainWindowViewModel()
{
IsAuto = false;
}
Related
I am trying to realize Wordle(Game) in WPF as a project to practice. In the ViewModel I have a Property(e.g. FirstWord) for the first, second, third, fourth and fifth word, all of which have INotifyPropertyChanged implemented. I would like to avoid creating a property for every single textbox (would be 5x5). Therefore, my model consists of 1st letter, 2nd letter, 3rd letter, etc. In XAML the binding looks like this: {Binding FirstWord.FirstLetter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}.
When debugging, the program does not even jump into the setter, it was not detected that the value has changed. What can be the reason for this?
ViewModel
public class WordleViewModel : ObservableObject
{
private int counter;
public string solutionWord;
private static int[] _stateColor = new int[5];
public static int[] StateColor
{
get { return _stateColor;} private set { _stateColor = value; }
}
private SafeWordsModel _firstWord;
public SafeWordsModel FirstWord
{
get { return _firstWord; }
set
{
_firstWord = value;
OnPropertyChanged();
}
}
//....
public WordleViewModel()
{
solutionWord = "TESTE";
}
}
Model (Do I really need variable + Property and the INotifyChanged here?)
public class SafeWordsModel : ObservableObject
{
private string _firstLetter;
private string _secondLetter;
private string _thirdLetter;
private string _fourthLetter;
private string _fifthLetter;
public string FirstLetter
{
get { return _firstLetter; }
set { _firstLetter = value; OnPropertyChanged(); }
}
public string SecondLetter
{
get { return _secondLetter; }
set { _secondLetter = value; OnPropertyChanged(); }
}
public string ThirdLetter
{
get { return _thirdLetter; }
set { _thirdLetter = value; OnPropertyChanged(); }
}
public string FourthLetter
{
get { return _fourthLetter; }
set { _fourthLetter = value; OnPropertyChanged(); }
}
public string FifthLetter
{
get { return _fifthLetter; }
set { _fifthLetter = value; OnPropertyChanged(); }
}
public SafeWordsModel()
{
this.FirstLetter = _firstLetter;
this.SecondLetter = _secondLetter;
this.ThirdLetter = _thirdLetter;
this.FourthLetter = _fourthLetter;
this.FifthLetter = _fifthLetter;
}
}
View
public WordleView()
{
InitializeComponent();
ViewModel = new WordleViewModel();
}
public WordleViewModel ViewModel
{
get { return DataContext as WordleViewModel; }
set { DataContext = value; }
}
public void FocusNext(object sender, TextChangedEventArgs e)
{
if (((TextBox)sender).MaxLength == ((TextBox)sender).Text.Length)
{
// move focus
var ue = e.OriginalSource as FrameworkElement;
e.Handled = true;
ue.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
XAML for one Word
<StackPanel Orientation="Horizontal"
FocusManager.FocusedElement="{Binding ElementName=tbx11}">
<TextBox x:Name="tbx11"
Style="{StaticResource Input_tbx}"
TextChanged="FocusNext"
Background="{Binding ElementName=Line2_ckb, Path=IsChecked, Converter={StaticResource brush1}}"
Text="{Binding FirstWord.FirstLetter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="tbx12"
Style="{StaticResource Input_tbx}"
TextChanged="FocusNext"
Background="{Binding ElementName=Line2_ckb, Path=IsChecked, Converter={StaticResource brush2}}"
Text="{Binding FirstWord.SecondLetter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="tbx13"
Style="{StaticResource Input_tbx}"
TextChanged="FocusNext"
Text="{Binding FirstWord.ThirdLetter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="tbx14"
Style="{StaticResource Input_tbx}"
TextChanged="FocusNext"
Background="{Binding ElementName=Line2_ckb, Path=IsChecked, Converter={StaticResource brush4}}"
Text="{Binding FirstWord.FourthLetter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="tbx15"
TextChanged="FocusNext"
Style="{StaticResource Input_tbx}"
Background="{Binding ElementName=Line2_ckb, Path=IsChecked, Converter={StaticResource brush5}}"
Text="{Binding FirstWord.FifthLetter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
ObservableObject Class
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
So far it has always worked well with INotifyPropertyChanged. It should set the value that comes from the textbox accordingly in the property and I can also use this value. Feel free to make suggestions on other places in the code, I'm still very new to WPF.
I need some help with binding. Twoway mode doesn't work at all.
I fill my window with data passed to the constructor and it's working fine.
The problem is that I can't rewrite some data imputed in the window control even if I use Twoway binding.
Below is how I open window
var tempInregistrare = BaseConnection.GetInregistrareById(itemSelected.InregistrareId.ToString());
var tichet = new TichetView(new InregistrareModel {
Id =tempInregistrare.Id,
NumeFurnizor = tempInregistrare.NumeFurnizor,
IdFurnizor = tempInregistrare.IdFurnizor,
NumeProdus = tempInregistrare.NumeProdus......
ticket.Show();
Here is window constructor with DataContext set to self.
public TichetView(InregistrareModel inregistrare)
{
InitializeComponent();
InregistrareModel = inregistrare;
DataContext = this;
grdButtonsPrint.Visibility = Visibility.Visible;
}
public InregistrareModel InregistrareModel
{
get => inregistrareModel;
set
{
if (value != inregistrareModel)
{
inregistrareModel = value;
NotifyPropertyChanged();
}
}
}
public class InregistrareModel
{
public int Id { get; set; }
public int IdProdus { get; set; }
public int IdFurnizor { get; set; }
public string NumeProdus { get; set; }
public string NumeFurnizor { get; set; }
public string NrAuto { get; set; }
public string NumeSofer { get; set; }
public double CantitateInitiala { get; set; }
public double CantitateIesire { get; set; }
public double Umiditate { get; set; }
public double CantitateScazuta { get; set; }
public double CantitateMarfa { get; set; }
public DateTime DataIntrare { get; set; }
public DateTime DataIesire { get; set; }
public FurnizorModel Furnizor { get; set; }
public int NIR { get; set; }
}
And here is Xaml of window
<TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">Intrare</TextBlock>
<TextBox Grid.Row="2" Grid.Column="3" Text="{Binding InregistrareModel.CantitateInitiala}"/>
<TextBlock Grid.Row="4" Grid.Column="2" VerticalAlignment="Center">Umiditatea (%)</TextBlock>
<TextBox x:Name="txtUmiditate" Grid.Row="4" Grid.Column="3" IsReadOnly="False" Text="{Binding InregistrareModel.Umiditate, Mode=TwoWay}"/>
<TextBlock Grid.Row="5" Grid.Column="2" VerticalAlignment="Center">Cantitatea scazuta</TextBlock>
<TextBox x:Name="txtCantitateScazuta" Grid.Row="5" Grid.Column="3" IsReadOnly="False" Text="{Binding InregistrareModel.CantitateScazuta, Mode=TwoWay}"/>
<TextBlock Grid.Row="6" Grid.Column="2" VerticalAlignment="Center">Iesire</TextBlock>
<TextBox Grid.Row="6" Grid.Column="3" Text="{Binding InregistrareModel.CantitateIesire}"/>
<TextBlock Grid.Row="7" Grid.Column="2" VerticalAlignment="Center">Dată iesire</TextBlock>
<TextBox Grid.Row="7" Grid.Column="3" Text="{Binding InregistrareModel.DataIesire,StringFormat='{}{0:HH:HH dd/M/yyyy}'}"/>
<TextBlock Grid.Row="10" Grid.Column="2" VerticalAlignment="Center">Net</TextBlock>
<TextBox Grid.Row="10" Grid.Column="3" Text="{Binding InregistrareModel.CantitateMarfa}"/>
All text boxes are filled with data expect the second and third that I fill by hand.
The goal that I can't achieve right now is to take data from 1st textbox(InregistrareModel.CantitateInitiala) to type in 3rd(txtCantitateScazuta) some data and show the result in the last textbox so after I update my database with this data.
I totally agree with #Peter Boone.
You have a lot of gross architectural mistakes in the Solution and for good reason it needs to be completely redone.
But if you do not have such an opportunity, try to implement this option.
For fields (TextBox, TextBlock) that change, declare properties in the Window.
In the body of these properties, implement communication with the parent container (InregistrareModel) and with other properties.
Let's say you have a CantitateInitiala property that affects the value of the CantitateScazuta property.
public InregistrareModel InregistrareModel
{
get => inregistrareModel;
set
{
if (value != inregistrareModel)
{
inregistrareModel = value;
NotifyPropertyChanged();
CantitateInitiala = InregistrareModel.CantitateInitiala;
}
}
public double CantitateInitiala
{
get => InregistrareModel.CantitateInitiala;
set
{
if (value != InregistrareModel.CantitateInitiala)
{
InregistrareModel.CantitateInitiala = value;
NotifyPropertyChanged();
// Calculation of the CantitateScazuta value
double cantSc = CantitateInitiala / 123.45;
CantitateScazuta = cantSc;
}
}
}
public double CantitateScazuta
{
get => InregistrareModel.CantitateScazuta;
set
{
if (value != InregistrareModel.CantitateScazuta)
{
InregistrareModel.CantitateScazuta = value;
NotifyPropertyChanged();
}
}
}
In XAML, change the bindings for these fields:
<TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">Intrare</TextBlock>
<TextBox Grid.Row="2" Grid.Column="3" Text="{Binding CantitateInitiala}"/>
<TextBlock Grid.Row="4" Grid.Column="2" VerticalAlignment="Center">Umiditatea (%)</TextBlock>
<TextBox x:Name="txtUmiditate" Grid.Row="4" Grid.Column="3" IsReadOnly="False" Text="{Binding InregistrareModel.Umiditate, Mode=TwoWay}"/>
<TextBlock Grid.Row="5" Grid.Column="2" VerticalAlignment="Center">Cantitatea scazuta</TextBlock>
<TextBox x:Name="txtCantitateScazuta" Grid.Row="5" Grid.Column="3" IsReadOnly="False" Text="{Binding CantitateScazuta, Mode=TwoWay}"/>
Но нужно тщательно продумать алгоритм зависимостей свойств в том случае, если они имеют циклическую зависимость.
То есть не только изменение CantitateInitiala влияет на значение CantitateScazuta, но также существует обратная зависимость CantitateInitiala от изменения CantitateScazuta.
You should make the ViewModel a separate file/class. Let's call it TichetViewModel. This class should have the InregistrareModel. Something like this:
public class TichetViewModel : ObservableObject
{
private InregistrareModel _InregistrareModel;
public InregistrareModel InregistrareModel
{
get { return _InregistrareModel; }
set
{
if (value != _InregistrareModel)
{
_InregistrareModel = value;
NotifyPropertyChanged();
}
}
}
public TichetViewModel()
{
InregistrareModel = new InregistrareModel();
}
}
Then set the DataContext of TichetView in either you code behind or in xaml.
Code behind:
TichetView.xaml.cs
public TichetView()
{
InitializeComponent();
DataContext = new TichetViewModel();
}
or in xaml
TichetView.xaml
<Window.DataContext>
<local:TichetViewModel />
</Window.DataContext>
I like doing this in xaml because the Intellisense in Visual Studio picks this up and autocompletes based on the classes.
Implement INotifyPropertyChanged on the properties of the InregistrareModel. Like this:
public class InregistrareModel : ObservableObject
{
private int _Id;
public int Id
{
get { return _Id; }
set
{
if (value != _Id)
{
_Id = value;
NotifyPropertyChanged();
}
}
}
private string _NumeProdus;
public string NumeProdus
{
get { return _NumeProdus; }
set
{
if (value != _NumeProdus)
{
_NumeProdus = value;
NotifyPropertyChanged();
}
}
}
}
I have the following "element":
public class ReportElementViewModel
{
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
public bool IsChecked
{
get { return _isChecked; }
set
{
if (_isChecked != value)
{
_isChecked = value;
RaisePropertyChanged("IsChecked");
}
}
}
}
My ViewModel contains many ReportElementViewModels:
public abstract class ReportViewModel<TPrimaryModel> : SharedViewModel
where TPrimaryModel : Model, new()
{
public ObservableCollection<ReportElementViewModel> ReportElementViewModels
{
get { return _reportElementViewModels; }
set
{
if (_reportElementViewModels != value)
{
_reportElementViewModels = value;
RaisePropertyChanged("ReportElementViewModels");
}
}
}
}
I removed the members to reduce code complexity but they are implemented correctly.
In my view I want to show all ReportElementViewModels by showing their Name and IsChecked (checkbox).
I thought the ItemsControl would be the right "tool", however it doesn't work (nothing is shown):
<ItemsControl ItemsSource="{Binding ReportElemetViewModels}" Height="auto" VerticalAlignment="Top" Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="269"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You have made a spelling mistake in your Binding.
ItemsSource="{Binding ReportElemetViewModels}"
Should be:
ItemsSource="{Binding ReportElementViewModels}"
I am pretty new to windows phone app development. I am trying to fill a list box but it's not getting populated. I have debugged and saw that View model is returning the data in OnNavigatioTo method but still list box is empty. Can somebody suggest any thing after looking at the code below:
Xaml page
`
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="list box" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="mylistbox" ItemsSource="{Binding Path=Diet}" Margin="0,0,0,101" SelectionChanged="mylistbox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<!--<Grid Height="80" VerticalAlignment="Top">-->
<TextBlock x:Name="nameblock" Text="{Binding foodName}" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Height="57" Width="236" FontSize="36" Margin="10,10,0,0" />
<!--<Button Content="Edit" HorizontalAlignment="Left" Margin="275,0,0,0" VerticalAlignment="Top" Height="80" Width="181" Click="Button_Click"/>-->
<!--</Grid>-->
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!--<TextBlock Grid.Column="0" x:Name="txtFoodName" Text="{Binding foodName}" VerticalAlignment="Center"/>-->
<!--<TextBlock x:Name="Studentnameblock" HorizontalAlignment="Left" Margin="40,543,0,0" TextWrapping="Wrap" Text="Student name" VerticalAlignment="Top" Height="64" Width="193" FontSize="30"/>-->
<TextBlock x:Name="marksblock" HorizontalAlignment="Left" Margin="322,543,0,0" TextWrapping="Wrap" Text="Marks" VerticalAlignment="Top" Height="64" Width="134" FontSize="30"/>
</Grid>
</Grid>`
Code behind
public partial class DietEdit : PhoneApplicationPage
{
public DietViewModel ViewModel;
public DietEdit()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
try
{
ViewModel = DietViewModel.GetDefault();
this.DataContext = ViewModel.GetAllItems();
}
catch (SQLiteException ex)
{
MessageBox.Show("Can't find that item: " + ex.Message);
}
}
Diet Class
public class Diet : ViewModelBase
{
private long mdietid = -1;
public long dietID
{
get { return mdietid; }
set { SetProperty(ref mdietid, value); }
}
private long mmealid = -1;
public long mealID
{
get { return mmealid; }
set { SetProperty(ref mmealid, value); }
}
private string mmealname = string.Empty;
public string mealName
{
get { return mmealname; }
set { if (SetProperty(ref mmealname, value)) IsDirty = true; }
}
private string mfoodname = string.Empty;
public string foodName
{
get { return mfoodname; }
set { if (SetProperty(ref mfoodname, value)) IsDirty = true; }
}
private long mserving = 0;
public long serving
{
get { return mserving; }
set { SetProperty(ref mserving, value); }
}
private long mcalories = 0;
public long calories
{
get { return mcalories; }
set { SetProperty(ref mcalories, value); }
}
private string mcreateddate = DateTime.Today.ToString();
public string createdDate
{
get { return mcreateddate; }
set { SetProperty(ref mcreateddate, value); }
}
private string mupdateddate = DateTime.Today.ToString();
public string updatedDate
{
get { return mupdateddate; }
set { SetProperty(ref mupdateddate, value); }
}
private bool isDirty = false;
public bool IsDirty
{
get { return isDirty; }
set { SetProperty(ref isDirty, value); }
}
internal Diet()
{ }
internal Diet(long dietid, long mealid, string foodname, long serving, long calories, string createddate, string updateddate, string mealmname)
{
this.dietID = dietid;
this.mealID = mealid;
this.foodName = foodname;
this.serving = serving;
this.calories = calories;
this.createdDate = createdDate;
this.updatedDate = updatedDate;
this.mealName = mealmname;
this.isDirty = false;
}
public bool IsNew { get { return dietID < 0; } }
}
Edit: ViewModel.GetAllItems() is actually returning a collection of type Diet. See the image below:
Ive posted another thread regarding refreshing a silverlight listbox - In the meantime Ive become slightly more familiar with the issue. It has to do with implementing the ObservableCollection interface.
Im using RIA services to populate a listbox with a collection of type ObservableCollection. The problem is refreshing the Items once the database has been updated. I am using a silverlight child window to save the data to the database, and this is happening correctly On the close event of the child window.
Can anyone give me more information as to why the ListBox is not updating.
Thanks
You need to make your poco class that is used within your ObservableCollection implement INotifyChanged.
Example:
<viewModels:LocationsViewModel x:Key="viewModel" />
.
.
.
<ListView
DataContext="{StaticResource viewModel}"
ItemsSource="{Binding Locations}"
IsItemClickEnabled="True"
ItemClick="GroupSection_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="0,0,10,0" Style="{ThemeResource ListViewItemTextBlockStyle}" />
<TextBlock Text="{Binding Latitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{ThemeResource ListViewItemTextBlockStyle}" Margin="0,0,5,0"/>
<TextBlock Text="{Binding Longitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{ThemeResource ListViewItemTextBlockStyle}" Margin="5,0,0,0" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public class LocationViewModel : BaseViewModel
{
ObservableCollection<Location> _locations = new ObservableCollection<Location>();
public ObservableCollection<Location> Locations
{
get
{
return _locations;
}
set
{
if (_locations != value)
{
_locations = value;
OnNotifyPropertyChanged();
}
}
}
}
public class Location : BaseViewModel
{
int _locationId = 0;
public int LocationId
{
get
{
return _locationId;
}
set
{
if (_locationId != value)
{
_locationId = value;
OnNotifyPropertyChanged();
}
}
}
string _name = null;
public string Name
{
get
{
return _name;
}
set
{
if (_name != value)
{
_name = value;
OnNotifyPropertyChanged();
}
}
}
float _latitude = 0;
public float Latitude
{
get
{
return _latitude;
}
set
{
if (_latitude != value)
{
_latitude = value;
OnNotifyPropertyChanged();
}
}
}
float _longitude = 0;
public float Longitude
{
get
{
return _longitude;
}
set
{
if (_longitude != value)
{
_longitude = value;
OnNotifyPropertyChanged();
}
}
}
}
public class BaseViewModel : INotifyPropertyChanged
{
#region Events
public event PropertyChangedEventHandler PropertyChanged;
#endregion
protected void OnNotifyPropertyChanged([CallerMemberName] string memberName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(memberName));
}
}
}