【问题标题】:How to get access to a binding to a WPF Binding on C# CodeBehind level如何在 C# CodeBehind 级别访问到 WPF 绑定的绑定
【发布时间】:2022-09-23 16:55:22
【问题描述】:

我是一名 VB.Net 程序员,对 C# 很陌生。我正处于我陷入困境的地步。 我想制作一个应用程序来使用 Word 创建报价单。此报价单应包含两个 Word 文件。 Word 文件是带有书签的模板,因此写入它们应该没有问题。

我想要一个 WPF 用户界面,用户可以在其中描述文章,当单击一个按钮时,将创建两个 Word 文件。

我制作了 WPF 用户界面并将文本框绑定到 cl_Data.cs 类,其中的属性包括:描述、函数名等。

我的问题: 如何从我的 Code Behinde 的用户界面访问数据以将其转换为 Word 文件?

编码: WPF:我如何在 .xaml 级别上绑定它

    <Window.Resources>
        <!-- Binding the Data Class-->
        <local:Cl_Data x:Key=\"Data\" 
                       Dealer=\"Test\"
                       Costumer=\"Tester\"
                       Machine=\"M***s\"
                       PRJ=\"123456\"
                       DeliveryTime=\"6\"
                       Description=\"Managing different chucks, Saving position data of the linear sensor for chuck clamp unclamp position\"
                       Operation=\"The operator can select a chuck form the chuck management and save the clamp and unclamp position and reuse this position for next time\"
                       FunctionName=\"GeneratorAPP\"
                       Requirements=\"API-Kit\"
                       />
    </Window.Resources>

我如何在 .xaml 级别(同一文档)上调用它-> 这有效

    <Border BorderBrush=\"#FFB0F0FF\" BorderThickness=\"1\" Height=\"26\">
                                            <TextBox x:Name=\"Tb_Dealer\"  
                                            TextWrapping=\"Wrap\" Text=\"{Binding Dealer,    UpdateSourceTrigger=PropertyChanged}\" Width=\"auto\" Foreground=\"#FFB0F0FF\" BorderBrush=\"#00ABADB3\" Background=\"Transparent\" TextAlignment=\"Center\" VerticalAlignment=\"Center\" />
                                        </Border>

<Border BorderBrush=\"#FFB0F0FF\" BorderThickness=\"1\" Height=\"26\">
                                            <TextBox x:Name=\"Tb_Dealer\"                             TextWrapping=\"Wrap\" Text=\"{Binding Dealer, UpdateSourceTrigger=PropertyChanged}\" Width=\"auto\" Foreground=\"#FFB0F0FF\" BorderBrush=\"#00ABADB3\" Background=\"Transparent\" TextAlignment=\"Center\" VerticalAlignment=\"Center\" />
                                        </Border>

所以我的类 cl_Data.cs 看起来像:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Windows;

namespace QuotationApp.Classes
{
    internal class Cl_Data : INotifyPropertyChanged
    {
        #region Descriptions
        private string _Dealer   ;

        public string Dealer
        {
            get { return _Dealer; }
            set 
            { _Dealer = value;
                OnPropertyChanged(\"Dealer\");
            }
        }

        private string _Costumer;

        public string Costumer
        {
            get { return _Costumer; }
            set
            {
                _Costumer = value;
                OnPropertyChanged(\"Costumer\");
            }
        }


        private string _Machine;

        public string Machine
        {
            get { return _Machine; }
            set 
            { 
                _Machine = value;
                OnPropertyChanged(\"Machine\");
            }
        }

    
        

        private string _PRJ;

        public string PRJ
        {
            get { return _PRJ; }
            set { _PRJ = value; 
            OnPropertyChanged(PRJ);
            }
        }

        private string _DeliveryTime;

        public string DeliveryTime
        {
            get { return _DeliveryTime; }
            set { 
                _DeliveryTime = value;
                OnPropertyChanged(\"DeliveryTime\");
            }
        }

        private string _Operation;
                
        public string Operation
        {
            get { return _Operation; }
            set { 
                _Operation = value;
                OnPropertyChanged(\"Operation\");
            }
        }

        private string _Description;

        public string Description
        {
            get { return _Description; }
            set {
                _Description = value;
                OnPropertyChanged(\"Description\");
            }
        }

        private string _FunctionName;

        public string FunctionName
        {
            get { return _FunctionName; }
            set { 
                _FunctionName = value;
                OnPropertyChanged(\"FunctionName\");
            }
        }

        private string _Requirements;

        public string Requirements
        {
            get { return _Requirements; }
            set { 
                _Requirements = value;
                OnPropertyChanged(\"Requirements\");
            }
        }
        #endregion

        #region Costs

        private double _HardwareCost;

        public double HardwareCost
        {
            get { return _HardwareCost; }
            set { 
                _HardwareCost = value;
                _CostTotal = CalcTotal();
                OnPropertyChanged(\"HardwareCost\");
            }
        }

        private double _PersonalCost;

        public double PersonalCost
        {
            get { return _PersonalCost; }
            set { 
                _PersonalCost = value;
                _CostTotal = CalcTotal();
                OnPropertyChanged(\"PersonalCost\");

            }
        }

        private double _TravelCost;

        public double TravelCost
        {
            get { return _TravelCost; }
            set { 
                _TravelCost = value;
                _CostTotal = CalcTotal();
                OnPropertyChanged(\"TravelCost\");
            }
        }

        private double _CostTotal;

        public double CostTotal
        {
            get { return _CostTotal; }
            set { 
                _CostTotal = value;
                OnPropertyChanged(\"CostTotal\");
            }
        }

       public double CalcTotal()
        {
            double total = 0;
            try
            {
              total = TravelCost + HardwareCost + PersonalCost;
                
               
                                
            }
            catch (Exception e)
            {

               MessageBox.Show(\"Error getting the total Value: \" + e.Message);  
            }


            return total;
        }



        #endregion










        #region PropertyChangedEvents
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

所以现在我想访问这些数据,例如描述(Data.Description)以将其处理为单词书签。但是我如何从 CodeBehind 访问 WPF 级别的这些数据?

请对我放轻松,我知道这个问题很奇怪,但我现在用谷歌搜索了 2 天,我开始感到沮丧。如果这个问题在其他地方得到了回答,我很想有答案的链接。

提前致谢

  • 正确实施后,您不应使用 Code Behind 中的数据——这违反了 OOP 和 SOLID 的原则。处理数据的所有逻辑都应该在模型中。实际上,ViewModel 是在其属性中反映模型的代理。对于简单的任务,可以创建组合的 Model + ViewModel 类。
  • 好吧,假设我会为此做一个模型。如何从 UI 获取数据?那是我的问题。
  • 绑定。您已在代码中设置它们。我假设一旦你使用它们,你就会知道它们是如何工作的。当更改 TextBox 的值时,此更改将自动传递到 Dealer 属性。 GUI 中的用户操作主要通过命令传递给 ViewModel(即您的 Cl_Data 类)。并且 Execute 方法中的命令可以获取其参数和 ViewModel 属性/字段。
  • 嘿@EldHasp,是的。问题是我不知道如何访问在 cl_data.cs 的 MainWindow.xaml 中创建的对象 \"Data\"。我想要类似的东西。书签 1 = 数据。描述。
  • 所以在我想使用 Data 属性的模型中。如何从我创建的对象中获取数据?

标签: c# wpf data-binding


【解决方案1】:

就我想到的而言,我做了一个最简单的例子。
如果您不明白,请提出相关问题。
我会尽力回答。

using System;

namespace Core2022.Lexxy_B
{
    public class PersonDto
    {
        public int Id { get; }
        public string Name { get; }
        public int Age { get; }

        public PersonDto(int id, string name, int age)
        {
            if (Id < 0)
                throw new ArgumentOutOfRangeException(nameof(id));
            Id = id;
            if (string.IsNullOrWhiteSpace(name))
                throw new ArgumentNullException(nameof(name));
            Name = name;
            if (age < 0)
                throw new ArgumentOutOfRangeException(nameof(age));
            Age = age;
        }
        public PersonDto(string name, int age)
            : this(0, name, age)
        {
            Id = -1;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;

namespace Core2022.Lexxy_B
{
    public class PeopleModel
    {
        private readonly List<PersonDto> people = new List<PersonDto>()
        {
            new PersonDto(5, "Thomas", 25),
            new PersonDto(1, "Harry", 40),
        };
        public IReadOnlyList<PersonDto> GetPeople() => Array.AsReadOnly(people.ToArray());

        public void AddPerson(PersonDto person)
        {
            int id = people.LastOrDefault()?.Id ?? 0;
            do
            {
                id++;
            } while (people.Any(p => p.Id == id));

            person = new PersonDto(id, person.Name, person.Age);
            people.Add(person);
            AddedPerson?.Invoke(this, person);
        }

        public event EventHandler<PersonDto>? AddedPerson;
    }
}
namespace Core2022.Lexxy_B
{
    public class PersonVM
    {
        public string? Name { get; set; }
        public int Age { get; set; }
    }
}
using Simplified;
using System.Collections.ObjectModel;

namespace Core2022.Lexxy_B
{

    public class PeopleViewModel : ViewModelBase
    {
        private readonly PeopleModel model = new PeopleModel();
        private string _mode = "view";

        public ObservableCollection<PersonDto> People { get; } = new ObservableCollection<PersonDto>();
        public string ViewMode { get => _mode; private set => Set(ref _mode, value); }
        public PeopleViewModel()
        {
            foreach (var person in model.GetPeople())
            {
                People.Add(person);
            }

            model.AddedPerson += OnAddedPerson;
        }

        private void OnAddedPerson(object? sender, PersonDto newPerson)
        {
            People.Add(newPerson);
        }

        public RelayCommand AddPersonCommand => GetCommand<PersonVM>(AddPersonExecute, AddPersonCanExecute);
        private void AddPersonExecute(PersonVM person)
        {
            model.AddPerson(new PersonDto(person.Name ?? string.Empty, person.Age));
            ViewMode = "view";
        }

        private bool AddPersonCanExecute(PersonVM person)
        {
            return !string.IsNullOrWhiteSpace(person.Name) && person.Age >= 0;
        }
        public RelayCommand ExitAddingPersonCommand => GetCommand(() => ViewMode = "view");
        public RelayCommand BeginAddingPersonCommand => GetCommand(() => ViewMode = "add");
    }
}
<Window x:Class="Core2022.Lexxy_B.PeopleWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Core2022.Lexxy_B"
        mc:Ignorable="d"
        Title="PeopleWindow" Height="450" Width="800"
        DataContext="{DynamicResource vm}">
    <Window.Resources>
        <local:PeopleViewModel x:Key="vm"/>
    </Window.Resources>
    <UniformGrid Columns="2">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <ListBox x:Name="lBox" ItemsSource="{Binding People}" DisplayMemberPath="Name"/>
            <Button Grid.Row="1" Content="Go to Add Person" Padding="15 5" Margin="5"
                    Command="{Binding BeginAddingPersonCommand}">
                <Button.Style>
                    <Style TargetType="Button">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ViewMode}" Value="add">
                                <Setter Property="IsEnabled" Value="False"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>
        </Grid>
            <ContentControl x:Name="cp">
                <ContentControl.Style>
                    <Style TargetType="ContentControl">
                        <Style.Resources>
                            <DataTemplate x:Key="view.Template">
                                <local:PersonDetailsUC/>
                            </DataTemplate>
                            <DataTemplate x:Key="add.Template">
                                <local:AddPersonUC/>
                            </DataTemplate>
                        </Style.Resources>
                        <Setter Property="Content" Value="{Binding}"/>
                        <Setter Property="ContentTemplate" Value="{StaticResource add.Template}"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ViewMode}" Value="view">
                                <Setter Property="Content" Value="{Binding SelectedItem, ElementName=lBox}"/>
                                <Setter Property="ContentTemplate" Value="{StaticResource view.Template}"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ContentControl.Style>
            </ContentControl>
    </UniformGrid>
</Window>
<UserControl x:Class="Core2022.Lexxy_B.PersonDetailsUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Core2022.Lexxy_B"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             d:DataContext="{d:DesignInstance Type=local:PersonDto}">
    <UniformGrid Columns="1">
        <TextBlock Text="{Binding Id, StringFormat={}Id: {0}, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBlock Text="{Binding Name, StringFormat={}Name: {0}}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBlock Text="{Binding Age, StringFormat={}Age: {0}, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
    </UniformGrid>
</UserControl>
<UserControl x:Class="Core2022.Lexxy_B.AddPersonUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Core2022.Lexxy_B"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <d:UserControl.DataContext>
        <local:PeopleViewModel/>
    </d:UserControl.DataContext>
    <UserControl.Resources>
        <local:PersonVM x:Key="person"/>
    </UserControl.Resources>
    <UniformGrid Columns="2">
        <TextBlock Text="Name" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBox Text="{Binding Name, Source={StaticResource person}}" VerticalAlignment="Center" Margin="10"/>
        <TextBlock Text="Age" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBox Text="{Binding Age, Source={StaticResource person}}" VerticalAlignment="Center" Margin="10"/>
        <Button Content="Add" Padding="15 5"  VerticalAlignment="Center" HorizontalAlignment="Center"
                Command="{Binding AddPersonCommand}"
                CommandParameter="{Binding Mode=OneWay, Source={StaticResource person}}"/>
        <Button Content="Exit" Padding="15 5"  VerticalAlignment="Center" HorizontalAlignment="Center"
                Command="{Binding ExitAddingPersonCommand}"/>
    </UniformGrid>
</UserControl>

由于存储库而添加。

更改 Word.cs 的第 33 行,因为我无法分配打开到 word 模板的相对路径

通过相对可执行程序集给出的路径获取文件全名的实现示例。

  1. 项目资源中的文件本身必须具有“内容”-“复制...”属性。我有一个俄罗斯化的工作室,所以截图是俄语的。
    “bin”文件夹不能包含在项目中,否则,它的所有内容也将包含在程序集中。

    这是将相对路径转换为绝对路径的代码:
            public static readonly string ApplicationFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            public const string TestRelativeNameFile = @"Resources\Word\Test.docx";
            public static readonly string TestFullNameFile = Path.Combine(ApplicationFolder, TestRelativeNameFile);
            public static void GenerateLocalSolution()
            {
                try
                {
                    WordApp = new Microsoft.Office.Interop.Word.Application();
                    TestApp = WordApp.Documents.Open(TestFullNameFile);
                }
    

【讨论】:

  • 非常感谢 !!我不明白你的答案是怎么回事,我找到了一种适合我的方法。如何向您展示我的解决方案?
  • 最简单的方法:创建一个最小的解决方案来演示正在讨论的问题,将其上传到 GitHub 并提供指向已上传存储库的链接。
  • 你好@EldHasp,我终于设法准备了一个 repo 。请阅读 README.md 我付出了一些努力:) github.com/Bauschi/QuoteApp_EldHasp
  • @Lexxy_B,我已经下载了你的存储库。但是没有足够的空闲时间,所以我将部分回答。在以编程方式获取测试文件的路径时,我已经在我的答案中写了一个补充。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-02
  • 2012-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
相关资源
最近更新 更多