Assign TextBox text to TextBlock - System.NullReferenceException: „Object reference not set …" - c#

C# UWP Application XAML (Body Mass Index Calculator - BMI)
I need to take TextBox txtKG.Textand pass it to txtDescription.Text
I'm assuming that i have to create instance of TextBox Class somehow but I'm stuck on this error for 2 days. I have tried many ways but I don't know exackly what to do.
ERROR MESSAGE:
System.NullReferenceException: „Object reference not set to an instance of an object.”
MY XAML segment:
<Slider x:Name="sldKG" HorizontalAlignment="Left" Margin="170,306,0,0" VerticalAlignment="Top" Width="184" ValueChanged="Slider_ValueChanged" Minimum="40" Maximum="150" Value="70"/>
<TextBox x:Name="txtKG" FontSize="18" HorizontalAlignment="Left" Margin="50,310,0,0" VerticalAlignment="Top" TextAlignment="Center" Text="{Binding ElementName=sldKG,Path=Value}"/>
<TextBlock FontSize="18" x:Name="kg" HorizontalAlignment="Left" Margin="121,316,0,0" Text="kg" TextWrapping="Wrap" VerticalAlignment="Top"/>
<Slider x:Name="sldCM" HorizontalAlignment="Left" Margin="170,366,0,0" VerticalAlignment="Top" Width="184" ValueChanged="Slider_ValueChanged" Minimum="145" Maximum="240" Value="170"/>
<TextBlock FontSize="18" x:Name="txtDescription" HorizontalAlignment="Left" Margin="52,499,0,0" Text="Type Your parameters and i wil show Your BMI" TextWrapping="Wrap" VerticalAlignment="Top" Height="96" Width="302" TextAlignment="Center"/>
MyPage.xaml.cs
namespace Kalkulator_BMI_UWP
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
txtDescription.Text = txtKG.Text; // <!-- HERE IS THIS ERROR
}

The problem is with the Slider value changed event, an error occurs since the controls have NOT yet been loaded (TextBlocks in your XAML),
and as a workaround (which I do in some of my projects), you can encapsulate the method with a try-catch statement like this:
private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
try
{
txtDescription.Text = txtKG.Text;
}
catch { }
}

Related

WPF Setting Window Data Context

I'm a relative beginner with WPF so please bear with me. I have a simple app that converts farenheit values to celcius and vice versa. I thought I would have a play with refactoring this to MVVM so I moved everything from my code-behind to a separate class and then set the dataContext programmatically. However I'm getting a lot of ..'does not exist in context errors'. Where am I going wrong? Thanks
XAML
<Window x:Class="FarenheitCelciusConverter.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Temperature Converter" Height="500" Width="500"
xmlns:local="clr-namespace:FarenheitCelciusConverter">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Height="473" Width="488">
<Label Height="28" HorizontalAlignment="Left" Margin="10,10,0,0" Name="lblF" VerticalAlignment="Top" Width="64" FontWeight="Bold">Farenheit</Label>
<Label Height="28" HorizontalAlignment="Left" Margin="10,42,0,0" Name="lblC" VerticalAlignment="Top" Width="64" FontWeight="Bold">Celcius</Label>
<TextBox Height="23" Margin="94,10,112,0" Name="tbFaren" VerticalAlignment="Top" Width="72" HorizontalAlignment="Left" />
<TextBox Height="23" Margin="94,42,112,0" Name="tbCelcius" VerticalAlignment="Top" Width="72" HorizontalAlignment="Left" />
<Button Margin="94,76,109,0" Name="btnConvert" Click="btnConvert_Click" Height="23" VerticalAlignment="Top" HorizontalContentAlignment="Center" Width="72" HorizontalAlignment="Left">Convert</Button>
<Image Name="image1" Stretch="Fill" Margin="94,112,240,228">
<Image.Source>
<BitmapImage DecodePixelWidth="200" UriSource="C:\Users\Winston\Pictures\thermometer.jpg"/>
</Image.Source>
</Image>
<TextBlock FontWeight="Bold" Height="21" Margin="195,12,173,0" Name="tblCelci" VerticalAlignment="Top" /><TextBlock FontWeight="Bold" Height="21" Margin="195,44,0,0" Name="tblFarenh" VerticalAlignment="Top" HorizontalAlignment="Left" Width="120" /><TextBlock FontWeight="Bold" Height="21" Margin="195,78,15,0" Name="tblCex" VerticalAlignment="Top" Foreground="Red" />
</Grid>
</Window>
Code behind
namespace FarenheitCelciusConverter
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new ConverterViewModel();
}
}
}
View Model
namespace FarenheitCelciusConverter
{
public class ConverterViewModel
{
private void btnConvert_Click(object sender, RoutedEventArgs e)
{
tblCex.Text = "";
try
{
if (tbCelcius.Text.Length != 0)
{
double celcius = Double.Parse(tbCelcius.Text);
if (celcius < 99999.0 && celcius > -99999.0)
{
tblFarenh.Text = Math.Round(1.8 * celcius + 32.0) + " F";
}
else
{
throw new OverflowException("Number limit exceeded!");
}
}
if (tbFaren.Text.Length != 0)
{
double farenh = Double.Parse(tbFaren.Text);
if (farenh < 99999.0 && farenh > -99999.0)
{
tblCelci.Text = Math.Round(0.555 * (farenh - 32.0)) + " C";
}
else
{
throw new OverflowException("Number limit exceeded!");
}
}
}
catch (Exception ex)
{
tblCex.Text = ex.Message;
}
}
}
}
When using MVVM data is passed back and forth from the View (Window1) and the ViewModel through Databinding. So each of your textboxes should be databound to a public property in your Viewmodel:
<TextBox Height="23" Margin="94,10,112,0" Name="tbFaren" VerticalAlignment="Top" Width="72" HorizontalAlignment="Left" Text="{Binding FahrenText}"/>
And your ViewModel will take the values in the properties, do something with them, and set the properties bound to the appropriate textboxes.
In this way, the Viewmodel is performing the logic and the View is interpreting the output according to the rules that you are giving it. Later on, you can change the rules in the View without messing with the ViewModel whereas using the codebehind often you have to explicitly set View settings alongside the program logic.
Also, be sure to implement iNotifyPropertyChanged on your ViewModel , otherwise the UI wont know when the databound property values have changed and it wont update. Check out this post for an example.
Also here is the MSDN article on Databinding in WPF.

How group wpf controls and send group to method

I have 2 buttons and they do the same on different controls. How can i make this better? Because now i too much copy/paste. Here is image and code.
enter image description here
private void button_ClickOld(object sender, RoutedEventArgs e)
{
TextBoxOld.Text = SelectCatalog();
if (File.Exists(TextBoxOld + ConfigFilePath))
{
GetClientProperty(TextBoxOld.Text);
UpdateOldLabel();
}
else
{
LogsTextBox.AppendText("\nWrong folder selected - Config file doesn't exist");
}
}
private void button_ClickNew(object sender, RoutedEventArgs e)
{
TextBoxNew.Text = SelectCatalog();
if (File.Exists(TextBoxNew + ConfigFilePath))
{
GetClientProperty(TextBoxNew.Text);
UpdateNewLabel();
}
else
{
LogsTextBox.AppendText("\nWrong folder selected - Config file doesn't exist");
}
}
xaml
<Button x:Name="ButtonOld" Content="..." HorizontalAlignment="Left" Margin="149,35,0,0" VerticalAlignment="Top" Width="25" Click="button_ClickOld"/>
<TextBox x:Name="TextBoxOld" HorizontalAlignment="Left" Height="23" Margin="24,35,0,0" Text="" VerticalAlignment="Top" Width="120" IsReadOnly="True"/>
<Button x:Name="ButtonNew" Content="..." HorizontalAlignment="Left" Margin="447,35,0,0" VerticalAlignment="Top" Width="25" Click="button_ClickNew"/>
<TextBox x:Name="TextBoxNew" HorizontalAlignment="Left" Height="23" Margin="322,35,0,0" Text="" VerticalAlignment="Top" Width="120" IsReadOnly="True"/>` <Label x:Name="OldNameLabel" Content="Name" HorizontalAlignment="Left" Margin="24,70,0,0" VerticalAlignment="Top"/>
<Label x:Name="OldIpLabel" Content="IP" HorizontalAlignment="Left" Margin="24,100,0,0" VerticalAlignment="Top"/>
<Label x:Name="OldWebpageUriLabel" Content="WebpageUri" HorizontalAlignment="Left" Margin="24,130,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="OldConnectionStringTextBox" Text="ConnectionString" HorizontalAlignment="Left" Margin="24,160,0,0" Width="120"
VerticalAlignment="Top" Background="Linen" BorderThickness="0" IsReadOnly="True"/>
<Label x:Name="NewNameLabel" Content="Name" HorizontalAlignment="Left" Margin="322,70,0,0" VerticalAlignment="Top"/>
<Label x:Name="NewIpLabel" Content="IP" HorizontalAlignment="Left" Margin="322,100,0,0" VerticalAlignment="Top"/>
<Label x:Name="NewWebpageUriLabel" Content="WebpageUri" HorizontalAlignment="Left" Margin="322,130,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="NewConnectionStringTextBox" Text="ConnectionString" HorizontalAlignment="Left" Margin="322,160,0,0" Width="120"
VerticalAlignment="Top" Background="Linen" BorderThickness="0" IsReadOnly="True"/>
<Label x:Name="ArrowLabel" Content="<-" HorizontalAlignment="Left" Margin="221,14,0,0" VerticalAlignment="Top" FontSize="30" />
<Label x:Name="OldVersionTextBoxLabel" Content="Old Version:" HorizontalAlignment="Left" Margin="24,4,0,0" VerticalAlignment="Top"/>
<Label x:Name="NewVersionTextBoxLabel" Content="New Version:" HorizontalAlignment="Left" Margin="325,4,0,0" VerticalAlignment="Top"/>`
By the looks of your it, you don't understand MVVM and SOLID principles. If you truly want to take advantage of WPF, you must first learn MVVM, and to truly take advantage of MVVM, you need to understand SOLID. To reduce the burden of verbose XAML and boiler plate code, you should take advantage of MVVM frameworks, Caliburn.Micro is super easy to use but require you to have a good architecture to be able to fully utilize it.
Further, using MVVM will make your XAML code so much simpler. Old Version and New Version section will just have one UserControl and may look like
<views:VersionView DataContext={Binding OldVersionViewModel}/>
<views:VersionView DataContext={Binding NewVersionViewModel}/>
You will save yourself a lot of pain and make you delighted you chose WPF for your UI once you learn the power of MVVM.
But if this is just a small project and you insist on using code behind, you can do
private void button_ClickOld(object sender, RoutedEventArgs e)
{
SelectVerifyAndLog(TextBoxOld, UpdateOldLabel);
}
private void button_ClickNew(object sender, RoutedEventArgs e)
{
SelectVerifyAndLog(TextBoxNew, UpdateNewLabel);
}
void SelectVerifyAndLog(TextBox textBox, Action updateLabel)
{
textBox.Text = SelectCatalog();
if (File.Exists(textBox + ConfigFilePath))
{
GetClientProperty(textBox.Text);
updateLabel();
}
else
{
LogsTextBox.AppendText("\nWrong folder selected - Config file doesn't exist");
}
}
1) You can reuse your code
private void button_ClickOld(object sender, RoutedEventArgs e)
{
ButtonHelper(TextBoxOld);
}
private void button_ClickNew(object sender, RoutedEventArgs e)
{
ButtonHelper(TextBoxNew);
}
void ButtonsHelper(TextBox textBox) {
TextBoxNew.Text = SelectCatalog();
if (File.Exists(textBox + ConfigFilePath))
{
GetClientProperty(textBox.Text);
UpdateNewLabel();
}
else
{
LogsTextBox.AppendText("\nWrong folder selected - Config file doesn't exist");
}
}
2) In WPF, use MVVM, otherwise you just don't have advantages of WPF
3) If you have many groups of controls like you marked on your picture and they have much of code, make them controls. And each of them will contain it's own xaml, it's own code, and you can reuse it. It's not necessary to put all the xaml in one file.

How to get text from TextBox inside ListViewItem's DataTemplate

I don't know how to get text from "firstBox" and "secondBox" after button click.
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<!-- some code -->
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Data}" VerticalAlignment="Top" Height="18" Width="100" FontSize="13.333" Margin="162,9,0,0"/>
<TextBlock HorizontalAlignment="Left" Margin="0,35,0,0" TextWrapping="Wrap" Text="{Binding D_gospodarzy}" FontSize="14.667" VerticalAlignment="Top" Height="59" Width="100"/>
<TextBlock HorizontalAlignment="Center" Margin="268,35,7,0" TextWrapping="Wrap" Text="{Binding D_gosci}" FontSize="14.667" VerticalAlignment="Top" Width="100" Height="59"/>
<TextBox x:Name="firstBox" ... />
<Button Content="Click" " Click="Button_Click_1"/>
<TextBox x:Name="secondBox" ... />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
I get only the object
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var myobject = (sender as Button).DataContext;
}
There are cuple of ways to do it, for example you can traverse the VisualTree of clicked button's parent and retrive TextBox with the name you want. In this case, I would take advantage of an extension method written by yasen in this answer.
Then it can look for example like this:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var parent = (sender as Button).Parent;
TextBox firstOne = parent.GetChildrenOfType<TextBox>().First(x => x.Name == "firstBox");
Debug.WriteLine(firstOne.Text);
}
Remember to put an extension method somewhere in a static class:
public static class Extensions
{
public static IEnumerable<T> GetChildrenOfType<T>(this DependencyObject start) where T : class
{
// rest of the code
Here's how to get the text..
String text1 = firstBox.Text;
String text2 = secondBox.Text;
note: firstBox and secondBox must be class members to use them in different class methods.

WPF Slider control (NullReferenceException)

I'm trying to display the value of a slider control in a TextBlock. However I keep getting a NullRerferenceException when I try to load the dialog.
public partial class GeneralSettingsDialog : Window
{
public GeneralSettingsDialog()
{
InitializeComponent();
}
private void DistSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
DistTextBlock.Text = DistSlider.Value.ToString();
}
}
XAML:
<TabItem Header="Miscellaneous" Name="tabItem1" Background="#FFF0F0F0">
<Grid Height="230" Background="#FFF0F0F0">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="13,13,0,0" Name="textBlock1" Text="Spacing" VerticalAlignment="Top" />
<Slider Height="23" HorizontalAlignment="Left" IsSnapToTickEnabled="True" TickPlacement="BottomRight" Margin="13,35,0,0" Name="DistSlider" VerticalAlignment="Top" Width="100" Interval="1" Maximum="50" Minimum="1" ValueChanged="DistSlider_ValueChanged" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="111,35,0,0" Name="DistTextBlock" Text="TextBlock" VerticalAlignment="Top" />
</Grid>
</TabItem>
Not exactly sure why your way isn't working, I guess the controls are not fully initialized when the first value changed event is thrown. But you can do it that way directly in xaml without any code behind:
in TextBlock bind directly to the slider's current value and remove the value changed event handler:
Text="{Binding ElementName=DistSlider, Path=Value}"
PS:
When you attach to the slider's value changed event in codebehind after InitializeComponent() your approach should also work fine:
public MainWindow()
{
InitializeComponent();
DistSlider.ValueChanged +=new RoutedPropertyChangedEventHandler<double>(DistSlider_ValueChanged);
}
private void DistSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
DistTextBlock.Text = DistSlider.Value.ToString();
}
In your XAML you have the TextBlock DistTextBlock defined after DistSlider. When the XAML is loaded for the first time it will fire the ValueChanged handler and DistTextBlock will be null. You can protect against this in a few ways:
// 1. Naive, but least changes to your code
if (DistTextBlock != null)
{
DistTextBlock.Text = DistSlider.Value.ToString();
}
There is #SvenG's excellent suggestion, which moves the logic to the XAML (no need for a ValueChanged handler):
<TextBlock Text="{Binding Value, ElementName=DistSlider}" ... />
Lastly you could use a ViewModel (or any data context supporting INotifyPropertyChanged) to handle the passing to and from of the value.
The important part of using the binding is it allows you to put any string formatting right alongside its usage in the XAML (say, if this slider was for a currency amount):
<TextBlock Text="{Binding Value, ElementName=DistSlider, StringFormat={}{0:C}}"
The last bonus of using a binding is coming out in .Net Framework 4.5, which allows you to specify a time delay prior to the binding updating its source. This would allow your GUI to seem more reactive if the binding is used in expensive operations.
<Slider Value="{Binding DollarAmount, Delay=50}" ... />
<TextBlock Text="{Binding DollarAmount, StringFormat={}{0:C}}" ... />

Getting a null exception while trying to hide the text block in WPF application

I am trying to develop some tools as I am new to WPF. I have a combobox which has 2 items.
the xaml code is as below
<Window x:Class="New_generator2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="500" Width="500">
<Grid>
<ComboBox Height="21" Margin="36,15,22,0" Name="comboBox1" VerticalAlignment="Top" AllowDrop="True" Text="" SelectionChanged="comboBox1_SelectionChanged">
<ComboBoxItem Tag="1" IsSelected="True" Name="ComboBox_Rule_Parameter">Rule_Parameter</ComboBoxItem>
<ComboBoxItem Tag="2" Name="ComboBox_Rule_Instance">Rule_Instance</ComboBoxItem>
</ComboBox>
<TextBox Height="25" HorizontalAlignment="Right" Margin="0,71,14,0" Name="Field_Code_textbox" VerticalAlignment="Top" Width="220" Visibility="Hidden" />
<TextBlock Height="25" HorizontalAlignment="Left" Margin="14,73,0,0" Name="Field_Code" VerticalAlignment="Top" Width="220" TextBlock.FontSize="20" Background="BurlyWood" TextAlignment="Center" Text="Data_Field_Code" Visibility="Hidden"/>
<TextBox Height="84" Margin="35,0,23,12" Name="Script" VerticalAlignment="Bottom" Width="420" Visibility="Hidden"/>
<Button Height="25" Margin="120,0,123,106" Name="Generate" VerticalAlignment="Bottom" TextBlock.FontSize="18" Background="BlanchedAlmond" TextBlock.TextAlignment="Justify" Click="button1_Click" Visibility="Hidden">Dispaly</Button>
</Grid>
</Window>
And C# code is as below
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Field_Code = new TextBlock();
}
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (comboBox1.SelectedIndex == 0)
{
Field_Code.Visibility = Visibility.Visible;
}
if (comboBox1.SelectedIndex == 1)
{
Field_Code.Visibility = Visibility.Hidden;
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
Script.Text = Field_Code_textbox.Text;
}
}
When I run this, I am getting a Null Exception i.e Object reference not set to an instance of an object. I have attached the screenshot of the null exception.
please help me in solving this issue.
Move your initialisation of Field_Code to BEFORE InitialiseComponent() in the constructor.
This happens because combobox_selection changed is called from InitializeComponent() and at this time your Field_Code is uninitialized. Simpliest workaround is to move Field_Code = new TextBlock(); before InitializeComponent(); in Window1() constructor.
Looks like combo selection changed is triggered from InitializeComponent.
Personally I would make a property like public bool FieldCodeVisible { .. } and bind the visibility of your textbox to that property.
Instead of saying Field_Code.Visibility = Visibility.Visible; you can say FieldCodeVisible = true;
This way you have your logic in your ViewModel, but you can decide the on functionality in your view.

Resources