C# WPF - 变量值不会显示在文本框上(DataContext?)

C# WPF - variable value won't display on Textboxes (DataContext?)

我的 C# WPF 应用程序遇到了一个非常棘手和烦人的问题。我想一个好的程序员解决它并不是什么大问题,但我还不知道如何解决它。对于学校,我必须编写一个描述过程的应用程序。所以我通过 XML-File 获取数据,必须计算一些值,为用户交互等显示它们,最后输出又是一个文件,可以进一步处理。

为此,我得到了不同的用户控件,它描述了不同的模块,例如,一个用于数据导入,另一个用于计算和显示值等等。 Main Window 就像免费的 space 或占位符,根据我们在进程中的位置加载不同的模块。

我现在的问题是,我在我的 UserControl 中计算的值不会分别显示在我的 UI 我的应用程序中,我真的不知道为什么。 0 是传输到应用程序的唯一值。奇怪的是,在调试器中的值是正确的,但在显示本身中只有一个 0。

好的,现在我向您展示不同文件的代码(我不是最好的程序员,所以代码有时可能有点脏)。

我有一个主用户控件,我们称它为 UC_Main,在此用户控件中,您可以根据选中 UC_Main 中的哪个单选按钮在 3 个不同的其他用户控件之间切换。 (UC_Main 始终显示,因为这里只有 3 个单选按钮,下面是一个很大的空闲 space,其中加载了不同的 UserControls 1、2 和 3)。

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();            
    }  
}
}

为简单起见,我将仅向您展示 UserControl 1 的代码,因为 UC 2 和 3 除了其他变量或值外几乎相同。

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);
    }

我之前在 UserControl 中调用了函数 calc_data(),所以在我的 UserControl 出现之前,数据被计算并保存在我的变量中。我声明了我的 UC1 的一个新 public 实例,并通过 UC1.calc_data(); 调用该函数; (链接到一个正在加载我的 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"); }
    }

当我在调用方法 calc_data() 后查看调试器时,值已正确保存在我的 ValueStore 实例中,并且文本框在调试器中向我显示正确的值在那里(调试器说 "Name: TextBox1" 和 "Value: {System.Windows.Controls.TextBox: 100}";100 是我从字典中得到的值),但在我的应用程序本身中只显示值 0。

我不太明白的是,当我在 ValueStore.cs 中将类型从 variable1 更改为 string 并将其保存在方法 calc_data()(without Convert. ToInt32),它在我的应用程序中甚至不再显示 0,但在调试器中仍然有值“100”。

这里有几件事,但我最好的猜测是为什么在 none 更新到 GUI 时你的调试值是正确的:

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();            
    }  
}

您正在为用户控件创建这些 class 代码隐藏的新实例。但是用户控件对象已经由 UC_Main.xaml 创建,因此在运行时,您有两个对象,例如 UC1 class,一个绑定到您的 GUI,另一个用于存储和更新您的值.您在 GUI 上看到的那个没有得到任何值更新,这就是为什么您看不到任何东西的原因。

我目前无法自己测试代码,但据我所知,这就是问题所在。 此外,我有点困惑,为什么要使用数据绑定进行代码隐藏。 (您正在使用 UC-classes 的代码隐藏作为主要 class 的数据上下文,这是....奇怪的;)我认为在您的情况下,实际上不需要任何数据绑定,但是,如果你想用数据绑定做一些事情,你可能应该阅读 MVVM)