I got a really tricky and annoying problem with my C# WPF Application. I guess it's not a big deal for a good programmer to solve it, but I don't know how to fix it yet. For school, I have to program an application which depicts a process. So I get Data by an XML-File, have to calculate some values, display them for User Interaction etc. and at the end the output is again a file, which can be processed further.
For that, I got different UserControls, which depicts different modules for example, one for the Data Import, the other one for calculating and displayng values and so on. The Main Window is like the free space or the place-maker on which the different modules are loaded depending on where we are in the process.
My problem now is that the values I calculate in my UserControl won't display in my UI respectively my application and I don't really know why. 0 is the only value which is transferred to the application. Curious about it, is that in the Debugger the values are correct, but in the display itself there is only a 0.
Ok, so I show you now the code of the different files (I'm not the best programmer, so maybe the code is sometimes a bit dirty).
I got a Main UserControl, let's call it UC_Main, and in this UserControl you can switch between 3 different other UserControls depending on which Radiobutton in the UC_Main is checked. (The UC_Main is always displayed, because in this there are only the 3 radio buttons and underneath is a big free space, where the different UserControls 1, 2 and 3 are loaded).
UC_Main.xaml
<UserControl.Resources>
<DataTemplate x:Name="UC1_Template" DataType="{x:Type local:UC1}">
<local:UC1 DataContext="{Binding}" />
</DataTemplate>
<DataTemplate x:Name="UC2_Template" DataType="{x:Type local:UC2}">
<local:UC2 DataContext="{Binding}" />
</DataTemplate>
<DataTemplate x:Name="UC3_Template" DataType="{x:Type local:UC3}">
<local:UC3 DataContext="{Binding}" />
</DataTemplate>
</UserControl.Resources>
<Border Padding="10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- In the First Row there are the radio buttons in the second the
different UserControls 1, 2 or 3 -->
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<materialDesign:ColorZone Mode="PrimaryMid" Width="400" HorizontalAlignment="Left">
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="2">
<RadioButton x:Name="UC1_radiobutton" Checked="UC1_radiobutton_Checked"
Style="{StaticResource MaterialDesignTabRadioButton}"
Margin="4"
IsChecked="True"
Content="UserControl1" />
<RadioButton x:Name="UC2_radiobutton" Checked="UC2_radiobutton_Checked"
Style="{StaticResource MaterialDesignTabRadioButton}"
Margin="4"
IsChecked="False"
Content="UserControl2" />
<RadioButton x:Name="UC3_radiobutton" Checked="UC3_radiobutton_Checked"
Style="{StaticResource MaterialDesignTabRadioButton}"
Margin="4"
IsChecked="False"
Content="UserControl3" />
</StackPanel>
</materialDesign:ColorZone>
<ContentControl Grid.Row="1" Content="{Binding}" />
</Grid>
</Border>
</UserControl>
UC_Main.xaml.cs
public partial class UC_Main : UserControl
{
public UC_Main()
{
InitializeComponent();
}
private void UC1_radiobutton_Checked(object sender, RoutedEventArgs e)
{
DataContext = new UC1();
}
private void UC2_radiobutton_Checked(object sender, RoutedEventArgs e)
{
DataContext = new UC2();
}
private void UC3_radiobutton_Checked(object sender, RoutedEventArgs e)
{
DataContext = new UC3();
}
}
}
To keep it simple, I'll only show you the Code of UserControl 1, because UC 2 and 3 are pretty the same beside other variables or values.
UC1.xaml
<Border Padding="10">
<StackPanel>
<!-- To keep the example simple, I got 1 Row and 2 Colums; in each
is one TextBox -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBox x:Name="TextBox1" Grid.Column="0" IsTabStop="False"
Text="{Binding Path=variable1, Mode=TwoWay}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextAlignment="Center"
Height="25"
Width="85"
Foreground="DarkGray"
IsReadOnly="True" />
<TextBox x:Name="TextBox2" Grid.Column="1" IsTabStop="False"
Text="{Binding Path=variable2, Mode=TwoWay}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextAlignment="Center"
Height="25"
Width="85"
Foreground="DarkGray"
IsReadOnly="True" />
</Grid>
</StackPanel>
</Border>
</UserControl>
UC_1.xaml.cs
public partial class UC1 : UserControl
{
public MainWindow Speaker;
public ValueStore vs;
public UC1()
{
InitializeComponent();
Speaker = MainWindow.AppWindow;
vs = new ValueStore();
DataContext = vs;
}
public void calc_data()
{
// I get the data from the data import (XML-File), which is saved in
// a dictionary (strings), converting them to int (so I can do some
// math operations) and save them in my variable.
// UC_Other is a UserControl, where the data import happens
// dict_other is the dictionary, where the data from the import is
// saved
vs.variable1 =
Convert.ToInt32(MainWindow.AppWindow.UC_other.dict_other["0"].Amount);
vs.variable2 =
Convert.ToInt32(MainWindow.AppWindow.UC_other.dict_other["1"].Amount);
}
I call the function calc_data() in an UserControl before, so the data gets calculated and saved in my variables before my UserControl shows up. I declare a new public instance of my UC1 and call the function via UC1.calc_data(); (which is linked to a Button, that is loading my UC_Main).
ValueStore.cs
public class ValueStore : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
private int _variable1;
public int variable1
{
get { return _variable1; }
set { _variable1 = value; OnPropertyChanged("variable1"); }
}
private int _variable2;
public int variable2
{
get { return _variable2; }
set { _variable2 = value; OnPropertyChanged("variable2"); }
}
When I look in the debugger after the method calc_data() is called, the values are correct saved in my ValueStore instance and the TextBoxes are showing me in the Debugger that the correct value is in there (the Debugger says "Name: TextBox1" and "Value: {System.Windows.Controls.TextBox: 100}"; 100 is the value I got from the dictionary), but in my application itself there is only the value 0 displayed.
What I don't really understand is, when I change the type from variable1 to string in my ValueStore.cs and save it in my variable in the method calc_data()(without Convert.ToInt32), it doesn't even show a 0 any more in my application, but in the debugger there is still the value "100".
There are a few things here, but my best guess why your debugging-values are correct while none are updated to the GUI is here:
public partial class UC_Main : UserControl
{
public UC_Main()
{
InitializeComponent();
}
private void UC1_radiobutton_Checked(object sender, RoutedEventArgs e)
{
DataContext = new UC1();
}
private void UC2_radiobutton_Checked(object sender, RoutedEventArgs e)
{
DataContext = new UC2();
}
private void UC3_radiobutton_Checked(object sender, RoutedEventArgs e)
{
DataContext = new UC3();
}
}
You are creating new instances of these classes of the code-behind to the usercontrols. But the usercontrol objects are already created by the UC_Main.xaml
so during runtime, you have two objects for example of the UC1 class, one which is your bound to your GUI and one where you store and update your values. The one you see on your GUI doesn't get any values updates, which is why you aren't seeing anything.
I currently can't test the code myself, but from what I can see that is where the issue lies. Furthermore it is a bit confusing to me, why you are using databinding for code-behind. (You are using the code-behind of the UC-classes as datacontext for the main class, which is....weird ;) I think in your case no databinding whatsoever is really needed, however if you want to do stuff with databinding you should probably read up on MVVM)